GitHubからAWS CloudFormationをデプロイするチャレンジ

GitHubからのAWS CloudFormationデプロイ自動化 を見て、実際に試してみました。そこで学んだことやつまずいた点を書いてみます。

試してみてわかったこと

GitHubからCloudFormationをDeployしたかったので、記事の内容に基づいてそのまま試してみましたが、何点かでつまずいたのでその経験を下記します。

基本的にはドキュメント通りで問題ないのですが、Deployするときに必要なRoleが2つあります。それは、Git 同期およびCloudFormationがスタックをデプロイ するための権限を付与されたRoleです。

その他にも、AWS CodePipelineでGitHub connections を事前に作成しておく必要があります。

CloudFormation Roleの構築

ここでは、CloudFormationをDeployするためのRoleを定義しています。

cloudformation-deployment-role.yaml

## aws cloudformation deploy --stack-name "deploy-role-stack" --template-file ./sandbox-teamc-cloudformation-deployment-role.yaml --capabilities CAPABILITY_NAMED_IAM --region "us-east-1"

AWSTemplateFormatVersion: '2010-09-09'
Description: Create IAM Role with specified permissions

Resources:
  DeploymentRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: sandbox-teamc-cloudformation-deployment-role
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - cloudformation.amazonaws.com
            Action: 'sts:AssumeRole'
      Policies:
        - PolicyName: SandboxTeamCPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - 'ec2:CreateVpc'
                  - 'ec2:CreateSubnet'
                  - 'ec2:DescribeVpcs'
                  - 'ec2:DescribeSubnets'
                  - 'ec2:DeleteVpc'
                  - 'ec2:DeleteSubnet'
                  - 'ec2:ModifySubnetAttribute'
                  - 'ec2:ModifyVpcAttribute'
                  - "ec2:DescribeSecurityGroups"
                  - ec2:DescribeNetworkAcls
                Resource: '*'
                Condition:
                  ForAnyValue:StringEquals:
                    aws:CalledVia:
                      - cloudformation.amazonaws.com
  GitSyncRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: sandbox-teamc-git-sync-role
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - cloudformation.sync.codeconnections.amazonaws.com
            Action: 'sts:AssumeRole'
      Policies:
        - PolicyName: GitSyncPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: SyncToCloudFormation
                Effect: Allow
                Action:
                  - "cloudformation:CreateChangeSet"
                  - "cloudformation:DeleteChangeSet"
                  - "cloudformation:DescribeChangeSet"
                  - "cloudformation:DescribeStackEvents"
                  - "cloudformation:DescribeStacks"
                  - "cloudformation:ExecuteChangeSet"
                  - "cloudformation:GetTemplate"
                  - "cloudformation:ListChangeSets"
                  - "cloudformation:ListStacks"
                  - "cloudformation:ValidateTemplate"
                  - "codestar-connections:UseConnection"
                Resource: "*"
              - Sid: PolicyForManagedRules
                Effect: Allow
                Action:
                  - "events:PutRule"
                  - "events:PutTargets"
                Resource: "*"
                Condition:
                  StringEquals:
                    events:ManagedBy: "cloudformation.sync.codeconnections.amazonaws.com"
              - Sid: PolicyForDescribingRule
                Effect: Allow
                Action: "events:DescribeRule"
                Resource: "*"

Pull Request Workflowのサンプル

GitHub Actionsを使ってYAMLファイルをデプロイするワークフローを設定しました。

.github/workflows/pull-request.yaml

name: Pull Request workflow

on:
  - pull_request

jobs:
  cloudformation-linter:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install cfn-lint
        run: |
          pip install cfn-lint

      - name: Lint specified YAML files
        run: |
          # List of files to check
          files=(
            "./vpc.yaml"
            "./sandbox-teamc-cloudformation-deployment-role.yaml"
          )

          # Lint each file
          for file in "${files[@]}"; do
            if [ -f "$file" ]; then
              echo "Linting $file"
              cfn-lint -t "$file" || exit 1
            else
              echo "File not found: $file"
              exit 1
            fi
          done

VPCのテンプレート

vpc.yaml

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  EnvironmentName:
    Type: String
    Default: dev
  VpcCIDR:
    Type: String
    Default: 10.0.0.0/16

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
      Tags: 
        - Key: "Name"
          Value:  !Sub "vpc-${EnvironmentName}"
  Subnet:
    Type: AWS::EC2::Subnet 
    Properties:
      VpcId: !Ref VPC 
      CidrBlock: 10.0.0.2/16 

Outputs:
  VpcId:
    Description: The ID of the VPC
    Value: !Ref VPC

  VpcCidrBlock:
    Description: The primary IPv4 CIDR block for the VPC
    Value: !GetAtt VPC.CidrBlock

  VpcCidrBlockAssociations:
    Description: The association IDs of the IPv4 CIDR blocks for the VPC
    Value: !Join [",", !GetAtt VPC.CidrBlockAssociations]

  DefaultNetworkAcl:
    Description: The ID of the default network ACL for the VPC
    Value: !GetAtt VPC.DefaultNetworkAcl

  DefaultSecurityGroup:
    Description: The ID of the default security group for the VPC
    Value: !GetAtt VPC.DefaultSecurityGroup

deployment-file

deployment-file.yaml

template-file-path: ./vpc.yaml 

学び

vpc.yamlのOutPutで!GetAtt VPC.DefaultNetworkAclを使っていますが、DefaultNetworkAclを参照するにはec2:DescribeNetworkAclsのPolicyが必要です。そこで、その他のアトリビュートの値を取得するときにも、CloudFormationをDeployするRoleに対して、都度必要なPolicyを適用していく必要があることを学びました。今まではローカルからAdmin権限でDeployしていたので、このような詳細な権限については気づきませんでした。良い学びとなりました。

関連記事