KubernetesのSecret情報をExternalSecretとAWS Secrets Managerで安全に管理する方法


はじめに

セゾン情報システムズ Advent Calendar 2020
2日目を担当させていただきます。よろしくお願いいたします!

本記事では、以下を使用することで、機密情報をマニフェストファイルに記載することなく安全に管理する方法を紹介いたします。

概要

kubernetes上に作成されたExternalSecretリソースが、外部のSecretManagerに登録されている情報を読み取り、Secretリソースを作成します。

Secretリソースとして登録するKey名と、外部のSecretManagerに登録されているデータの参照情報で秘匿情報を取得できるため、
機密情報をマニフェストファイルに記載する必要はありません!

手順

AWS Secrets Managerに登録されている秘匿情報を取得する手順を記載いたします。

サービスアカウントへのIAM権限付与設定

AWSリソースへアクセスするための権限をpod単位で付与したかったので、「IAM Roles for Service Accounts」の仕組みを使用

IAM IDプロバイダ作成

Kubernetes サービスアカウントでIAMロールの権限を使用するために、まずは以下のコマンドでOIDC IDプロバイダを作成

eksctl utils associate-iam-oidc-provider --cluster {CLUSTER_NAME} --approve --region ap-northeast-1

IAMロール作成

既存のAWSのポリシーに「SecretsManagerReadWrite」があるので、そのポリシーを付与したIAMロールを作成し、
上記で作成したOIDC IDプロバイダのIDを信頼関係に設定

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::{AWS_ACCOUNT_ID}:oidc-provider/oidc.eks.ap-northeast-1.amazonaws.com/id/{PROVIDER_ID}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.ap-northeast-1.amazonaws.com/id/{PROVIDER_ID}:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "oidc.eks.ap-northeast-1.amazonaws.com/id/{PROVIDER_ID}:sub": "system:serviceaccount:default:*"
        }
      }
    }
  ]
}

※「*」を使用する場合は、「StringEquals」ではなく「StringLike」を使用する必要あり!

AWS Secrets Managerで秘匿情報登録

e.g.
シークレット名:test-credentials
値:{"username":"admin","password":"admin123"}

以下のようにAWS CLIで作成

aws secretsmanager create-secret --region ap-northeast-1 --name test-credentials --secret-string '{"username":"admin","password":"admin123"}'

ExternalSecretリソース作成

helmでExternalSecretのリポジトリを追加
(リポジトリは最近移動したらしい -> 関連記事)

helm repo add external-secrets https://external-secrets.github.io/kubernetes-external-secrets/

helm installでExternalSecretリソースを作成

helm install {RELEASE_NAME} external-secrets/kubernetes-external-secrets --skip-crds \
--set securityContext.fsGroup=65534 \
--set nodeSelector."alpha\.eksctl\.io/nodegroup-name"={NODE_GROUP_NAME} \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"='arn:aws:iam::{AWS_ACCOUNT_ID}:role/{ROLE_NAME}' \
--set env.AWS_REGION='ap-northeast-1' \
--set env.AWS_DEFAULT_REGION='ap-northeast-1'

securityContext.fsGroup=65534 :
シークレット情報にアクセスするためのtokenファイルに、rootユーザー以外のユーザーがアクセスできるようにするための設定
(起動したpodのユーザーはrootではないため必要な設定)

nodeSelector :
指定したNodeにpodを起動させたかったので設定

serviceAccount.annotations :
サービスアカウントでIAMロールの権限を使用するための設定、上記で作成したIAMロールを指定

その他オプション等については以下参照
https://artifacthub.io/packages/helm/external-secrets/kubernetes-external-secrets

Secret Managerから秘匿情報取得

以下のyamlをkubectlでapply

externalSecret.yaml
apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: test-external-secret
spec:
  backendType: secretsManager
  data:
    - key: test-credentials #SecretManagerのシークレット名
      name: username #変数名
      property: username #取得したい値のキー
$ kubeclt apply -f externalSecret.yaml
$ kubectl get externalsecret
NAME                    LAST SYNC   STATUS    AGE
test-external-secret    2s          SUCCESS   34h

以下のコマンドで取得した秘匿情報の確認も可能
↓結果抜粋↓(値はbase64でエンコードされてます)

$ kubectl get secret test-external-secret -o yaml
data:
  username: YWRtaW4K
  password: YWRtaW4xMjMK
  :

上記の秘匿情報を使用する場合は以下のようにyamlに環境変数を定義することで使用可能

env:
  - name: TEST_VALUE
    valueFrom:
      secretKeyRef:
        name: test-external-secret #ExternalSecretのmetadata.name
        key: username #ExternalSecretのspec.data.name