2024/12/07

AWS CloudFormation

[AWS CloudFormation とは何ですか?](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/Welcome.html)

## CloudFormationの動作概要
ポイントは**StackSets**でクロスリージョンやクロスアカウントのリソースを作成できる点。必要であればオリジナルな処理を**カスタムリソース**で定義できる点。クロスアカウントでは管理者とターゲットアカウントの間に信頼関係を設定する。
### CloudFormation テンプレートの操作
動的なパラメータ参照、テンプレートのスニペットなど
* [CloudFormation テンプレートの使用](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-guide.html)
* [CloudFormation テンプレートスニペット](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-snippets.html)

### スタックの作成と管理
* [AWS CloudFormation スタックを使用した単一ユニットとしての AWS リソースの管理](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/stacks.html)

### 組込関数リファレンス
* [組み込み関数リファレンス](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html)
```
# 使用例
  UserData:
    Fn::Base64: 
      Fn::Sub:
      - |
        #!/bin/bash
        sed -i -e 's/APP_URL=.*/APP_URL=${APP_URL}/' /tmp/.env
        sed -i -e 's/DB_HOST=.*/DB_HOST=${DB_HOST}/' /tmp/.env
        sed -i -e 's/DB_DATABASE=.*/DB_DATABASE=${DbName}/' /tmp/.env
        sed -i -e 's/DB_USERNAME=.*/DB_USERNAME=${UserName}/' /tmp/.env
        sed -i -e 's/DB_PASSWORD=.*/DB_PASSWORD=${Password}/' /tmp/.env
        sed -i -e 's/AWS_S3_BUCKET=.*/AWS_S3_BUCKET=${S3_BUCKET}/' /tmp/.env
      - APP_URL:
          Fn::ImportValue:
            !Sub ${Prefix}::${Client}::LoadBalancerDNSName
        DB_HOST:
          Fn::ImportValue:
            !Sub ${Prefix}::${Client}::EndpointAddress
        S3_BUCKET:
          Fn::ImportValue:
            !Sub ${Prefix}::${Client}::DataBucket
```

### 疑似パラメータ
* [擬似パラメータ参照](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html)

### AWS リソースとプロパティタイプのリファレンス
* [AWS リソースおよびプロパティタイプのリファレンス](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html)

### StackSets 
信頼関係を構築すれば、Organizationsを利用していなくても利用可能
* [StackSets を使用したアカウントとリージョン全体でのスタックの管理](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/what-is-cfnstacksets.html)
* [AWS CloudFormation StackSets のサンプルテンプレート](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/stacksets-sampletemplates.html)
* [セルフマネージド型のアクセス許可を付与する](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/stacksets-prereqs-self-managed.html)
```
# セルフマネージド型のアクセス許可
#
# 管理者アカウント側
#
AWSTemplateFormatVersion: 2010-09-09
Description: Configure the AWSCloudFormationStackSetAdministrationRole to enable use of AWS CloudFormation StackSets.

Parameters:
  AdministrationRoleName:
    Type: String
    Default: AWSCloudFormationStackSetAdministrationRole
    Description: "The name of the administration role. Defaults to 'AWSCloudFormationStackSetAdministrationRole'."
  ExecutionRoleName:
    Type: String
    Default: AWSCloudFormationStackSetExecutionRole
    Description: "The name of the execution role that can assume this role. Defaults to 'AWSCloudFormationStackSetExecutionRole'."

Resources:
  AdministrationRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Ref AdministrationRoleName
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudformation.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: AssumeRole-AWSCloudFormationStackSetExecutionRole
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - sts:AssumeRole
                Resource:
                  - !Sub 'arn:*:iam::*:role/${ExecutionRoleName}'

#
# ターゲットアカウント側
# 
AWSTemplateFormatVersion: 2010-09-09
Description: Configure the AWSCloudFormationStackSetExecutionRole to enable use of your account as a target account in AWS CloudFormation StackSets.

Parameters:
  AdministratorAccountId:
    Type: String
    Description: AWS Account Id of the administrator account (the account in which StackSets will be created).
    MaxLength: 12
    MinLength: 12
  ExecutionRoleName:
    Type: String
    Default: AWSCloudFormationStackSetExecutionRole
    Description: "The name of the execution role. Defaults to 'AWSCloudFormationStackSetExecutionRole'."

Resources:
  ExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Ref ExecutionRoleName
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS:
                - !Ref AdministratorAccountId
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess
```

### カスタムリソース
* [CloudFormation が提供するリソースタイプの使用によるテンプレートの機能の拡張](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/cloudformation-supplied-resource-types.html)
#### 削除イベントの時にS3バケットを掃除するカスタムリソース
```
AWSTemplateFormatVersion: 2010-09-09
Description: If you use S3 bucket, you need to clean up used S3 bucket. so this template is cleanup example

Resources:
  #==========================
  # S3 Bucket
  #==========================
  DataBucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: !Sub 'data-bucket'
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

  #==========================
  # カスタムリソース
  #==========================
  # S3バケット掃除のカスタムリソース
  CleanoutBucketOnDelete:
    Type: Custom::cleanupBucket
    Properties:
      ServiceToken: !GetAtt CleanoutBucketFunction.Arn
    DependsOn: 
      - CleanoutBucketFunction

  # 掃除用ファンクション
  CleanoutBucketFunction:
    Type: AWS::Lambda::Function
    DependsOn: 
      - DataBucket
      - CleanoutBucketRole
    Properties:
      Description: Clean out Bucket on delete.
      Handler: index.handler
      Runtime: python3.12
      Role: !GetAtt CleanoutBucketRole.Arn
      Timeout: 120
      Environment:
        Variables: 
          BUCKET_NAME: !Ref DataBucket
      Code:
        ZipFile: |
          import cfnresponse
          import logging
          import boto3
          import time, os
          status = cfnresponse.SUCCESS
          logger = logging.getLogger(__name__)
          logging.basicConfig(format='%(asctime)s %(message)s',level=logging.DEBUG)

          def handler(event, context):
              logger.debug(event)

              if event['RequestType'] == 'Delete':
                try:
                  BUCKETNAME = os.environ['BUCKET_NAME']
                  s3 = boto3.resource('s3')
                  bucket = s3.Bucket(BUCKETNAME)
                  bucket_versioning = s3.BucketVersioning(BUCKETNAME)
                  if bucket_versioning.status == 'Enabled':
                    bucket.object_versions.delete()
                  else:
                    bucket.objects.all().delete()
                  cfnresponse.send(event, context, status, {}, None)
                except Exception as e:
                  print(e)
                  cfnresponse.send(event, context, cfnresponse.FAILED, {}, None)
              else:
                cfnresponse.send(event, context, status, {}, None)

  # 掃除用ロール
  CleanoutBucketRole:
    Type: AWS::IAM::Role
    Properties:
      PermissionsBoundary: !Sub 'arn:aws:iam::${AWS::AccountId}:policy/DevelopUserBoundary'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: lambda-bucketcleaner
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:DeleteObject
                  - s3:DeleteObjectVersion
                Resource: !Sub 'arn:${AWS::Partition}:s3:::${DataBucket}/*'
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:GetBucketVersioning
                Resource: !Sub 'arn:${AWS::Partition}:s3:::${DataBucket}'
```
#### インスタンスのネットワークインターフェイスを取得するカスタムリソース
```
AWSTemplateFormatVersion: 2010-09-09
Description: The template for creating FlowLog resources.

Resources:
  CustomResource:
    Type: AWS::CloudFormation::CustomResource
    DependsOn: 
      - Function
    Properties:
      ServiceToken: !GetAtt Function.Arn
      ServiceTimeout: 60
      INSTANCEID: i-1234567890abcdef0

  Function:
    Type: "AWS::Lambda::Function"
    Properties:
      Handler: index.handler
      Runtime: python3.8
      Timeout: 60
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: |
          import cfnresponse
          import boto3
          status = cfnresponse.SUCCESS
          def handler(event, context):
              try:
                INSTANCEID = event['ResourceProperties']['INSTANCEID']
                ec2 = boto3.client('ec2')
                response = ec2.describe_network_interfaces(
                    Filters=[
                        {
                            'Name': 'attachment.instance-id',
                            'Values': [INSTANCEID]
                        }
                    ]
                )
                network_interface_id = response['NetworkInterfaces'][0]['NetworkInterfaceId']
                responseData = {}
                responseData['Data'] = network_interface_id
                cfnresponse.send(event, context, status, responseData, None)
              except Exception as e:
                print(e)
                cfnresponse.send(event, context, cfnresponse.FAILED, {}, None)

  LambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties: 
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Effect: "Allow"
            Principal: 
              Service: 
                - "lambda.amazonaws.com"
            Action: 
              - "sts:AssumeRole"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: "LambdaEC2Policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "ec2:DescribeNetworkInterfaces"
                Resource: "*"

  LogGroup:
    DeletionPolicy: Delete
    UpdateReplacePolicy: Delete
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub '${AWS::StackName}-LogGroup'
      RetentionInDays: 1

  FlowLogPolicy:
    Type: "AWS::IAM::ManagedPolicy"
    Properties:
      ManagedPolicyName: !Sub '${AWS::StackName}-FlowLogPolicy'
      Path: "/"
      PolicyDocument: |
          {
              "Version": "2012-10-17",
              "Statement": [
                  {
                      "Effect": "Allow",
                      "Action": [
                          "logs:CreateLogGroup",
                          "logs:CreateLogStream",
                          "logs:PutLogEvents",
                          "logs:DescribeLogGroups",
                          "logs:DescribeLogStreams"
                      ],
                      "Resource": "*"
                  }
              ]
          }

  FlowLogRole:
    Type: "AWS::IAM::Role"
    DependsOn: 
      - FlowLogPolicy
    Properties:
      Path: "/"
      RoleName: !Sub '${AWS::StackName}-FlowLogRole'
      AssumeRolePolicyDocument: 
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - sts:AssumeRole
            Principal:
              Service:
                - vpc-flow-logs.amazonaws.com
      MaxSessionDuration: 3600
      ManagedPolicyArns: 
        - !Ref FlowLogPolicy

  EC2FlowLog:
    Type: "AWS::EC2::FlowLog"
    DependsOn: 
      - CustomResource
    Properties:
      DeliverLogsPermissionArn: !GetAtt FlowLogRole.Arn
      LogGroupName: !Ref LogGroup
      ResourceId: !GetAtt CustomResource.Data
      TrafficType: "ALL"
      LogDestinationType: "cloud-watch-logs"
      ResourceType: "NetworkInterface"
      LogFormat: "${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status}"
      MaxAggregationInterval: 60
```

0 件のコメント:

コメントを投稿

人気の投稿