[JAWS-UG CLI] Amazon KMS 入門 (1) カスタマーマスターキーの作成

# このハンズオンについて

この手順は、[JAWS-UG CLI専門支部 #58 KMS入門](https://manage.doorkeeper.jp/groups/jawsug-cli/events/41911)で実施したものです。


# 前提条件

## 必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

- KMSに対するフルコントロール権限
- S3に関するフルコントロール権限
- STSに関するフルコントロール権限
- IAMに関するフルコントロール権限

# 0. 準備

## 0.1. リージョンを指定

```bash:コマンド
export AWS_DEFAULT_REGION='ap-northeast-1'
```

## 0.2. 資格情報を確認


```bash:コマンド
aws configure list
```

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

```text:結果
Name                    Value             Type    Location
----                    -----             ----    --------
profile                <not set>             None    None
access_key     ****************RDPA         iam-role
secret_key     ****************9GA8         iam-role
region           ap-northeast-1              env    AWS_DEFAULT_REGION
```

## 0.3. バージョン確認

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

```text:結果
aws-cli/1.10.56 Python/2.7.10 Linux/4.4.15-25.57.amzn1.x86_64 botocore/1.4.46
```

## 0.4. バージョンアップ（必要に応じて）

```bash:コマンド
sudo pip install -U awscli
```

# 1. カスタマーマスターキーの作成

## 1.1. キーの不存在を確認

```bash:コマンド
aws kms list-keys
```

```json:結果
{
    "Keys": []
}
```

## 1.2. カスタマーマスターキーの説明を指定

descriptionは必須ではありませんが、運用時にはきちんと設定しましょう。

```bash:コマンド
KEY_DESCRIPTION='JAWS-UG CLI 58 KMS at Co-Edo'
```

## 1.3. カスタマーマスターキーの作成

### 変数の確認

```bash:コマンド
cat << ETX

    KEY_DESCRIPTION: "${KEY_DESCRIPTION}"

ETX
```

```text:結果

    KEY_DESCRIPTION: "JAWS-UG CLI 58 KMS at Co-Edo"

```

### カスタマーマスターキーの作成

```bash:コマンド
KEY_ID=$(aws kms create-key \
    --description "${KEY_DESCRIPTION}" \
    --query KeyMetadata.KeyId \
    --output text) \
    && echo ${KEY_ID}
```

```text:結果（例）
********-****-****-****-************
```

## 1.4. キーの存在確認

```bash:コマンド
aws kms list-keys \
    --query "Keys[?KeyId == \`${KEY_ID}\`]"
```

```json:結果
{
    "Keys": [
        {
            "KeyArn": "arn:aws:kms:ap-northeast-1:************:key/********-****-****-****-************",
            "KeyId": "********-****-****-****-************"
        }
    ]
}
```

## 1.5. キーの確認

```bash:コマンド
aws kms describe-key \
    --key-id ${KEY_ID}
```

```json:結果
{
    "KeyMetadata": {
        "KeyId": "********-****-****-****-************",
        "Description": "JAWS-UG CLI 58 KMS at Co-Edo",
        "Enabled": true,
        "KeyUsage": "ENCRYPT_DECRYPT",
        "KeyState": "Enabled",
        "CreationDate": 1467540748.716,
        "Arn": "arn:aws:kms:ap-northeast-1:************:key/********-****-****-****-************",
        "AWSAccountId": "************"
    }
}
```

## 1.6. エイリアス名の指定

CMKを識別する際、KeyIdの以外にAliasを指定することが可能です。

```bash:コマンド
ALIAS="alias/cli-handson0800"
```

## 1.7.  エイリアスの作成

### 変数の確認

```bash:コマンド
cat << ETX

    ALIAS: ${ALIAS}
    KEY_ID: ${KEY_ID}

ETX
```

```text:結果

    ALIAS: alias/cli-handson08015
    KEY_ID: ********-****-****-****-************

```

### エイリアスの作成

```bash:コマンド
aws kms create-alias \
    --alias-name ${ALIAS} \
    --target-key-id ${KEY_ID}
```

```text:結果
（返値無し）
```

## 1.8. エイリアスの確認

```bash:コマンド
aws kms list-aliases \
    --query "Aliases[?TargetKeyId == \`${KEY_ID}\`]"
```

```json:結果
{
    "Aliases": [
        {
            "AliasArn": "arn:aws:kms:ap-northeast-1:************:alias/cli-handson01",
            "AliasName": "alias/cli-handson01",
            "TargetKeyId": "********-****-****-****-************"
        }
    ]
}
```


# 2. ユーザの作成

KMSによるユーザ操作を行うためのIAMユーザを定義します。

このシナリオでは、データキーを取り扱う一般ユーザと、CMKの管理を行う管理者ユーザを作成します。

これらのユーザに対し、KMSに関する権限をIAMでは付与せず、KMS側でコントロールします。
（詳細は後述します。）

## 2.1. 管理ユーザ名の指定

```bash:コマンド
ADMIN_NAME='jawsug-cli-admin'
```

## 2.2. 管理ユーザの不存在を確認

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

```text:結果
An error occurred (NoSuchEntity) when calling the GetUser operation: The user with name jawsug-cli-admin cannot be found.
```

## 2.3. 管理ユーザの作成

### 変数の確認

```bash:コマンド
cat << ETX

    ADMIN_NAME: ${ADMIN_NAME}

ETX
```

```text:結果

    ADMIN_NAME: jawsug-cli-admin

```

### 管理ユーザの作成

```bash:コマンド
aws iam create-user \
    --user-name ${ADMIN_NAME}
```

```json:結果
{
    "User": {
        "UserName": "jawsug-cli-admin",
        "Path": "/",
        "CreateDate": "2016-07-23T06:59:00.482Z",
        "UserId": "A********************",
        "Arn": "arn:aws:iam::************:user/jawsug-cli-admin"
    }
}
```

## 2.4. 実行結果の確認

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

```json:結果
{
    "User": {
        "UserName": "jawsug-cli-admin",
        "Path": "/",
        "CreateDate": "2016-08-01T09:22:14Z",
        "UserId": "A********************",
        "Arn": "arn:aws:iam::************:user/jawsug-cli-admin"
    }
}
```

## 2.5. 利用ユーザ名の指定

```bash:コマンド
USER_NAME='jawsug-cli-user'
```

## 2.6. 利用ユーザの不存在を確認

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

```text:結果
An error occurred (NoSuchEntity) when calling the GetUser operation: The user with name jawsug-cli-user cannot be found.
```

## 2.7. 利用ユーザの作成

### 変数の確認

```bash:コマンド
cat << ETX

    USER_NAME: ${USER_NAME}

ETX
```

```text:結果

    USER_NAME: jawsug-cli-user

```

### 利用ユーザの作成

```bash:コマンド
aws iam create-user \
    --user-name ${USER_NAME}
```

```json:結果
{
    "User": {
        "UserName": "jawsug-cli-user",
        "Path": "/",
        "CreateDate": "2016-07-23T07:00:59.402Z",
        "UserId": "A********************",
        "Arn": "arn:aws:iam::************:user/jawsug-cli-user"
    }
}
```

## 2.8. 実行結果の確認

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

```json:結果
{
    "User": {
        "UserName": "jawsug-cli-user",
        "Path": "/",
        "CreateDate": "2016-08-01T09:24:40Z",
        "UserId": "A********************",
        "Arn": "arn:aws:iam::************:user/jawsug-cli-user"
    }
}
```

# 3. ポリシーの定義

KMSで作成するCMK（カスタマーマスターキー）に対して設定するポリシーを定義します。
（IAMユーザに対してではなく、リソースであるCMSに対して付与するポリシーです。）

先に作成したIAMユーザに対する権限付与は、ここで実施します。

## 3.1. AWSアカウントIDの特定

```bash:コマンド
AWS_ID=$(aws sts get-caller-identity \
    --query Account \
    --output text) \
    && echo ${AWS_ID}
```

```text:結果
************
```

## 3.2. ポリシーを生成するファイル名を指定

```bash:コマンド
POLICY_FILE='policy.json'
```

## 3.3. ポリシーの生成

### 変数の確認

```bash:コマンド
cat << ETX

    POLICY_FILE: ${POLICY_FILE}
    AWS_ID: ${AWS_ID}
    ADMIN_NAME: ${ADMIN_NAME}
    USER_NAME: ${USER_NAME}

ETX
```

```text:結果

    POLICY_FILE: policy.json
    AWS_ID: ************
    ADMIN_NAME: jawsug-cli-admin
    USER_NAME: jawsug-cli-user

```

### ポリシーの生成

ここでは以下の4つの目的を実現するためのポリシーを記載しています。

- rootユーザにKMSに関する全ての権限を付与
- 管理者ユーザにCMKを管理する権限を付与
- 一般ユーザにCMKを利用する権限を付与
- 永続化リソースの適用許可

以下の記事が参考になります。

[AWS Key Management Serviceでキーの”管理”と”利用”を分離する #reinvent](http://dev.classmethod.jp/cloud/aws/kms-admin-user/)

```bash:コマンド
cat << EOF > ${POLICY_FILE}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Enable IAM User Permissions",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::${AWS_ID}:root"
        ]
      },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "Allow access for Key Administrators",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::${AWS_ID}:user/${ADMIN_NAME}"
        ]
      },
      "Action": [
        "kms:Create*",
        "kms:Describe*",
        "kms:Enable*",
        "kms:List*",
        "kms:Put*",
        "kms:Update*",
        "kms:Revoke*",
        "kms:Disable*",
        "kms:Get*",
        "kms:Delete*",
        "kms:ScheduleKeyDeletion",
        "kms:CancelKeyDeletion"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Allow use of the key",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::${AWS_ID}:user/${USER_NAME}"
        ]
      },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:DescribeKey"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Allow attachment of persistent resources",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::${AWS_ID}:user/${USER_NAME}"
        ]
      },
      "Action": [
        "kms:CreateGrant",
        "kms:ListGrants",
        "kms:RevokeGrant"
      ],
      "Resource": "*",
      "Condition": {
        "Bool": {
          "kms:GrantIsForAWSResource": true
        }
      }
    }
  ]
}
EOF

jsonlint -q ${POLICY_FILE}
```


## 3.4. ポリシー名の決定

defaultを使用しなければならないことがドキュメントに明記されています。

```bash:コマンド
POLICY_NAME="default"
```

## 3.5. ポリシーの設定

### 変数の確認

```bash:コマンド
cat << ETX

    KEY_ID: ${KEY_ID}
    POLICY_NAME: ${POLICY_NAME}
    POLICY_FILE: ${POLICY_FILE}

ETX
```

```text:結果

    KEY_ID: ********-****-****-****-************
    POLICY_NAME: default
    POLICY_FILE: policy.json

```

### ポリシーの設定

```bash:コマンド
aws kms put-key-policy \
    --key-id ${KEY_ID} \
    --policy-name ${POLICY_NAME} \
    --policy file://${POLICY_FILE}
```

```text:結果
（戻り値なし）
```

## 3.6. ポリシーの確認

```bash:コマンド
aws kms get-key-policy \
    --key-id ${KEY_ID} \
    --policy-name ${POLICY_NAME}
```

```json:結果
{
    "Policy": "{\n  \"Version\" : \"2012-10-17\",\n  \"Statement\" : [ {\n    \"Sid\" : \"Enable IAM User Permissions\",\n    \"Effect\" : \"Allow\",\n    \"Principal\" : {\n      \"AWS\" : \"arn:aws:iam::************:root\"\n    },\n    \"Action\" : \"kms:*\",\n    \"Resource\" : \"*\"\n  }, {\n    \"Sid\" : \"Allow access for Key Administrators\",\n    \"Effect\" : \"Allow\",\n    \"Principal\" : {\n      \"AWS\" : \"arn:aws:iam::************:user/jawsug-cli-admin\"\n    },\n    \"Action\" : [ \"kms:Create*\", \"kms:Describe*\", \"kms:Enable*\", \"kms:List*\", \"kms:Put*\", \"kms:Update*\", \"kms:Revoke*\", \"kms:Disable*\", \"kms:Get*\", \"kms:Delete*\", \"kms:ScheduleKeyDeletion\", \"kms:CancelKeyDeletion\" ],\n    \"Resource\" : \"*\"\n  }, {\n    \"Sid\" : \"Allow use of the key\",\n    \"Effect\" : \"Allow\",\n    \"Principal\" : {\n      \"AWS\" : \"arn:aws:iam::************:user/jawsug-cli-user\"\n    },\n    \"Action\" : [ \"kms:Encrypt\", \"kms:Decrypt\", \"kms:ReEncrypt*\", \"kms:GenerateDataKey*\", \"kms:DescribeKey\" ],\n    \"Resource\" : \"*\"\n  }, {\n    \"Sid\" : \"Allow attachment of persistent resources\",\n    \"Effect\" : \"Allow\",\n    \"Principal\" : {\n      \"AWS\" : \"arn:aws:iam::************:user/jawsug-cli-user\"\n    },\n    \"Action\" : [ \"kms:CreateGrant\", \"kms:ListGrants\", \"kms:RevokeGrant\" ],\n    \"Resource\" : \"*\",\n    \"Condition\" : {\n      \"Bool\" : {\n        \"kms:GrantIsForAWSResource\" : \"true\"\n      }\n    }\n  } ]\n}"
}
```


以上