【EKS】Pod IdentityでAWS Secrets Manager and Config Provider(ASCP)を利用する

※ 参考 : [ASCP と Pod Identity の統合を発表: Amazon EKS でのシークレット管理のセキュリティ強化 | AWS ブログ](https://aws.amazon.com/jp/blogs/security/announcing-ascp-integration-with-pod-identity-enhanced-security-for-secrets-management-in-amazon-eks/)

# Secrets Store CSI Driver と secrets-store-csi-driver-provider-aws のインストール

Secrets Store CSI Driver と secrets-store-csi-driver-provider-aws をインストールします。
今回はterraformのhelmプロバイダを利用してインストールしました。
※ バージョンが古いとPod Identityで利用できなかったので注意

- [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation)
- [secrets-store-csi-driver-provider-aws](https://github.com/aws/secrets-store-csi-driver-provider-aws/tree/main)

最新バージョンの確認

```bash
helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm search repo secrets-store-csi-driver
# NAME                                                    CHART VERSION   APP VERSION     DESCRIPTION                                       
# secrets-store-csi-driver/secrets-store-csi-driver       1.4.8           1.4.8           A Helm chart to install the SecretsStore CSI Dr...

helm repo add aws-secrets-manager https://aws.github.io/secrets-store-csi-driver-provider-aws
helm search repo secrets-store-csi-driver-provider-aws
# NAME                                                    CHART VERSION   APP VERSION     DESCRIPTION                                       
# aws-secrets-manager/secrets-store-csi-driver-pr...      0.3.11                          A Helm chart for the AWS Secrets Manager and Co...
```

terraformの定義

```tf
/**
 * Secrets Store CSI Driver チャートのインストール
 * helmコマンドでのインストール
 * $ helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
 * $ helm install -n kube-system csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver
 */
resource "helm_release" "csi_secrets_store" {
  //helm_release - helm - terraform: https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release
  name       = "csi-secrets-store"
  repository = "https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts"
  chart      = "secrets-store-csi-driver"
  version    = "1.4.8"  # helm search repo secrets-store-csi-driver
  namespace  = "kube-system"
  create_namespace = true

  // Option Values - Secrets Store CSI Driver: https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html#optional-values
  set {
    // KubernetesのSecretオブジェクトへの同期を有効化
    name = "syncSecret.enabled"
    value = true
  }

  set {
    // シークレット情報変更時のローテーションを有効化
    name = "enableSecretRotation"
    value = true
  }
}

/**
 * ASCP (aws secrets store csi provider) チャートのインストール
 * helmコマンドでのインストール
 * $ helm repo add aws-secrets-manager https://aws.github.io/secrets-store-csi-driver-provider-aws
 * $ helm install -n kube-system secrets-provider-aws aws-secrets-manager/secrets-store-csi-driver-provider-aws
 */
resource "helm_release" "secrets_provider_aws" {
  //helm_release - helm - terraform: https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release
  name       = "secrets-provider-aws"
  repository = "https://aws.github.io/secrets-store-csi-driver-provider-aws"
  chart      = "secrets-store-csi-driver-provider-aws"
  version    = "0.3.11"  # helm search repo secrets-store-csi-driver-provider-aws
  namespace  = "kube-system"
  create_namespace = true

  depends_on = [
    helm_release.csi_secrets_store
  ]
}
```

# SecretsManagerでシークレットの作成


```bash
aws secretsmanager create-secret \
  --name /baseport/prd/sample \
  --secret-string '{"password":"sample_password","username":"sample_user"}'
```


# サービスアカウントに紐づけるIAMロール

Pod Identityでサービスアカウントに紐づけるIAM ロールを作成します。

※ 参考: [IAM ロールを Kubernetes サービスアカウントに割り当てる | AWS](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/pod-id-association.html)

### ロール名

`baseport-prd-PodIdentityTest`

### 信頼ポリシー

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowEksAuthToAssumeRoleForPodIdentity",
            "Effect": "Allow",
            "Principal": {
                "Service": "pods.eks.amazonaws.com"
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
    ]
}
```

### ポリシー

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:/baseport/prd/*"
        }
    ]
}
```

# Pod Identity Assosiation
Pod Identityの関連付けを作成します。

```bash
aws eks create-pod-identity-association \
  --cluster-name クラスタ名 \
  --role-arn arn:aws:iam::111122223333:role/baseport-prd-PodIdentityTest \
  --namespace pod-identity-test \
  --service-account test
```

# マニフェスト

ネームスペース `pod-identity-test` を作成

```yml:ns.yaml
---
apiVersion: v1
kind: Namespace
metadata:
  name: pod-identity-test
```

サービスアカウント `test` を作成

```yml:sa.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test
  namespace: pod-identity-test
```

SecretProviderClassのマニフェスト。
先ほど作成したSecretsManager `/baseport/prd/ascp-test` を参照します。

※ `spec.parameters.usePodIdentity` に `"true"` を設定するのを忘れずに

```yml:spc.yaml
---
# https://docs.aws.amazon.com/secretsmanager/latest/userguide/integrating_csi_driver_SecretProviderClass.html
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  namespace: pod-identity-test
  name: ascp-test-secrets
spec:
  provider: aws
  secretObjects:
    - secretName: db-secret
      type: Opaque
      data:
        - key: username
          objectName: alias_username
        - key: password
          objectName: alias_password
  parameters:
    usePodIdentity: "true"  # ★重要
    objects: |
        - objectName: "/baseport/prd/ascp-test"
          objectType: "secretsmanager"
          jmesPath:
            - path: "username"
              objectAlias: "alias_username"  # ポッドにマウントするファイル名
            - path: "password"
              objectAlias: "alias_password"  # ポッドにマウントするファイル名
```

アプリのマニフェスト。
SecretProviderClassをvolumeとしてマウントし、環境変数から参照します。

```yml:app.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: pod-identity-test
  name: ascp-test
spec:
  selector:
    matchLabels:
      app: ascp-test
  replicas: 2
  template:
    metadata:
      labels:
        app: ascp-test
    spec:
      serviceAccountName: test
      containers:
        - name: ascp-test
          image: ubuntu
          command: ["sleep", "infinity"]
          env:
          - name: DB_USER
            valueFrom:
              secretKeyRef:
                name: db-secret # SecretObjectsのsecretName
                key: username
          - name: DB_PASSWORD
            valueFrom:
              secretKeyRef:
                name: db-secret # SecretObjectsのsecretName
                key: password
          volumeMounts:
            - name: csi-secret-volume
              mountPath: /mnt/secrets-store
              readOnly: true
      volumes:
        # CSIストレージ指定
        - name: csi-secret-volume
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: ascp-test-secrets

```

### アプライ

```bash
kubectl apply -f ns.yaml
kubectl apply -f sa.yaml
kubectl apply -f spc.yaml
kubectl apply -f app.yaml
```


# 動作確認

```bash
# ポッドを確認
kubectl get po -n pod-identity-test 
# NAME                         READY   STATUS    RESTARTS   AGE
# ascp-test-5759cdfc5b-cvr2l   1/1     Running   0          46m
# ascp-test-5759cdfc5b-qq82d   1/1     Running   0          46m

# podにログイン
kubectl -n pod-identity-test exec -ti ascp-test-5759cdfc5b-cvr2l /bin/bash
```

以下Pod内での操作

```bash
# 環境変数に設定されていることを確認
printenv | grep "^DB_"
# DB_PASSWORD=piyopiyo
# DB_USER=hogehoge

# シークレットファイルがマウントされていることを確認
ls /mnt/secrets-store/
# _baseport_prd_ascp-test  alias_password  alias_username


# 中身を確認
echo $(cat /mnt/secrets-store/_baseport_prd_ascp-test )
# {"username":"hogehoge", "password":"piyopiyo"}
echo $(cat /mnt/secrets-store/alias_username )
# hogehoge
echo $(cat /mnt/secrets-store/alias_password )
# piyopiyo
```