EC2インスタンス起動とAWS Backupを利用したバックアップ設定をするCloudFormationテンプレートを作成しました

備忘録として作ったCfnテンプレートです。

こんにちは、AWS事業本部のニシヤマです。

最近、CloudFormationでEC2インスタンスを起動する機会があったのですが、その際にAMIを定期的に取得する必要がありました。 弊社ご契約のAWSアカウントですとAWS運用自動化ツールの「opswitch」を利用してAMIを定期的に取得することも可能です。 https://opswitch.io/

ただ今回はAWS Backupを利用して同じCloudFormationテンプレートで設定してみましたのでご紹介します。

テンプレート

テンプレートでは以下のリソースを作成しています。

  • EC2インスタンス用のセキュリティグループ
  • EC2インスタンス用のIAMRole
  • EC2インスタンス
  • AWS Backupボールト
  • AWS Backupプラン
  • AWS Backup用のIAMRole

そしてテンプレートがこちらです。

EC2インスタンス構築とAWS Backupを利用したバックアップ設定をするCloudFormationテンプレート
AWSTemplateFormatVersion: 2010-09-09

Description:  
  This is template of test Server EC2

Parameters:
  ProjectPrefix:
    Type: String
    Default: "test"
    Description: Project Prefix
  Environment:
    Description: Environment
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - stg
      - prd
  VpcId:
    Type: "String"
    Default: "vpc-XXXXXXXXXXXXXXXXX"
  EC2SubnetId: 
    Type: "String"
    Default: "subnet-XXXXXXXXXXXXXXXXX"
  InstanceType:
    Type: String
    Default: "t3.micro"
    Description: InstanceType for EC2
  ImageId:
    Type: String
    Default: "ami-XXXXXXXXXXXXXXXXX"
    Description: AMI-ID for EC2
  RootVolumeSize:
    Type: String
    Default: "30"
    Description: Size of Root Device
  KeyName:
    Type: String
    Default: "test-keypair"
    Description: EC2 Keypair Name
  EC2InstanceName:
    Type: String
    Default: "test-ec2"
    Description: EC2 Instance Name
  SSHIPAddress:
    Type: String
    Default: "192.168.0.0/24"
    Description: Allow SSH IPAddress
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
  BackupCron:
    Type: String
    Default: cron(00 15 * * ? *)
    Description: Exec Backup Time.(UTC)
  BackupGeneration:
    Type: Number
    Default: 7
    Description: Backup File Generation
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: Common Settings
      Parameters:
        - ProjectPrefix
        - Environment
    - Label:
        default: EC2 Settings
      Parameters:
        - VpcId
        - EC2SubnetId
        - InstanceType
        - ImageId
        - RootVolumeSize
        - KeyName
        - EC2InstanceName
        - SSHIPAddress
    - Label:
        default: Backup Settings
      Parameters:
        - BackupCron
        - BackupGeneration

Resources:
# ------------------------------------------------------------#
#  SecurityGroup for EC2 Instance
# ------------------------------------------------------------#
  TestServerEC2SG:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupName: !Sub ${ProjectPrefix}-${Environment}-sg-ec2-TestServer
      GroupDescription: Security Group for Test Server
      Tags:
        - Key: Name
          Value: !Sub ${ProjectPrefix}-${Environment}-sg-ec2-TestServer
      VpcId: 
          !Ref VpcId

  TestServerEC2SGIngressSSHNTD:
     Type: AWS::EC2::SecurityGroupIngress
     Properties:
        GroupId: !Ref TestServerEC2SG
        IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref SSHIPAddress

# ------------------------------------------------------------#
#  IAM Role for EC2 Instance
# ------------------------------------------------------------#
  TestServerEC2IAMRole:
      Type: AWS::IAM::Role
      Properties: 
        AssumeRolePolicyDocument:
          Version: "2012-10-17"
          Statement:
            -
              Effect: "Allow"
              Principal:
                Service:
                  - "ec2.amazonaws.com"
              Action:
                - "sts:AssumeRole"
        ManagedPolicyArns:
          - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        Path: /
        RoleName: !Sub ${ProjectPrefix}-${Environment}-iam-role-ec2-TestServer
  
  TestServerEC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties: 
      Path: /
      Roles:
        - Ref: TestServerEC2IAMRole
      InstanceProfileName: !Ref TestServerEC2IAMRole

# ------------------------------------------------------------#
#  EC2 Instance
# ------------------------------------------------------------#
  TestServerEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Sub ${InstanceType}
      ImageId: !Sub ${ImageId}
      KeyName: !Sub ${KeyName}
      IamInstanceProfile: !Ref TestServerEC2InstanceProfile
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeType: gp2
            VolumeSize: !Sub ${RootVolumeSize}
            DeleteOnTermination: true
      NetworkInterfaces:
        - SubnetId: 
            !Ref EC2SubnetId
          AssociatePublicIpAddress: false
          GroupSet:
             - !Ref TestServerEC2SG
          DeviceIndex: 0
          DeleteOnTermination: true
      DisableApiTermination: false
      EbsOptimized: true
      Tags:
        - Key: Name
          Value: !Sub ${EC2InstanceName}
        - Key: Backup
          Value: true

# ------------------------------------------------------------#
#  AWS Backup
# ------------------------------------------------------------#
  EC2BackupIAMRole:
      Type: AWS::IAM::Role
      Properties: 
        AssumeRolePolicyDocument:
          Version: 2012-10-17
          Statement:
            -
              Effect: Allow
              Principal:
                Service:
                  - backup.amazonaws.com
              Action:
                - sts:AssumeRole
        ManagedPolicyArns:
          - arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup
          - arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores
        Path: /service-role/
        RoleName: !Sub ${ProjectPrefix}-${Environment}-iam-role-ec2-backup

  TestBackupVaultforEC2:
    Type: AWS::Backup::BackupVault
    Properties:
      BackupVaultName: TestEC2BackupVault

  TestBackupPlan:
    Type: AWS::Backup::BackupPlan
    Properties:
      BackupPlan:
        BackupPlanName: TestBackupPlan
        AdvancedBackupSettings:
          -
            ResourceType: EC2
            BackupOptions:
              WindowsVSS: disabled
        BackupPlanRule:
          -
            RuleName: RuleForDailyBackups
            TargetBackupVault: !Ref TestBackupVaultforEC2
            ScheduleExpression: !Ref BackupCron
            Lifecycle:
              DeleteAfterDays: !Ref BackupGeneration
  TagBasedBackupSelection:
    Type: AWS::Backup::BackupSelection
    Properties:
      BackupSelection:
        SelectionName: TagBasedBackupSelection
        IamRoleArn: !GetAtt EC2BackupIAMRole.Arn
        ListOfTags:
         -
           ConditionType: STRINGEQUALS
           ConditionKey: Backup
           ConditionValue: true
      BackupPlanId: !Ref TestBackupPlan
    DependsOn: TestBackupPlan

こちらのテンプレートではEC2の終了保護は有効化していないので必要に応じて設定してください。

説明

それではテンプレートを説明していきます。

Parametersセクションでは以下のパラメータを指定します。

パラメータのキー 説明
ProjectPrefix リソースに付与する接頭語
Environment リソースの環境文字列(dev、stg、prdから選択)
VpcId EC2を起動するVPCのID
EC2SubnetId EC2を起動するサブネットのID
InstanceType EC2のインスタンスタイプ
ImageId AMIのID
RootVolumeSize EC2のルートボリュームのサイズ
KeyName EC2の接続に利用するキーペア
EC2InstanceName EC2の名前(Nameタグの値)
SSHIPAddress EC2へのSSH接続を許可するIPアドレス
BackupCron AWS Backupの実行タイミング(UTCでcron表記、デフォルト0時)
BackupGeneration AWS Backupで管理するAMIの世代数

次にResourcesセクションの中のAWS Backupに関わる部分を説明します。

# ------------------------------------------------------------#
#  AWS Backup
# ------------------------------------------------------------#
  EC2BackupIAMRole:
      Type: AWS::IAM::Role
      Properties: 
        AssumeRolePolicyDocument:
          Version: 2012-10-17
          Statement:
            -
              Effect: Allow
              Principal:
                Service:
                  - backup.amazonaws.com
              Action:
                - sts:AssumeRole
        ManagedPolicyArns:
          - arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup
          - arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores
        Path: /service-role/
        RoleName: !Sub ${ProjectPrefix}-${Environment}-iam-role-ec2-backup

まず上記でAWS Backupで利用するIAMロールを作成しています。すでにAWS Backupを利用している環境の場合は自動的にサービスにリンクされたロールAWSServiceRoleForBackupが作成されている場合もありますが、今回はCloudFormationで作成しました。 ポリシーは以下の2つをアタッチしています。

  • AWSBackupServiceRolePolicyForBackup
  • AWSBackupServiceRolePolicyForRestores
  TestBackupVaultforEC2:
    Type: AWS::Backup::BackupVault
    Properties:
      BackupVaultName: TestEC2BackupVault

次に上記のブロックでAWS Backupボールトを作成しています。ボールト名はTestEC2BackupVaultで決め打ちしています。

  TestBackupPlan:
    Type: AWS::Backup::BackupPlan
    Properties:
      BackupPlan:
        BackupPlanName: TestBackupPlan
        AdvancedBackupSettings:
          -
            ResourceType: EC2
            BackupOptions:
              WindowsVSS: disabled
        BackupPlanRule:
          -
            RuleName: RuleForDailyBackups
            TargetBackupVault: !Ref TestBackupVaultforEC2
            ScheduleExpression: !Ref BackupCron
            Lifecycle:
              DeleteAfterDays: !Ref BackupGeneration
  TagBasedBackupSelection:
    Type: AWS::Backup::BackupSelection
    Properties:
      BackupSelection:
        SelectionName: TagBasedBackupSelection
        IamRoleArn: !GetAtt EC2BackupIAMRole.Arn
        ListOfTags:
         -
           ConditionType: STRINGEQUALS
           ConditionKey: Backup
           ConditionValue: true
      BackupPlanId: !Ref TestBackupPlan
    DependsOn: TestBackupPlan

最後に上記でAWS Backupプランとバックアップ対象の割り当てをしています。 パラメータで指定したAWS Backupの実行タイミング、AMIの世代数を利用しています。

        ListOfTags:
         -
           ConditionType: STRINGEQUALS
           ConditionKey: Backup
           ConditionValue: true
      BackupPlanId: !Ref TestBackupPlan
    DependsOn: TestBackupPlan

また、バックアップ対象のEC2に関しては上記の部分でBackupタグの値がtrueの対象をバックアップ取得するようにしています。 既存のEC2インスタンスに対して同じタグを付与することで一緒にバックアップ対象にすることもできます。

以上です。

まとめ

いかがでしたでしょうか。踏み台サーバが必要になった場合にも、他のシステムとの依存はないけど一応バックアップを取得しておきたいといった際にこちらのテンプレートで簡単に構築&バックアップが可能になりました。 EC2インスタンスをサクッと構築したい時にマネジメントコンソールで起動するのも良いですが再現性が薄かったり、EC2構築したあとにバックアップ設定もしたいけど諸々設定が...のような場合にはこちらのテンプレートを利用していただければサクッと一式設定が可能です。

この記事がどなたかの参考になれば幸いです。

参考

汎用的に使えるAWS BackupのCfnテンプレートが欲しかったので作った