[JAWS-UG CLI] CloudFormation:#7 ハンズオン用IAMユーザの作成 (AWS管理ポリシ: KinesisFull)


AWS CLI と CloudFormationを利用して、Kinesis フルアクセスが可能な IAM ユーザを作成してみます。

前提条件
===============================

IAM への権限
-------------------------------

- IAM に対してフル権限があること。

CloudFormationへの権限
-------------------------------

- CloudFormation に対してフル権限があること。
- 
AWS CLIのバージョン
-------------------------------

- 以下のバージョンで動作確認済
	- AWS CLI 1.7.24

```bash:コマンド
aws --version
```

```bash:結果(例)
aws-cli/1.7.25 Python/2.7.6 Darwin/14.3.0
```
      
0. 準備
===============================

0.1. リージョンの決定
-------------------------------

作成するユーザのデフォルトリージョンを決めます。

Note: カレントユーザが利用するカレントリージョンも切り変わります。
指定の リージョンでCloudFormationスタックも作成されます。

```bash:command
export AWS_DEFAULT_REGION='ap-northeast-1'
```

0.2. 変数の確認
-------------------------------

プロファイルとリージョンが想定のものになっていることを確認します。

```bash:変数の確認
aws configure list
```

```bash:結果(例)
            Name                    Value             Type    Location
            ----                    -----             ----    --------
         profile       iamFull-prjZ-mbp13              env    AWS_DEFAULT_PROFILE
      access_key     ****************LOAQ shared-credentials-file
      secret_key     ****************I1O1 shared-credentials-file
          region           ap-northeast-1              env    AWS_DEFAULT_REGION
```
          
1. 事前作業
===============================

1.1. 組織名、プロジェクト名の決定
-------------------------------

今回のハンズオンでは、IAMユーザ名にプロジェクト名と作業場所を埋め込み
ます。

```bash:コマンド
PRJ_NAME=<プロジェクト名>
LOC_NAME=<作業場所名>
```

1.2. IAMグループの決定
-------------------------------

```bash:コマンド
aws iam list-groups \
        --query 'Groups[].GroupName'
```

```bash:コマンド
IAM_GROUP_NAME="KinesisFull"
```

1.3. IAMグループポリシーの確認
-------------------------------

IAMグループのグループポリシーを確認します。

```bash:コマンド
aws iam list-attached-group-policies \
        --group-name ${IAM_GROUP_NAME}
```

```json:結果(例)
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonKinesisFullAccess", 
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonKinesisFullAccess"
        }
    ], 
    "IsTruncated": false
}
```

```bash:コマンド
IAM_POLICY_NAME="AmazonKinesisFullAccess"
```

ARNを取得します。

```bash:コマンド
IAM_POLICY_ARN=`aws iam list-policies --max-items 1000 |  jq -r --arg name ${IAM_POLICY_NAME} '.Policies[] | select( .PolicyName == $name ) | .Arn'` \
        && echo ${IAM_POLICY_ARN}
```

```bash:結果(例)
arn:aws:iam::aws:policy/AmazonKinesisFullAccess
```

ポリシのバージョンを取得します。

```bash:コマンド
IAM_POLICY_VERSION=`aws iam list-policies --max-items 1000 |  jq -r --arg name ${IAM_POLICY_NAME} '.Policies[] | select( .PolicyName == $name ) | .DefaultVersionId'` \
        && echo ${IAM_POLICY_VERSION}
```

```bash:結果(例)
      v1
```

ポリシの内容を見てみましょう。

```bash:コマンド
aws iam get-policy-version \
        --policy-arn ${IAM_POLICY_ARN} \
        --version-id ${IAM_POLICY_VERSION}
```

```json:結果(例)
{
    "PolicyVersion": {
        "CreateDate": "2015-02-06T18:40:29Z", 
        "VersionId": "v1", 
        "Document": {
            "Version": "2012-10-17", 
            "Statement": [
                {
                    "Action": "kinesis:*", 
                    "Resource": "*", 
                    "Effect": "Allow"
                }
            ]
        }, 
        "IsDefaultVersion": true
    }
}
```

1.4. パスワードの決定
-------------------------------

マネジメントコンソールログイン用のパスワードを決定します。

```bash:コマンド
IAM_PASSWORD_NEW='#userPass123'
```

2. CloudFormationテンプレートの作成
===============================


テンプレートを作成します。

```bash:コマンド
CF_DESC="${IAM_GROUP_NAME} for handson."
FILE_CF_TEMPLATE="cf-${IAM_GROUP_NAME}-handson.template"
```

```bash:変数の確認
cat << ETX

        IAM_PASSWORD_NEW: ${IAM_PASSWORD_NEW}
        IAM_GROUP_NAME:   ${IAM_GROUP_NAME}
        CF_DESC:          ${CF_DESC}
        FILE_CF_TEMPLATE: ${FILE_CF_TEMPLATE}

ETX
```

```bash:コマンド
cat << EOF > ${FILE_CF_TEMPLATE}
{
        "AWSTemplateFormatVersion": "2010-09-09",
        "Description": "${CF_DESC}",
        "Resources": {
          "user": {
            "Type": "AWS::IAM::User",
            "Properties": {
              "LoginProfile": {
                "Password": "${IAM_PASSWORD_NEW}"
              }
            }
          },
          "belongGroups": {
            "Type": "AWS::IAM::UserToGroupAddition",
            "Properties": {
              "GroupName": "${IAM_GROUP_NAME}",
              "Users": [
                {
                  "Ref": "user"
                }
              ]
            }
          }
        },
        "Outputs" : {
          "UserName" : {
            "Value" : { "Ref" : "user" },
            "Description" : "UserName of new user"
          }
        }
}
EOF
```

JSONファイルを作成したら、フォーマットが壊れてないか必ず確認します。

```bash:コマンド
jsonlint -q ${FILE_CF_TEMPLATE}
```

エラーが出力されなければOKです。

validate-templateサブコマンドで、簡単な検証ができます。

```bash:コマンド
aws cloudformation validate-template \
        --template-body file://${FILE_CF_TEMPLATE}
```

```json:結果(例)
{
    "CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::User, AWS::IAM::UserToGroupAddition]", 
    "Description": "KinesisFull for handson.", 
    "Parameters": [], 
    "Capabilities": [
        "CAPABILITY_IAM"
    ]
}
```

3. CloudFormationスタックの作成
===============================

3.1. スタック名の決定
-------------------------------


```bash:コマンド
CF_STACK_NAME="${IAM_GROUP_NAME}-${PRJ_NAME}-${LOC_NAME}" \
        && echo ${CF_STACK_NAME}
```
        
3.2. スタックの作成
-------------------------------

```bash:変数の確認
cat << ETX

        CF_STACK_NAME:    ${CF_STACK_NAME}
        FILE_CF_TEMPLATE: ${FILE_CF_TEMPLATE}

ETX
```

```bash:コマンド
aws cloudformation create-stack \
        --stack-name "${CF_STACK_NAME}" \
        --template-body file://${FILE_CF_TEMPLATE} \
        --capabilities 'CAPABILITY_IAM'
```

```json:結果(例)
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/KinesisFull-handsOn-Kinesis/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX"
}
```

3.3. スタックのステータス確認
-------------------------------

```bash:コマンド
CF_STACK_STATUS=`aws cloudformation list-stacks |\
        jq -r --arg stackname ${CF_STACK_NAME} '.StackSummaries[] | select(.StackName == $stackname) | .StackStatus'` \
        && echo ${CF_STACK_STATUS}
```

```bash:結果
      CREATE_COMPLETE
```

'CREATE_COMPLETE'になっていれば作成は完了です。
それ以外が表示されている場合は、下記コマンドでFailedの文字が出ている前
後を見て原因を調べます。

```bash:コマンド
aws cloudformation describe-stack-events \
        --stack-name ${CF_STACK_NAME}
```
        
3.4. スタックの内容確認
-------------------------------

作成されたスタックの内容を確認します。

```bash:コマンド
aws cloudformation get-template \
        --stack-name ${CF_STACK_NAME}
```

```json:結果(例)
{
    "TemplateBody": {
        "AWSTemplateFormatVersion": "2010-09-09", 
        "Outputs": {
            "UserName": {
                "Description": "UserName of new user", 
                "Value": {
                    "Ref": "user"
                }
            }
        }, 
        "Description": "KinesisFull for handson.", 
        "Resources": {
            "belongGroups": {
                "Type": "AWS::IAM::UserToGroupAddition", 
                "Properties": {
                    "GroupName": "KinesisFull", 
                    "Users": [
                        {
                            "Ref": "user"
                        }
                    ]
                }
            }, 
            "user": {
                "Type": "AWS::IAM::User", 
                "Properties": {
                    "LoginProfile": {
                        "Password": "#userPass123"
                    }
                }
            }
        }
    }
}
```

3.5. スタックのユーザ名取得
-------------------------------

```bash:コマンド
CF_STACK_OUTPUT_KEY='UserName'
```

```bash:コマンド
STR_QUERY="Stacks[].Outputs[?OutputKey==\`${CF_STACK_OUTPUT_KEY}\`].OutputValue"  && echo ${STR_QUERY}

CF_STACK_OUTPUT_VALUE=`aws cloudformation describe-stacks --stack-name ${CF_STACK_NAME} --query ${STR_QUERY} --output text`  && echo ${CF_STACK_OUTPUT_VALUE}
```

```bash:コマンド
IAM_USER_NAME=${CF_STACK_OUTPUT_VALUE}
```

4. 確認
===============================

4.1. ユーザの確認
-------------------------------

```bash:コマンド
aws iam get-user --user-name ${IAM_USER_NAME}
```

```json:結果(例)
{
    "User": {
        "UserName": "KinesisFull-handsOn-Kinesis-user-5KVYHRGZMYWG", 
        "Path": "/", 
        "CreateDate": "2015-05-04T07:11:32Z", 
        "UserId": "AIDAJD6774QYU7CYCVXHY", 
        "Arn": "arn:aws:iam::252950251796:user/KinesisFull-handsOn-Kinesis-user-5KVYHRGZMYWG"
    }
}
```
      
4.2. ユーザのグループ所属確認
-------------------------------

IAMユーザが、所属しているIAMグループを確認します。

```bash:コマンド
IAM_GROUP_NAME=`aws iam list-groups-for-user \
        --user-name ${IAM_USER_NAME} \
        --query 'Groups[].GroupName' \
        --output text` \
        && echo ${IAM_GROUP_NAME}
```

```bash:結果
      KinesisFull
```
      
4.3. IAMグループの確認
-------------------------------

IAMユーザが所属しているIAMグループの詳細を確認します。

```bash:コマンド
aws iam get-group --group-name ${IAM_GROUP_NAME}
```

```json:結果(例)
{
    "Group": {
        "Path": "/", 
        "CreateDate": "2015-05-04T03:29:26Z", 
        "GroupId": "AGPAISM56HDBG3EOUYF76", 
        "Arn": "arn:aws:iam::252950251796:group/KinesisFull", 
        "GroupName": "KinesisFull"
    }, 
    "Users": [
        {
            "UserName": "KinesisFull-handsOn-Kinesis-user-5KVYHRGZMYWG", 
            "Path": "/", 
            "CreateDate": "2015-05-04T07:11:32Z", 
            "UserId": "AIDAJD6774QYU7CYCVXHY", 
            "Arn": "arn:aws:iam::252950251796:user/KinesisFull-handsOn-Kinesis-user-5KVYHRGZMYWG"
        }
    ]
}
```

5. ユーザのAPIアクセス設定
===============================

5.1. access keyの作成と取得
-------------------------------

```bash:変数の確認
cat << ETX

        IAM_USER_NAME:  ${IAM_USER_NAME}

ETX
```

```bash:コマンド
aws iam create-access-key --user-name ${IAM_USER_NAME} > ${IAM_USER_NAME}.json \
        && cat ${IAM_USER_NAME}.json
```

```json:結果(例)
{
    "AccessKey": {
        "UserName": "KinesisFull-handsOn-Kinesis-user-5KVYHRGZMYWG", 
        "Status": "Active", 
        "CreateDate": "2015-05-04T07:27:37.893Z", 
        "SecretAccessKey": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 
        "AccessKeyId": "AKIAXXXXXXXXXXXXXXXXX"
    }
}
```

5.2. 認証情報の作成
-------------------------------

sourceディレクトリ作成

```bash:コマンド
mkdir -p ~/.aws/source
```

```bash:結果
      (戻り値なし)
```

rcファイル作成

```bash:コマンド
cat ${IAM_USER_NAME}.json |\
        jq '.AccessKey | {AccessKeyId, SecretAccessKey}' |\
        sed '/[{}]/d' | sed 's/[\" ,]//g' | sed 's/:/=/' |\
        sed 's/AccessKeyId/aws_access_key_id/' |\
        sed 's/SecretAccessKey/aws_secret_access_key/' \
        > ~/.aws/source/${IAM_USER_NAME}.rc \
        && cat ~/.aws/source/${IAM_USER_NAME}.rc
```

```bash:結果(例)
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

configファイル(単体)作成

```bash:コマンド
REGION_AWS_CONFIG="${AWS_DEFAULT_REGION}"
```

```bash:コマンド
FILE_USER_CONFIG="${HOME}/.aws/source/${IAM_USER_NAME}.config"

echo "[profile ${IAM_USER_NAME}]" > ${FILE_USER_CONFIG} \
        && echo "region=${REGION_AWS_CONFIG}" >> ${FILE_USER_CONFIG} \
        && echo "" >> ${FILE_USER_CONFIG} \
        && cat ${FILE_USER_CONFIG}
```

```bash:結果(例)
[profile KinesisFull-handsOn-Kinesis-user-5KVYHRGZMYWG]
region=ap-northeast-1
```

~/.aws/credentials作成

```bash:バックアップ
cp ~/.aws/credentials ~/.aws/credentials.old
```

```bash:コマンド
file="${HOME}/.aws/credentials"
if [ -e ${file} ]; then mv ${file} ${file}.bak; fi
for i in `ls ${HOME}/.aws/source/*.rc`; do \
        name=`echo $i | sed 's/^.*\///' | sed 's/\.rc$//'` \
        && echo "[$name]" >> ${file} \
        && cat $i >> ${file} \
        && echo "" >> ${file} ;done \
        && cat ${file}
```

```bash:結果(例)
[KinesisFull-handsOn-Kinesis-user-5KVYHRGZMYWG]
aws_access_key_id=AKIAXXXXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

~/.aws/config作成

```bash:バックアップ
cp ~/.aws/config ~/.aws/config.old
```

```bash:コマンド
cat ${HOME}/.aws/source/*.config > ${HOME}/.aws/config \
        && cat ${HOME}/.aws/config
```

```bash:結果(例)
[profile KinesisFull-handsOn-Kinesis-user-5KVYHRGZMYWG]
region=ap-northeast-1
```

6. ユーザの切り替え
===============================

6.1. 現在のユーザの確認
-------------------------------

```bash:変数の確認
aws configure list | grep profile
```

```bash:結果(例)
      profile      iam_full-prjZ-mbp13              env    AWS_DEFAULT_PROFILE
```

6.2. 切替後ユーザの確認
-------------------------------

```bash:変数の確認
cat << ETX

        new:     IAM_USER_NAME:       ${IAM_USER_NAME}

ETX
```

6.3. ユーザの切り替え
-------------------------------

```bash:コマンド
export AWS_DEFAULT_PROFILE=${IAM_USER_NAME}
echo ${AWS_DEFAULT_PROFILE}
```

6.4. コマンドテスト
-------------------------------

```bash:コマンド
aws kinesis list-streams 
```

```json:結果(例)
{
    "StreamNames": []
}
```

7. 認証ファイルの削除
===============================

```bash:コマンド
rm ${IAM_USER_NAME}.json
```

完了
===============================