EKSのSecretのKMSでの暗号化

EKSのSecretのKMSでの暗号化を確認したメモ。

ユーザーから見える部分は今までと変わりなく、API Serverがetcdにデータを保存するときの暗号化にKMSキーが使用できるようになっただけという理解。この理解が間違っていないことを確認する。

Walkthrough

暗号化に使用するクラスターと同じリージョンにKMSキーを作成する。

MASTER_KEY_ARN=$(aws kms create-key --query KeyMetadata.Arn --output text)
aws kms create-alias \
    --alias-name alias/k8s-master-key \
    --target-key-id $(echo ${MASTER_KEY_ARN} | cut -d "/" -f 2)

作成したKMSキーをマネジメントコンソールでも確認する。

f:id:sotoiwa:20200430195910p:plain

eksctlはまだクラスター作成時のKMSキーの指定をサポートしていないよう。

なので、マネジメントコンソールからクラスターを作成する。

このとき、KMSキーを指定する。

f:id:sotoiwa:20200430195931p:plain

CLIの場合は以下のように指定する。デフォルトVPCに作成する場合の例。

vpc_id=$(aws ec2 describe-vpcs | jq -r '.Vpcs[] | select( .IsDefault ) | .VpcId')
subnet_ids=$(aws ec2 describe-subnets | jq -r '.Subnets[] | select ( .VpcId == "'${vpc_id}'" ) | .SubnetId' | tr '\n' ',' | sed -e 's/,$/\n/g')
account_id=$(aws sts get-caller-identity --output text --query Account)
cat <<EOF > input.json
{
    "name": "kms",
    "version": "1.15",
    "roleArn": "arn:aws:iam::${account_id}:role/eksClusterRole",
    "resourcesVpcConfig": {
        "subnetIds": [
            ${subnet_ids}
        ],
        "securityGroupIds": [
            "sg-9948bfec"
        ],
        "endpointPublicAccess": true,
        "endpointPrivateAccess": false
    },
    "encryptionConfig": [
        {
            "resources": [
                "secrets"
            ],
            "provider": {
                "keyArn": "${MASTER_KEY_ARN}"
            }
        }
    ]
}
EOF
aws eks create-cluster --cli-input-json file://input.json

Secretの確認をしたいだけなので、ノードはなくても確認できる。

kubeconfigを作成する。

aws eks update-kubeconfig --name kms

クラスターに接続できることを確認する。

$ kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   40m

Secretを作成してみる。

$ kubectl create secret generic test --from-literal testkey=testvalue
secret/test created
$ kubectl get secret test -o yaml
apiVersion: v1
data:
  testkey: dGVzdHZhbHVl
kind: Secret
metadata:
  creationTimestamp: "2020-04-30T05:55:48Z"
  name: test
  namespace: default
  resourceVersion: "3792"
  selfLink: /api/v1/namespaces/default/secrets/test
  uid: c7d6a4db-3630-4f40-915b-edacc1ccb116
type: Opaque
$ kubectl get secret test -o json | jq -r '.data.testkey'
dGVzdHZhbHVl
$ kubectl get secret test -o json | jq -r '.data.testkey' | base64 --decode
testvalue

別にSecretが暗号化されているわけではなく、これまでと何ら変わりない。

CloudTrailでイベントを見てみる。詳細はよくわからないが、KMSキーが使われていそうなことはわかる。

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AWSService",
        "invokedBy": "eks.amazonaws.com"
    },
    "eventTime": "2020-04-30T05:55:48Z",
    "eventSource": "kms.amazonaws.com",
    "eventName": "Decrypt",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "eks.amazonaws.com",
    "userAgent": "eks.amazonaws.com",
    "requestParameters": {
        "encryptionContext": {
            "aws:eks:context": "51cc1354-2b57-4697-8b56-f8094e200721"
        },
        "encryptionAlgorithm": "SYMMETRIC_DEFAULT"
    },
    "responseElements": null,
    "requestID": "55ced85f-e2e6-440f-a5e0-8ee159d99ef7",
    "eventID": "f8803fd3-42c2-4458-be16-7129393c7342",
    "readOnly": true,
    "resources": [
        {
            "accountId": "XXXXXXXXXXXX",
            "type": "AWS::KMS::Key",
            "ARN": "arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/14baef70-20a3-4202-93ad-fdfd12d52f60"
        }
    ],
    "eventType": "AwsApiCall",
    "recipientAccountId": "XXXXXXXXXXXX",
    "sharedEventID": "3e7f8ff5-b1e8-430c-8904-4a279706aace"
}

Secretのyamlの管理という意味では、kubernetes-external-secretsがよさそう。