CodeBuildでCloudformationを使ってIAMロールを作成する

# はじめに
本記事ではAWS CodeBuildでCloudformation、aws cliを使ってIAMロールの作成、更新、削除をできるようにします。

なお、本記事で使用するファイルは以下Gitに上げています。
https://github.com/kyuaz/codebuild-iam-role-manager

# 目次
[1.全体構成](#1全体構成)
[2.下準備](#2下準備)
　[2.1.CodeBuildに割り当てるIAM Roleの作成](#21codebuildに割り当てるiam-roleの作成)
　[2.2.CodeCommitのリポジトリを作成](#22codecommitのリポジトリを作成)
[3.CodeBuildプロジェクトの作成](#3codebuildプロジェクトの作成)
　[3.1.ビルドプロジェクトの新規作成](#31ビルドプロジェクトの新規作成)
　[3.2.ファイル構成](#32ファイル構成)
　[3.3.buildspec.yml](#33buildspecyml)
　[3.4.ルートディレクトリ直下のスクリプトファイルの説明](#34ルートディレクトリ直下のスクリプトファイルの説明)
　　[3.4.1.param.sh](#341paramsh)
　　[3.4.2.build.sh](#342buildsh)
　　[3.4.3.upload.sh](#343uploadsh)
　　[3.4.4.deploy.sh](#344deploysh)
　　[3.4.5.delete.sh](#345deletesh)
　[3.5.各ロールごとに定義するファイルの説明](#35各ロールごとに定義するファイルの説明)
　　[3.5.1.param.sh](#351paramsh)
　　[3.5.2.template.yaml](#352templateyaml)
　　[3.5.3.template_param.json](#353template_paramjson)
[4.CodeBuildを動かしてみる](#4codebuildを動かしてみる)
　[4.1.create IAM Role](#41create-iam-role)
　[4.2.update IAM Role](#42update-iam-role)
　[4.3.delete IAM Role](#43delete-iam-role)
[まとめ](#まとめ)


# 1.全体構成
これから作成するCodeBuildプロジェクトは以下の各AWSサービスを使ってIAM Roleを管理します。
![スクリーンショット 2020-01-10 16.38.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/bff44423-d153-8d7c-c307-bf4b79a3d67e.png)


# 2.下準備
CodeBuildプロジェクトの作成に入る前の下準備です。

## 2.1.CodeBuildに割り当てるIAM Roleの作成
これからCodeBuildで任意のIAM Roleを作成できるようにするわけですが、その前にCodeBuildが使用するIAM Roleを作成する必要があります。
つまりCodeBuildがCloudformationを使ってIAM Roleを作成、更新、削除するための権限を与えて上げる必要があります。

このIAM Roleのみ、AWSコンソール上で手動で作成します。

ロール名: iam-role-manager-role
アタッチするポリシー: 以下の通り

![スクリーンショット 2020-01-22 16.30.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/4c5a2c41-0ede-7a54-3aa5-d277e3008bc3.png)

cloudformation-acceses-policyポリシーの詳細↓
![スクリーンショット 2020-01-22 16.32.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/9594f49f-4240-9f7b-2145-b2157cca33d1.png)

iam-access-policyポリシーの詳細↓
![スクリーンショット 2020-01-22 16.32.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/063b2ded-44ed-cbc4-615f-40268e54ef24.png)

s3-access-policyポリシーの詳細↓
![スクリーンショット 2020-01-22 16.33.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/5ace230a-cbd9-0be0-a29a-d8dbffa9a120.png)


これで「iam-role-manager-role」というCodeBuild用のIAM Roleが作成できました。

## 2.2.CodeCommitのリポジトリを作成
CodeBuildで使用するファイルを格納しておくCodeCommitリポジトリを作成します。

ここでは以下の名前で作成することにします。
リポジトリ名: iam-role-manager


以上で、下準備は終わります。
ではCodeBuildプロジェクトを作っていきます。

# 3.CodeBuildプロジェクトの作成
CodeBuildのビルドプロジェクトを作成します。

## 3.1.ビルドプロジェクトの新規作成
ビルドプロジェクトの作成画面です。

![スクリーンショット 2020-01-10 12.58.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/67def9e5-f0c5-160e-fe80-dc3fb7bd6cb0.png)

プロジェクト名はiam-role-managerとします。

![スクリーンショット 2020-01-10 12.59.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/b0025727-0aee-2b46-7a62-80c9d4e61073.png)
リポジトリはさきほど本ビルドプロジェクト用に作成したリポジトリiam-role-managerを指定し、ブランチはmasterとします。

![スクリーンショット 2020-01-10 13.08.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/8537d5c2-6c27-b643-87ed-e8dfa963b563.png)
環境の項目では上記のようにUbuntuのstandard:3.0のイメージを選択します。

![スクリーンショット 2020-01-10 13.10.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/501d7257-3bff-f743-b991-41e89efe8be6.png)
サービスロールでは既存のサービスロールを選択し、さきほど作成したロールを選択します。

![スクリーンショット 2020-01-10 13.00.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/9ffd637c-0924-fed6-c38f-63f4eefcfcc2.png)
それ以外の項目（Buildspec、アーティファクト、ログ）はデフォルトのままとします。

以上の設定でビルドプロジェクトを作成します。

## 3.2.ファイル構成
CodeBuildのビルドプロジェクトで使用するファイルは以下の構成でリポジトリにアップします。
なお#以降はコメントです。

```
├── build.sh                           #Buildフェーズで実行するスクリプト
├── buildspec.yml                      #CodeBuildビルドプロジェクトのビルド仕様
├── delete.sh                          #IAMロール削除時に実行するスクリプト
├── deploy.sh                          #IAMロール作成、更新時に実行するスクリプト
├── iam-role-lambda                    #lambda用IAMロール
│   ├── param.sh                       #パラメータ定義ファイル
│   ├── template.yaml                  #CloudFormation templateファイル
│   └── template_param.json            #templateファイル用パラメータ
├── iam-role-dynamodb-readonly-lambda  #dynamodb読み込みのみ可能なlambda用IAMロール
├── param.sh                           #パラメータ定義ファイル
└── upload.sh                          #templateファイルアップロード時に実行するスクリプト
```
## 3.3.buildspec.yml
CodeBuildビルドプロジェクトの[ビルド仕様](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html)を記述するファイルがbuildspec.ymlです。

以下のように定義します。

```yaml
version: 0.2

phases:
  install:
    runtime-versions:
      python: 3.8
    commands:
      - ls -l
  build:
    commands:
      - bash build.sh
```
runtime-versionsはpythonである必要はありませんが、何かしら指定する必要があります。私はちょっとした処理が必要になった時にpythonを使いたいのでpythonを指定しています(本記事ではpythonは使っていませんが)。

## 3.4.ルートディレクトリ直下のスクリプトファイルの説明
ルートディレクトリ直下に配置する各スクリプトファイルの説明です。

### 3.4.1.param.sh
本ファイルでは変数定義やエラーチェックを行ないます。
ROLEでIAMロールを指定して、MODEでIAMロールを作成、削除、更新するのか指定できるようにしています。
指定されたROLEに対応したディレクトリをDIR_NAMEに格納します。ROLEごとに必要な定義は各ディレクトリ下に定義します。

```bash:param.sh
#!/bin/bash

if [ -z $IS_EXECUTED ]; then
    ENV_MODE_CREATE_ROLE="create"
    ENV_MODE_DELETE_ROLE="delete"
    ENV_MODE_UPDATE_ROLE="update"
    ENV_ROLE_BASIC_LAMBDA_ROLE="lambda"
    ENV_ROLE_DYNAMODB_READONLY_ROLE="dynamodb-readonly-lambda"

    S3_BUCKET_NAME="build-bucket"
    S3_PRJ_NAME="iam-role-manager"
    S3_TEMPLATE_DIR="s3://${S3_BUCKET_NAME}/${S3_PRJ_NAME}/template/"
    REGION="ap-northeast-1"
    TEMPLATE_URL="https://s3-${REGION}.amazonaws.com/${S3_BUCKET_NAME}/${S3_PRJ_NAME}/template/template.yaml"

    if [ -z $MODE ]; then
        echo "ERROR: MODE is required"
        exit 1
    fi
    if [ -z $ROLE ]; then
        echo "ERROR: ROLE is required"
        exit 1
    fi
    echo "MODE = ${MODE}"
    echo "ROLE = ${ROLE}"

    if [ $ROLE = $ENV_ROLE_BASIC_LAMBDA_ROLE ]; then
        DIR_NAME="iam-role-lambda"
    elif [ $ROLE = $ENV_ROLE_DYNAMODB_READONLY_ROLE ]; then
        DIR_NAME="iam-role-dynamodb-readonly-lambda"
    else
        echo "invalid ROLE"
        exit 1
    fi

    IS_EXECUTED=1
fi

```
### 3.4.2.build.sh
本ファイルはbuildspec.ymlから呼ばれるスクリプトファイルです。
MODEに応じたスクリプトファイルを実行します。

```bash:build.sh
#!/bin/bash

source ./param.sh
source ./${DIR_NAME}/param.sh

if [ $MODE = $ENV_MODE_CREATE_ROLE ] || [ $MODE = $ENV_MODE_UPDATE_ROLE ]; then
    bash ./upload.sh
    bash ./deploy.sh
elif [ $MODE = $ENV_MODE_DELETE_ROLE ]; then
    bash ./delete.sh
fi

```

### 3.4.3.upload.sh
本ファイルはbuild.shから呼ばれ、IAMロール作成時、更新時に実行されます。
CloudFormationのテンプレートファイルをs3にアップロードします。

```bash:upload.sh
#!/bin/bash

source ./param.sh
source ./${DIR_NAME}/param.sh

echo "S3_TEMPLATE_DIR: ${S3_TEMPLATE_DIR}"
aws s3 cp ./${DIR_NAME}/template.yaml $S3_TEMPLATE_DIR
aws s3 ls $S3_TEMPLATE_DIR

```

### 3.4.4.deploy.sh
本ファイルはbuild.shから呼ばれ、IAMロール作成時、更新時に実行されます。
作成or更新を実行する前に以下を実施しています。

- テンプレートファイルの検証
- 今から作ろうとしているスタックが既に存在するかのチェック

IAMロールの作成、更新はCloudFormationのcreate stack, update stackで実現します。
※スタックの状態がROLLBACK_COMPLETEになっている場合、update stackができません。そのため一度削除してからcreate stackしています。

```bash:deploy.sh
#!/bin/bash

source ./param.sh
source ./${DIR_NAME}/param.sh

echo "TEMPLATE_URL: ${TEMPLATE_URL}"

echo "validate template file"
aws cloudformation validate-template --template-url $TEMPLATE_URL 3>&1 1>&2 2>&3 | grep ValidationError
if [ $? = 0 ]; then
    echo "cloudformation template validate error"
    exit 1
fi
echo -e "validate template file OK\n"

aws cloudformation describe-stacks --stack-name $STACK_NAME 3>&1 1>&2 2>&3 | grep error >/dev/null
if [ $? = 0 ]; then
    echo "creating new stack."
    aws cloudformation create-stack --stack-name $STACK_NAME --template-url $TEMPLATE_URL --tags Key=COST,Value=$TAG_COST_VALUE --capabilities CAPABILITY_NAMED_IAM --region ${REGION} --parameters file://${TEMPLATE_PARAMETER_FILE}
    echo "waiting stack create complete..."
    aws cloudformation wait stack-create-complete --stack-name $STACK_NAME
else
    echo "stack exists."
    if [ $MODE = $ENV_MODE_CREATE_ROLE ]; then
        echo "stack already exists error. if you want to update IAM Role, use update MODE instead."
        exit 1
    elif [ $MODE = $ENV_MODE_UPDATE_ROLE ]; then
        aws cloudformation describe-stacks --stack-name $STACK_NAME 2>&1 | grep ROLLBACK_COMPLETE
        if [ $? = 0 ]; then
            echo "stack state is ROLLBACK_COMPLETE. deleting stack.."
            aws cloudformation delete-stack --stack-name $STACK_NAME
            aws cloudformation wait stack-delete-complete --stack-name $STACK_NAME
            echo "creating stack.."
            aws cloudformation create-stack --stack-name $STACK_NAME --template-url $TEMPLATE_URL --tags Key=COST,Value=$TAG_COST_VALUE --capabilities CAPABILITY_NAMED_IAM --region ${REGION} --parameters file://${TEMPLATE_PARAMETER_FILE}
            echo "waiting stack create complete..."
            aws cloudformation wait stack-create-complete --stack-name $STACK_NAME
        else
            echo "updating stack.."
            aws cloudformation update-stack --stack-name $STACK_NAME --template-url $TEMPLATE_URL --tags Key=COST,Value=$TAG_COST_VALUE --capabilities CAPABILITY_NAMED_IAM --region ${REGION} --parameters file://${TEMPLATE_PARAMETER_FILE} 2>&1 1>/dev/null | grep error
            if [ $? = 0 ]; then
                echo "update stack error"
                exit 1
            else
                echo "waiting stack update complete..."
                aws cloudformation wait stack-update-complete --stack-name $STACK_NAME
            fi
        fi
    fi
fi

aws cloudformation describe-stacks --stack-name $STACK_NAME

```

### 3.4.5.delete.sh
本ファイルはbuild.shから呼ばれ、IAMロール削除時に実行されます。

```bash:delete.sh
#!/bin/bash

source ./param.sh
source ./${DIR_NAME}/param.sh

aws cloudformation delete-stack --stack-name $STACK_NAME
aws cloudformation wait stack-delete-complete --stack-name $STACK_NAME

aws cloudformation describe-stacks --stack-name $STACK_NAME 2>&1 1>/dev/null | grep error > /dev/null
if [ $? = 0 ]; then
    echo -e "\ndelete stack completed"
else
    echo -e "\nddelete stack error"
    exit 1
fi

```

ルートディレクトリ直下のファイルの説明は以上です。
続けて、各IAMロール依存のファイル（サブディレクトリのファイル）の説明をしていきます。

## 3.5.各ロールごとに定義するファイルの説明
このビルドプロジェクトでは複数のIAMロールを管理できるようにします。
各ロールごとに対応したディレクトリを作り、その中に当該IAMロールの内容を定義します。

### 3.5.1.param.sh
本ファイルでは当該IAMロール依存のパラメータを定義します。

```bash:param.sh
#!/bin/bash

source ./param.sh

TEMPLATE_PARAMETER_FILE="./${DIR_NAME}/template_param.json"

POSTFIX="${ROLE}-role"
STACK_NAME="${S3_PRJ_NAME}-${POSTFIX}"
TAG_COST_VALUE="cf-${S3_PRJ_NAME}-${POSTFIX}"

```

### 3.5.2.template.yaml
本ファイルは当該IAMロールのCloudFormationテンプレートファイルです。ここでIAMロールに付与する各種権限を記述します。

ここではdynamodbへの読み書き、SNSへのpublish、cloudwatchへの権限付与などを行なっています。インラインポリシーの形で記述しています。

```yaml:template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  RoleName:
    Type: String
  RoleDescription:
    Type: String
Resources:
  BasicLambdaRole:
    Type: 'AWS::IAM::Role'
    Properties:
      Description: !Ref RoleDescription
      AssumeRolePolicyDocument: 
        Version: '2012-10-17'
        Statement: 
          - 
            Effect: Allow
            Principal: 
              Service: 
                - lambda.amazonaws.com
            Action: 
              - sts:AssumeRole
      Path: /
      RoleName: !Ref RoleName
  UseDynamoPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: use-dynamo-policy
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action: 
            - dynamodb:Query
            - dynamodb:Scan
            - dynamodb:BatchGetItem
            - dynamodb:GetItem
            - dynamodb:PutItem
            - dynamodb:UpdateItem
            - dynamodb:DeleteItem
          Resource: '*'
      Roles:
      - !Ref BasicLambdaRole
  SnsPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: sns-policy
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action: 
            - sns:Publish
          Resource: '*'
      Roles:
      - !Ref BasicLambdaRole
  CloudWatchLogPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: cloudwatch-log-policy
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action: 
            - logs:*
            - cloudwatch:*
          Resource: '*'
      Roles:
      - !Ref BasicLambdaRole
Outputs:
  StackName:
    Value: !Ref AWS::StackName
  StackID:
    Value: !Ref AWS::StackId
```

### 3.5.3.template_param.json
本ファイルは上記テンプレートファイルで使用するパラメータを定義します。

```json:template_param.json
[
    {
        "ParameterKey": "RoleName",
        "ParameterValue": "iam-role-manager-lambda-role",
        "UsePreviousValue": false
    },
    {
        "ParameterKey": "RoleDescription",
        "ParameterValue": "IAM Role for basic lambda",
        "UsePreviousValue": false
    }
]
```

必要な全てのファイルの説明は以上になります。
なおIAMロールの定義を増やす場合は同様にルート直下にディレクトリを追加して、ROLE名に対応して切り替えるようにすれば実現できます。

それでは実際にCodeBuildを動かしてみます。

# 4.CodeBuildを動かしてみる
作成したCodeBuildのビルドプロジェクトを動かしてみます。

## 4.1.create IAM Role
「ビルドの開始」画面で下の方にある「環境変数の上書き」で以下のようにMODEとROLEを指定してビルドの開始をします。ここではMODEをcreateに指定し、ROLEをlambdaと指定します。
※別のIAMロールを作成したい場合はROLEに指定する値を変えます(例えばdynamodb-readonly-lambda）

![スクリーンショット 2020-01-10 14.39.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/5a167bee-7a8c-0123-f9d5-0c46865909d2.png)

ビルドを実行すると以下のようになります。

```bash
[Container] 2020/01/23 03:52:57 Waiting for agent ping
[Container] 2020/01/23 03:52:59 Waiting for DOWNLOAD_SOURCE
[Container] 2020/01/23 03:53:02 Phase is DOWNLOAD_SOURCE
[Container] 2020/01/23 03:53:02 CODEBUILD_SRC_DIR=/codebuild/output/src123456789/src/git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/iam-role-manager
[Container] 2020/01/23 03:53:02 YAML location is /codebuild/output/src123456789/src/git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/iam-role-manager/buildspec.yml
[Container] 2020/01/23 03:53:02 Processing environment variables
[Container] 2020/01/23 03:53:02 Moving to directory /codebuild/output/src123456789/src/git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/iam-role-manager
[Container] 2020/01/23 03:53:02 Registering with agent
[Container] 2020/01/23 03:53:02 Phases found in YAML: 2
[Container] 2020/01/23 03:53:02  INSTALL: 1 commands
[Container] 2020/01/23 03:53:02  BUILD: 1 commands
[Container] 2020/01/23 03:53:02 Phase complete: DOWNLOAD_SOURCE State: SUCCEEDED
[Container] 2020/01/23 03:53:02 Phase context status code:  Message: 
[Container] 2020/01/23 03:53:02 Entering phase INSTALL
[Container] 2020/01/23 03:53:02 Running command echo "Installing Python version 3.8 ..."
Installing Python version 3.8 ...

[Container] 2020/01/23 03:53:02 Running command ls -l
total 32
-rw-r--r-- 1 root root  253 Jan 23 03:53 build.sh
-rw-r--r-- 1 root root  146 Jan 23 03:53 buildspec.yml
-rw-r--r-- 1 root root  407 Jan 23 03:53 delete.sh
-rw-r--r-- 1 root root 2525 Jan 23 03:53 deploy.sh
drwxr-xr-x 2 root root 4096 Jan 23 03:53 iam-role-lambda
drwxr-xr-x 2 root root 4096 Jan 23 03:53 iam-role-dynamodb-readonly-lambda
-rw-r--r-- 1 root root 1072 Jan 23 03:53 param.sh
-rw-r--r-- 1 root root  226 Jan 23 03:53 upload.sh

[Container] 2020/01/23 03:53:02 Phase complete: INSTALL State: SUCCEEDED
[Container] 2020/01/23 03:53:02 Phase context status code:  Message: 
[Container] 2020/01/23 03:53:03 Entering phase PRE_BUILD
[Container] 2020/01/23 03:53:03 Phase complete: PRE_BUILD State: SUCCEEDED
[Container] 2020/01/23 03:53:03 Phase context status code:  Message: 
[Container] 2020/01/23 03:53:03 Entering phase BUILD
[Container] 2020/01/23 03:53:03 Running command bash build.sh
MODE = create
ROLE = lambda
MODE = create
ROLE = lambda
S3_TEMPLATE_DIR: s3://build-bucket/iam-role-manager/template/
Completed 1.7 KiB/1.7 KiB (11.0 KiB/s) with 1 file(s) remaining
upload: iam-role-lambda/template.yaml to s3://build-bucket/iam-role-manager/template/template.yaml
2020-01-23 03:53:09       1752 template.yaml
MODE = create
ROLE = lambda
TEMPLATE_URL: https://s3-ap-northeast-1.amazonaws.com/build-bucket/iam-role-manager/template/template.yaml
validate template file
{
    "Parameters": [
        {
            "ParameterKey": "RoleName",
            "NoEcho": false
        },
        {
            "ParameterKey": "RoleDescription",
            "NoEcho": false
        }
    ],
    "Capabilities": [
        "CAPABILITY_NAMED_IAM"
    ],
    "CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::Policy, AWS::IAM::Role]"
}
validate template file OK

creating new stack.
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:1234567890123:stack/iam-role-manager-lambda-role/df2f3040-3d93-11ea-af99-0a0f495cff22"
}
waiting stack create complete...
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:1234567890123:stack/iam-role-manager-lambda-role/df2f3040-3d93-11ea-af99-0a0f495cff22",
            "StackName": "iam-role-manager-lambda-role",
            "Parameters": [
                {
                    "ParameterKey": "RoleName",
                    "ParameterValue": "iam-role-manager-lambda-role"
                },
                {
                    "ParameterKey": "RoleDescription",
                    "ParameterValue": "IAM Role for basic lambda"
                }
            ],
            "CreationTime": "2020-01-23T03:53:10.342Z",
            "RollbackConfiguration": {},
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Capabilities": [
                "CAPABILITY_NAMED_IAM"
            ],
            "Outputs": [
                {
                    "OutputKey": "StackName",
                    "OutputValue": "iam-role-manager-lambda-role"
                },
                {
                    "OutputKey": "StackID",
                    "OutputValue": "arn:aws:cloudformation:ap-northeast-1:1234567890123:stack/iam-role-manager-lambda-role/df2f3040-3d93-11ea-af99-0a0f495cff22"
                }
            ],
            "Tags": [
                {
                    "Key": "COST",
                    "Value": "cf-iam-role-manager-lambda-role"
                }
            ],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}

[Container] 2020/01/23 03:54:11 Phase complete: BUILD State: SUCCEEDED
[Container] 2020/01/23 03:54:11 Phase context status code:  Message: 
[Container] 2020/01/23 03:54:11 Entering phase POST_BUILD
[Container] 2020/01/23 03:54:11 Phase complete: POST_BUILD State: SUCCEEDED
[Container] 2020/01/23 03:54:11 Phase context status code:  Message: 
```


## 4.2.update IAM Role
IAMロールの更新を実行してみます。IAMロールの内容(template.yaml)を何かしら変更して(変更しないと更新は実行されないため)、以下のようにMODEをupdateにしてビルドを開始します。

![スクリーンショット 2020-01-23 13.14.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/bd43f279-bf5f-eb54-46fc-a8fd2cf7d745.png)

実行結果は以下のようになります（BUILD phase以降のログになります）。

```bash
[Container] 2020/01/23 04:07:27 Entering phase BUILD
[Container] 2020/01/23 04:07:27 Running command bash build.sh
MODE = update
ROLE = lambda
MODE = update
ROLE = lambda
S3_TEMPLATE_DIR: s3://build-bucket/iam-role-manager/template/
Completed 1.7 KiB/1.7 KiB (12.8 KiB/s) with 1 file(s) remaining
upload: iam-role-lambda/template.yaml to s3://build-bucket/iam-role-manager/template/template.yaml
2020-01-23 04:07:34       1718 template.yaml
MODE = update
ROLE = lambda
TEMPLATE_URL: https://s3-ap-northeast-1.amazonaws.com/build-bucket/iam-role-manager/template/template.yaml
validate template file
{
    "Parameters": [
        {
            "ParameterKey": "RoleName",
            "NoEcho": false
        },
        {
            "ParameterKey": "RoleDescription",
            "NoEcho": false
        }
    ],
    "Capabilities": [
        "CAPABILITY_NAMED_IAM"
    ],
    "CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::Policy, AWS::IAM::Role]"
}
validate template file OK

{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:1234567890123:stack/iam-role-manager-lambda-role/df2f3040-3d93-11ea-af99-0a0f495cff22",
            "StackName": "iam-role-manager-lambda-role",
            "Parameters": [
                {
                    "ParameterKey": "RoleName",
                    "ParameterValue": "iam-role-manager-lambda-role"
                },
                {
                    "ParameterKey": "RoleDescription",
                    "ParameterValue": "IAM Role for basic lambda"
                }
            ],
            "CreationTime": "2020-01-23T03:53:10.342Z",
            "RollbackConfiguration": {},
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Capabilities": [
                "CAPABILITY_NAMED_IAM"
            ],
            "Outputs": [
                {
                    "OutputKey": "StackName",
                    "OutputValue": "iam-role-manager-lambda-role"
                },
                {
                    "OutputKey": "StackID",
                    "OutputValue": "arn:aws:cloudformation:ap-northeast-1:1234567890123:stack/iam-role-manager-lambda-role/df2f3040-3d93-11ea-af99-0a0f495cff22"
                }
            ],
            "Tags": [
                {
                    "Key": "COST",
                    "Value": "cf-iam-role-manager-lambda-role"
                }
            ],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
stack exists.
updating stack..
waiting stack update complete...
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:1234567890123:stack/iam-role-manager-lambda-role/df2f3040-3d93-11ea-af99-0a0f495cff22",
            "StackName": "iam-role-manager-lambda-role",
            "Parameters": [
                {
                    "ParameterKey": "RoleName",
                    "ParameterValue": "iam-role-manager-lambda-role"
                },
                {
                    "ParameterKey": "RoleDescription",
                    "ParameterValue": "IAM Role for basic lambda"
                }
            ],
            "CreationTime": "2020-01-23T03:53:10.342Z",
            "LastUpdatedTime": "2020-01-23T04:07:36.612Z",
            "RollbackConfiguration": {},
            "StackStatus": "UPDATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Capabilities": [
                "CAPABILITY_NAMED_IAM"
            ],
            "Outputs": [
                {
                    "OutputKey": "StackName",
                    "OutputValue": "iam-role-manager-lambda-role"
                },
                {
                    "OutputKey": "StackID",
                    "OutputValue": "arn:aws:cloudformation:ap-northeast-1:1234567890123:stack/iam-role-manager-lambda-role/df2f3040-3d93-11ea-af99-0a0f495cff22"
                }
            ],
            "Tags": [
                {
                    "Key": "COST",
                    "Value": "cf-iam-role-manager-lambda-role"
                }
            ],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}

[Container] 2020/01/23 04:08:07 Phase complete: BUILD State: SUCCEEDED
[Container] 2020/01/23 04:08:07 Phase context status code:  Message: 
[Container] 2020/01/23 04:08:08 Entering phase POST_BUILD
[Container] 2020/01/23 04:08:08 Phase complete: POST_BUILD State: SUCCEEDED
[Container] 2020/01/23 04:08:08 Phase context status code:  Message: 
```

※注意
IAMコンソールを開いている状態で、stack updateしたらコンソール上でIAM Roleを確認しても変更が反映されていませんでした。一度IAMコンソールを閉じて再度開き直したら反映されていました。(2020/1/11 確認時)

## 4.3.delete IAM Role
以下のようにMODEにdeleteを指定してIAMロールを削除します。

![スクリーンショット 2020-01-23 13.17.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191873/37ba62f0-d5d2-37b8-6499-c38dfb85ede9.png)

実行結果は以下のようになります。

```bash
[Container] 2020/01/23 04:18:12 Entering phase BUILD
[Container] 2020/01/23 04:18:12 Running command bash build.sh
MODE = delete
ROLE = lambda
MODE = delete
ROLE = lambda

delete stack completed

[Container] 2020/01/23 04:18:48 Phase complete: BUILD State: SUCCEEDED
[Container] 2020/01/23 04:18:48 Phase context status code:  Message: 
[Container] 2020/01/23 04:18:48 Entering phase POST_BUILD
[Container] 2020/01/23 04:18:48 Phase complete: POST_BUILD State: SUCCEEDED
[Container] 2020/01/23 04:18:48 Phase context status code:  Message: 
```

# まとめ
本記事ではAWS CodeBuildでCloudformation、aws cliを使ってIAMロールの作成、更新、削除を実現する方法について記載しました。