TECHSTEP

ITインフラ関連の記事を公開してます。

Kubernetes External SecretsからExternal Secrets Operatorへの移行方法を調査する

今回は、Kubernetes External SecretsからExternal Secrets Operatorへ移行する際のポイントを調査しました。

前回触れたExternal Secrets Operator (以降ESO) は、同様の機能を提供する Kubernetes External Secrets (以降KES) から移行先として推奨されているプロダクトです。そのため、すでにKESを使っているプロジェクトではESOへの移行を検討する必要があります。

今回は、KESからESOへ移行する際に注意するべき点や、実際の移行方法について調査・検証しました。なお、KESからESOへの移行は、すでにProduction環境で実施している例がいくつかあるため、そちらも参考にしてください。

※参考:

移行時のポイント

今回調査してわかった結論を先に書いておきます。

  • KESインストール時にリソース名を変更している場合、ESOのリソース名と重複する可能性があるため、必要に応じてESO側のリソース名を変更する
  • KESとESOの扱う ExternalSecretAPIが異なるため、同一クラスターにリソースを作成しても問題ない
  • KESとESOとで同じ名称のSecretを扱う場合、Secret中の metadata.ownerReferences を変更する必要がある。これを避けたい場合はKESとESOで異なるSecret名にする必要がある。

移行方法の概要

KESからESOへの移行を行う際のパターンはいくつかありそうですが、大きくは KESの管理する既存のSecretをESOが管理するよう移行する か、 ESO用の新しい名称のSecretリソースを使う かに分かれそうです。

ESOのドキュメントには、KESからESOへの移行をサポートする kes-to-eso というツールが紹介されています。このツールは、KES・ESOがどちらもインストールされていることを前提に、既存のKES ExternalSecret の設定をもとに、ESO SecretStore ExternalSecret のテンプレートを生成・デプロイします。そのため、このツールによる移行は、KESの管理するSecretをESOが管理するように移行する方法となります。

上記ツールによるAutomatic migrationを実行すると、以下のような動きで移行を実行します。


  • クラスター上のKES ExternalSecrets リソースの情報からマニフェストファイルを作成し、 kes_files フォルダに保存する
  • ESO replicasetのPod数をゼロにスケールインする
  • KES ExternalSecrets ファイルからESO SecretStore ExternalSecrets を生成し、 eso_files フォルダに保存する
  • ESO SecretStore ExternalSecrets リソースをクラスター上に作成する
  • KES replicasetのPod数をゼロにスケールインする
  • KESの管理するSecretリソースからKESのownershipを削除する
  • ESO replicasetのPod数を1にスケールアウトする

一方、ESOが管理するSecretは別名で用意し、アプリケーションは新しいSecretを見るように変更する方法もあります。こちらは最後のほうで少し触れます。

今回は kes-to-eso ツールをもとにKESからESOへの移行方法を検討し、以下のような流れでの作業を実施します。また作業前にいくつか疑問点が生じたので、そちらの解消も行います。

  1. ESOをKESと同じクラスター上にインストールする
  2. SecretStore ExternalSecret をデプロイする
  3. KESの扱う既存SecretからKESのownershipを削除する
  4. KES関連リソースを削除する

前提条件

前提として、今回は 移行前後で同じ名称のSecretリソースを更新し、既存のPodの設定に変更が入らないようにする こととしました。

また、KES/ESOがそれぞれAWSリソースにアクセスするための権限ですが、KESはあらかじめEKSノードにSecrets Managerへのアクセス権を付与して、ESOはAWSアカウント情報を持つSecretリソースを別に用意する形で付与しました。なお、IRSAを使用した場合については後述します。

検証環境

KESからESOへの移行を試すため、あらかじめKESをインストールしたKubernetesクラスターを用意します。

使用する環境は Amazon EKS ver 1.22になります。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.0", GitCommit:"c2b5237ccd9c0f1d600d3072634ca66cefdf272f", GitTreeState:"clean", BuildDate:"2021-08-04T18:03:20Z", GoVersion:"go1.16.6", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"22+", GitVersion:"v1.22.16-eks-ffeb93d", GitCommit:"52e500d139bdef42fbc4540c357f0565c7867a81", GitTreeState:"clean", BuildDate:"2022-11-29T18:41:42Z", GoVersion:"go1.16.15", Compiler:"gc", Platform:"linux/amd64"}

また、KES/ESOが扱うAWS Secrets Managerは以下になります。

$ aws secretsmanager get-secret-value --secret-id test-secret
{
    "ARN": "arn:aws:secretsmanager:ap-northeast-1:111111111111:secret:test-secret-Rn6ufG",
    "Name": "test-secret",
    "VersionId": "93ed3aed-6048-41da-afec-48da94566aec",
    "SecretString": "{\"password\":\"1234\"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": "2023-01-07T20:54:39.190000+09:00"
}

検証を始める前に、あらかじめKESをインストールしておきます。KESのインストールにはHelmパッケージを利用すればよいですが、今回は helm template から生成したマニフェストファイル群を利用しました。

# templateファイルの生成
$ git clone https://github.com/external-secrets/kubernetes-external-secrets.git
$ cd kubernetes-external-secrets
$ helm template --output-dir ./testdir ./charts/kubernetes-external-secrets/

# KESのインストール
$ kubectl apply -f ./charts/kubernetes-external-secrets/crds
$ kubectl apply -f ./testdir/kubernetes-external-secrets/templates/


# インストール後の確認
$ kubectl get crd
NAME                                         CREATED AT
eniconfigs.crd.k8s.amazonaws.com             2023-01-14T00:26:18Z
externalsecrets.kubernetes-client.io         2023-01-14T00:39:36Z
securitygrouppolicies.vpcresources.k8s.aws   2023-01-14T00:26:22Z

$ kubectl get pods
NAME                                                        READY   STATUS    RESTARTS   AGE
release-name-kubernetes-external-secrets-754cc56b8f-xg2dp   1/1     Running   0          13s

KESインストール後は ExternalSecret リソースに加え、生成されるSecretを扱うDeploymentも作成しておきます。

# ExternalSecretリソースの作成
$ kubectl apply -f externalsecret-kes.yaml
externalsecret.kubernetes-client.io/test-secret created

$ kubectl get externalsecret
NAME          LAST SYNC   STATUS    AGE
test-secret   3s          SUCCESS   12m

$ kubectl get secret
NAME                                                   TYPE                                  DATA   AGE
default-token-6fbtj                                    kubernetes.io/service-account-token   3      44m
release-name-kubernetes-external-secrets-token-wf77j   kubernetes.io/service-account-token   3      31m
test-secret                                            Opaque                                1      30m

$ kubectl get secret test-secret -oyaml
apiVersion: v1
data:
  password: MTIzNA==  # "1234"
kind: Secret
metadata:
  creationTimestamp: "2023-01-14T00:40:16Z"
  name: test-secret
  namespace: default
  ownerReferences:
  - apiVersion: kubernetes-client.io/v1
    controller: true
    kind: ExternalSecret
    name: test-secret
    uid: 3821d90f-02d2-454d-8fba-704efeab81f7
  resourceVersion: "5639"
  uid: 7319187e-49fa-4436-9a6b-c42f6d67bea4
type: Opaque


# 上記Secretを利用するDeploymentの作成
$ kubectl apply -f kes-to-eso-deploy.yaml
deployment.apps/kes-to-eso-deploy created

$ kubectl get pods
NAME                                                        READY   STATUS    RESTARTS   AGE
kes-to-eso-deploy-5cfb75cd85-hrksm                          1/1     Running   0          13s
kes-to-eso-deploy-5cfb75cd85-mxlpl                          1/1     Running   0          13s
release-name-kubernetes-external-secrets-754cc56b8f-6q2gg   1/1     Running   0          30m


$ kubectl exec -it kes-to-eso-deploy-5cfb75cd85-hrksm -- printenv | grep password
password=1234

externalsecret-kes.yaml

apiVersion: kubernetes-client.io/v1
kind: ExternalSecret
metadata:
  name: test-secret
spec:
  backendType: secretsManager
  region: ap-northeast-1
  dataFrom:
    - test-secret

kes-to-eso-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kes-to-eso-deploy
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: kes-to-eso-container
        image: nginx
        env:
        - name: password
          valueFrom:
            secretKeyRef:
              name: test-secret
              key: password

ESO SecretStore ExternalSecret マニフェストファイルを作成する

今回使用したマニフェストファイルは以下の通りです。KESとESOの ExternalSecret は、リソース中で指定するパラメータが異なるため、移行前後で同じSecretの情報を扱うよう修正する必要があります。

※今回は試しませんでしたが、 kes-to-eso ツールでのManual migrationの手順を参照し、 kestoeso generate コマンドを使用すると、KESからESOに変換した SecretStore ExternalSecrets リソースが生成されるので、そちらを使うのもよさそうです。

secretstore-eso.yaml

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: secretstore-eso
spec:
  provider:
    aws:
      service: SecretsManager
      region: ap-northeast-1
      auth:
        secretRef:
          accessKeyIDSecretRef:
            name: awssm-secret
            key: access-key
          secretAccessKeySecretRef:
            name: awssm-secret
            key: secret-access-key

externalsecret-eso.yaml

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: test-secret
spec:
  refreshInterval: 5m
  secretStoreRef:
    name: secretstore-eso
    kind: SecretStore
  target:
    name: test-secret
    creationPolicy: Owner
  data:
  - secretKey: password
    remoteRef:
      key: test-secret
      property: password

※参考:

ESOをKESと同じクラスター上にインストールする

次にESOのインストールを行います。インストールを行う前に、KESとESOのリソースについて比較をしたうえで、ESOのインストールを行いました。

# templateファイルを生成
$ helm repo add external-secrets https://charts.external-secrets.io
$ helm template external-secrets external-secrets/external-secrets --output-dir .

# ESOのインストール
$ kubectl apply -f ./templates/crds/
$ kubectl apply -f ./templates/


# インストール後の確認
$ kubectl get pods
NAME                                                        READY   STATUS    RESTARTS       AGE
external-secrets-66dbbc7b45-xvmnh                           1/1     Running   2              5m59s
external-secrets-cert-controller-6c95b96976-8rzvf           1/1     Running   0              5m59s
external-secrets-webhook-647478f6dc-wkjq6                   1/1     Running   2 (112s ago)   5m59s
kes-to-eso-deploy-5cfb75cd85-hrksm                          1/1     Running   0              9m27s
kes-to-eso-deploy-5cfb75cd85-mxlpl                          1/1     Running   0              9m27s
release-name-kubernetes-external-secrets-754cc56b8f-6q2gg   1/1     Running   0              39m

疑問点: ESOとKESのリソース名は重複しないか

KESとESOをインストールするにはHelmパッケージが用意されています。 helm template コマンドでそれぞれ使用するファイル群を生成すると、以下のようになります。

# KES
$ tree .
.
├── crds
│   └── kubernetes-client.io_externalsecrets_crd.yaml
├── deployment.yaml
├── rbac.yaml
├── service.yaml
└── serviceaccount.yaml

# ESO
$ tree .
.
├── cert-controller-deployment.yaml
├── cert-controller-rbac.yaml
├── cert-controller-serviceaccount.yaml
├── crds
│   ├── acraccesstoken.yaml
│   ├── clusterexternalsecret.yaml
│   ├── clustersecretstore.yaml
│   ├── ecrauthorizationtoken.yaml
│   ├── externalsecret.yaml
│   ├── fake.yaml
│   ├── gcraccesstoken.yaml
│   ├── password.yaml
│   ├── pushsecret.yaml
│   └── secretstore.yaml
├── deployment.yaml
├── rbac.yaml
├── serviceaccount.yaml
├── validatingwebhook.yaml
├── webhook-deployment.yaml
├── webhook-secret.yaml
├── webhook-service.yaml
└── webhook-serviceaccount.yaml

上記のようにESOのほうがKESよりも多くのファイルを使用し、作成されるリソースの数もESOのほうが多いです。

また各リソース名を見てみると、KESにはHelmパッケージ利用時に指定できる release-name という文字列が含まれ、その後ろに kubernetes-external-secret と続きます。

※例: deployment.yaml

# Source: kubernetes-external-secrets/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: release-name-kubernetes-external-secrets
  namespace: "default"
  labels:
    app.kubernetes.io/name: kubernetes-external-secrets
    helm.sh/chart: kubernetes-external-secrets-8.5.5
    app.kubernetes.io/instance: release-name
    app.kubernetes.io/managed-by: Helm

(以降割愛)

一方でESOのほうは release-name のような文字列はなく、KESと比較するとリソース名が重複するものはありませんでした。

※KESとESOのリソース名の比較表

リソースの種別 KESリソース名 ESOリソース名
Deployment release-name-kubernetes-external-secrets external-secrets
external-secrets-cert-controller
external-secrets-webhook
Service release-name-kubernetes-external-secrets external-secrets-webhook
Service Account release-name-kubernetes-external-secrets external-secrets
external-secrets-cert-controller
external-secrets-webhook
Secret external-secrets-webhook
Cluster Role release-name-kubernetes-external-secrets external-secrets-controller
external-secrets-view
external-secrets-edit
external-secrets-cert-controller
Cluster Role Binding release-name-kubernetes-external-secrets external-secrets-controller
release-name-kubernetes-external-secrets-auth external-secrets-cert-controller
Role external-secrets-leaderelection
Role Binding external-secrets-leaderelection
Validating Webhook Configuration secretstore-validate
externalsecret-validate
CRD externalsecrets.kubernetes-client.io externalsecrets.external-secrets.io
secretstores.external-secrets.io

このため、KESとESOを同じクラスター上にインストールする際、デフォルトではリソース名の重複などは気にする必要はなさそうです。ただKESのリソース名を修正している場合はこの限りではないため、必要に応じてESOのリソース名は修正が必要となります。

疑問点: ExternalSecret CRDは共存可能か

KESとESOは ExternalSecret という名称のCRDを使用します。実際にKESとESOを同じクラスター上にインストールすると、この2つのCRDが共存することは確認できます。

$ kubectl get crd
NAME                                                    CREATED AT
acraccesstokens.generators.external-secrets.io          2023-01-14T01:17:26Z
clusterexternalsecrets.external-secrets.io              2023-01-14T01:17:26Z
clustersecretstores.external-secrets.io                 2023-01-14T01:17:26Z
ecrauthorizationtokens.generators.external-secrets.io   2023-01-14T01:17:26Z
eniconfigs.crd.k8s.amazonaws.com                        2023-01-14T00:26:18Z
externalsecrets.external-secrets.io                     2023-01-14T01:17:26Z  # ESO
externalsecrets.kubernetes-client.io                    2023-01-14T00:39:36Z  # KES
fakes.generators.external-secrets.io                    2023-01-14T01:17:27Z
gcraccesstokens.generators.external-secrets.io          2023-01-14T01:17:27Z
passwords.generators.external-secrets.io                2023-01-14T01:17:27Z
pushsecrets.external-secrets.io                         2023-01-14T01:17:27Z
secretstores.external-secrets.io                        2023-01-14T01:17:27Z
securitygrouppolicies.vpcresources.k8s.aws              2023-01-14T00:26:22Z

それぞれの ExternalSecretリソースの定義を見ると、APIが異なっていることがわかります。このため、リソースの名称が同じでも、同時にCRDを作成することが可能となります。

なお、それぞれのリソースの状態を確認するコマンドは微妙に異なっているらしく、KES ExternalSecret リソースを見るには kubectl get externalsecret 、ESO ExternalSecret を確認するには kubectl get externalsecrets コマンドを使用します。

SecretStore/ExternalSecretをデプロイする

続いてSecretStore/ExternalSecretをデプロイします。

# AWSリソースにアクセスするための権限を付与
$ kubectl apply -f awssm-secret.yaml
secret/awssm-secret created


# Secret Storeのデプロイ
$ kubectl apply -f secretstore-eso.yaml
secretstore.external-secrets.io/secretstore-eso created

$ kubectl get secretstore
NAME              AGE   STATUS   CAPABILITIES   READY
secretstore-eso   7s    Valid    ReadWrite      True


# External Secretのデプロイ
$ kubectl apply -f externalsecret-eso.yaml
externalsecret.external-secrets.io/test-secret created

$ kubectl get externalsecrets.external-secrets.io
NAME          STORE             REFRESH INTERVAL   STATUS              READY
test-secret   secretstore-eso   5m                 SecretSyncedError   False

デプロイ後の状態を見ると、ESO ExternalSecret で以下のようなエラーが発生しています。これはKESが指定のSecretのownershipをすでに所有しており、ESOのownershipを追加できないために発生しています。

$ kubectl describe externalsecrets.external-secrets.io test-secret
Name:         test-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  external-secrets.io/v1beta1
Kind:         ExternalSecret
Metadata:

(一部割愛)

Events:
  Type     Reason        Age                From              Message
  ----     ------        ----               ----              -------
  Warning  UpdateFailed  0s (x15 over 83s)  external-secrets  could not set ExternalSecret controller reference: Object default/test-secret is already owned by another ExternalSecret controller test-secret

既存SecretからKESのownershipを削除する

ESO ExternalSecret のエラーを解消するため、Secretリソースの metadata.ownerReferences を修正します。今回はSecretリソース中の metadata.ownerReferences を削除しました。

$ kubectl edit secret test-secret
secret/test-secret edited


# 以下のようにmetadata.ownerReferencesの箇所を削除


# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  password: MTIzNA==
kind: Secret
metadata:
  creationTimestamp: "2023-01-14T00:40:16Z"
  name: test-secret
  namespace: default
  resourceVersion: "5639"
  uid: 7319187e-49fa-4436-9a6b-c42f6d67bea4
type: Opaque

ただし、KESが起動中に上記操作を行っても、KESがSyncすることで再び OwnerReferencesが追加されます

# 上記操作からしばらく後に状態を確認
$ kubectl get externalsecrets.kubernetes-client.io
NAME          LAST SYNC   STATUS    AGE
test-secret   1s          SUCCESS   51m

$ kubectl get externalsecrets.external-secrets.io
NAME          STORE             REFRESH INTERVAL   STATUS              READY
test-secret   secretstore-eso   5m                 SecretSyncedError   False

# ownershipが追加されている
$ kubectl get secret test-secret -oyaml
apiVersion: v1
data:
  password: MTIzNA==
kind: Secret
metadata:
  creationTimestamp: "2023-01-14T00:40:16Z"
  name: test-secret
  namespace: default
  ownerReferences:
  - apiVersion: kubernetes-client.io/v1
    controller: true
    kind: ExternalSecret
    name: test-secret
    uid: 3821d90f-02d2-454d-8fba-704efeab81f7
  resourceVersion: "13635"
  uid: 7319187e-49fa-4436-9a6b-c42f6d67bea4
type: Opaque

これを避けるため、事前にKES Deploymentのレプリカ数をゼロにし、KESからSyncを行わないようにします。

$ kubectl get deploy
NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
external-secrets                           1/1     1            1           25m
external-secrets-cert-controller           1/1     1            1           25m
external-secrets-webhook                   1/1     1            1           25m
kes-to-eso-deploy                          2/2     2            2           29m
release-name-kubernetes-external-secrets   1/1     1            1           59m

# KESのレプリカ数をゼロに
$ kubectl scale deploy --replicas=0 release-name-kubernetes-external-secrets
deployment.apps/release-name-kubernetes-external-secrets scaled

$ kubectl get deploy
NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
external-secrets                           1/1     1            1           26m
external-secrets-cert-controller           1/1     1            1           26m
external-secrets-webhook                   1/1     1            1           26m
kes-to-eso-deploy                          2/2     2            2           30m
release-name-kubernetes-external-secrets   0/0     0            0           60m

再びSecretのownershipを修正します。これでしばらくすると、Secretリソースが更新され、ESOがOwnershipを持つようになります。ExternalSecretに発生していたエラーも解消されることが確認できます。

# Secretからmetadata.ownerReferencesを削除
$ kubectl edit secret test-secret
secret/test-secret edited


# Secretを修正してからしばらく後
$ kubectl get externalsecrets.external-secrets.io
NAME          STORE             REFRESH INTERVAL   STATUS         READY
test-secret   secretstore-eso   5m                 SecretSynced   True


$ kubectl describe externalsecrets.external-secrets.io test-secret
Name:         test-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  external-secrets.io/v1beta1
Kind:         ExternalSecret
Metadata:

(一部割愛)

Events:
  Type     Reason        Age                   From              Message
  ----     ------        ----                  ----              -------
  Warning  UpdateFailed  6m33s (x33 over 17m)  external-secrets  could not set ExternalSecret controller reference: Object default/test-secret is already owned by another ExternalSecret controller test-secret
  Normal   Updated       65s (x3 over 12m)     external-secrets  Updated Secret


# SecretにはESOのownershipが記載されている
$ kubectl get secret test-secret -oyaml
apiVersion: v1
data:
  password: MTIzNA==
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"external-secrets.io/v1beta1","kind":"ExternalSecret","metadata":{"annotations":{},"name":"test-secret","namespace":"default"},"spec":{"data":[{"remoteRef":{"key":"test-secret","property":"password"},"secretKey":"password"}],"refreshInterval":"5m","secretStoreRef":{"kind":"SecretStore","name":"secretstore-eso"},"target":{"creationPolicy":"Owner","name":"test-secret"}}}
    reconcile.external-secrets.io/data-hash: aeb62059e67d377d0a0ff6afda1a82cf
  creationTimestamp: "2023-01-14T00:40:16Z"
  name: test-secret
  namespace: default
  ownerReferences:
  - apiVersion: external-secrets.io/v1beta1
    blockOwnerDeletion: true
    controller: true
    kind: ExternalSecret
    name: test-secret
    uid: 714a3d12-8869-4033-ad55-588e5789eabe
  resourceVersion: "15809"
  uid: 7319187e-49fa-4436-9a6b-c42f6d67bea4
type: Opaque

ただし、ここで再度KESのレプリカ数を1に戻すと、今度はSecretリソースのownershipがKESに上書きされてしまうので、注意してください。

疑問点: ESOの creationPolicy: Merge は利用できるか

ESOは ExternalSecret リソースのパラメータで、Secretリソース作成時のポリシーを指定できます。このうち Merge を選択すると、Secretの新規作成は行わず、既存のSecretに値を追加する形での更新が可能となります。

当初、creationPolicy: Merge を利用すれば、KESとESOとが同じSecretリソースを管理する状態を実現できるのではないかと考えたのですが、ESOがデータを追加するのは異なるデータが存在する場合とのことだったので、残念ながら同じデータを参照している場合は利用できませんでした。

※参考: External Secrets Operator Doc - Lifecycle

creationPolicy: Merge の検証ログ

# ExternalSecretリソースを以下のように修正
$ cat externalsecret-eso.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: test-secret
spec:
  refreshInterval: 5m
  secretStoreRef:
    name: secretstore-eso
    kind: SecretStore
  target:
    name: test-secret
    #creationPolicy: Owner
    creationPolicy: Merge
  data:
  - secretKey: password
    remoteRef:
      key: test-secret
      property: password


$ kubectl apply -f externalsecret-eso.yaml
externalsecret.external-secrets.io/test-secret configured


# ExternalSecretのStatusはSyncできたと表示される
$ kubectl get externalsecrets.external-secrets.io
NAME          STORE             REFRESH INTERVAL   STATUS         READY
test-secret   secretstore-eso   5m                 SecretSynced   True


# metadata.ownerReferencesは更新されない
$ kubectl get secret test-secret -oyaml
apiVersion: v1
data:
  password: MTIzNA==
kind: Secret
metadata:
  creationTimestamp: "2023-01-14T00:40:16Z"
  name: test-secret
  namespace: default
  ownerReferences:
  - apiVersion: kubernetes-client.io/v1
    controller: true
    kind: ExternalSecret
    name: test-secret
    uid: 3821d90f-02d2-454d-8fba-704efeab81f7
  resourceVersion: "17653"
  uid: 7319187e-49fa-4436-9a6b-c42f6d67bea4
type: Opaque

KES関連リソースを削除する

最後にKES関連のリソースを削除します。

$ kubectl delete -f ./testdir/kubernetes-external-secrets/templates/
$ kubectl delete -f ./charts/kubernetes-external-secrets/crds

削除後にESOの状態などを確認しますが、特に問題は発生していないように見えます。

KES削除後の状態確認ログ

$ kubectl get crd
NAME                                                    CREATED AT
acraccesstokens.generators.external-secrets.io          2023-01-14T01:17:26Z
clusterexternalsecrets.external-secrets.io              2023-01-14T01:17:26Z
clustersecretstores.external-secrets.io                 2023-01-14T01:17:26Z
ecrauthorizationtokens.generators.external-secrets.io   2023-01-14T01:17:26Z
eniconfigs.crd.k8s.amazonaws.com                        2023-01-14T00:26:18Z
externalsecrets.external-secrets.io                     2023-01-14T01:17:26Z
fakes.generators.external-secrets.io                    2023-01-14T01:17:27Z
gcraccesstokens.generators.external-secrets.io          2023-01-14T01:17:27Z
passwords.generators.external-secrets.io                2023-01-14T01:17:27Z
pushsecrets.external-secrets.io                         2023-01-14T01:17:27Z
secretstores.external-secrets.io                        2023-01-14T01:17:27Z
securitygrouppolicies.vpcresources.k8s.aws              2023-01-14T00:26:22Z


$ kubectl get deploy
NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
external-secrets                   1/1     1            1           53m
external-secrets-cert-controller   1/1     1            1           53m
external-secrets-webhook           1/1     1            1           53m
kes-to-eso-deploy                  2/2     2            2           56m

$ kubectl get pods
NAME                                                READY   STATUS    RESTARTS      AGE
external-secrets-66dbbc7b45-xvmnh                   1/1     Running   2             53m
external-secrets-cert-controller-6c95b96976-8rzvf   1/1     Running   0             53m
external-secrets-webhook-647478f6dc-wkjq6           1/1     Running   2 (49m ago)   53m
kes-to-eso-deploy-5cfb75cd85-hrksm                  1/1     Running   0             57m
kes-to-eso-deploy-5cfb75cd85-mxlpl                  1/1     Running   0             57m

$ kubectl get externalsecret
Error from server (NotFound): Unable to list "kubernetes-client.io/v1, Resource=externalsecrets": the server could not find the requested resource (get externalsecrets.kubernetes-client.io)

$ kubectl get externalsecrets
NAME                                             STORE             REFRESH INTERVAL   STATUS         READY
externalsecret.external-secrets.io/test-secret   secretstore-eso   5m                 SecretSynced   True

NAME                                              AGE   STATUS   CAPABILITIES   READY
secretstore.external-secrets.io/secretstore-eso   42m   Valid    ReadWrite      True

$ kubectl get secret
NAME                                           TYPE                                  DATA   AGE
awssm-secret                                   Opaque                                2      45m
default-token-6fbtj                            kubernetes.io/service-account-token   3      104m
external-secrets-cert-controller-token-nlt7d   kubernetes.io/service-account-token   3      57m
external-secrets-token-nltx6                   kubernetes.io/service-account-token   3      57m
external-secrets-webhook                       Opaque                                4      57m
external-secrets-webhook-token-kkx8s           kubernetes.io/service-account-token   3      57m
test-secret                                    Opaque                                1      90m


$ kubectl get secret test-secret -oyaml
apiVersion: v1
data:
  password: MTIzNA==
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"external-secrets.io/v1beta1","kind":"ExternalSecret","metadata":{"annotations":{},"name":"test-secret","namespace":"default"},"spec":{"data":[{"remoteRef":{"key":"test-secret","property":"password"},"secretKey":"password"}],"refreshInterval":"5m","secretStoreRef":{"kind":"SecretStore","name":"secretstore-eso"},"target":{"creationPolicy":"Owner","name":"test-secret"}}}
    reconcile.external-secrets.io/data-hash: aeb62059e67d377d0a0ff6afda1a82cf
  creationTimestamp: "2023-01-14T00:40:16Z"
  name: test-secret
  namespace: default
  ownerReferences:
  - apiVersion: external-secrets.io/v1beta1
    blockOwnerDeletion: true
    controller: true
    kind: ExternalSecret
    name: test-secret
    uid: 714a3d12-8869-4033-ad55-588e5789eabe
  resourceVersion: "20305"
  uid: 7319187e-49fa-4436-9a6b-c42f6d67bea4
type: Opaque

その他

別名のSecretを使う場合

今回はSecret名を同じと仮定しましたが、そもそもKESとESOで異なる名称のSecretを管理するようにすることも考えられます。

管理するSecret名を変更する場合は、今回発生したownershipの問題は発生せず、KESからESOへの切り替え自体はよりスムーズに実施できるはずです。冒頭に紹介した本番環境での例でも、別名のSecretに切り替える方法が紹介されています。

こちらの場合、ownershipの書き換えをする必要がない代わりに、Secretを利用するリソース側に変更が必要となります。具体的にはDeploymntなどが使用するSecret情報を更新する必要があります。

IRSAを使う場合

今回のAWSアカウントへのアクセス権限付与の方法は、KES・ESOともにセキュアとは言えない方法で行っており、本来はIRSAを使用することが推奨されます。

KES/ESOでIRSAを使用する方法は少し異なります。KESはExternal SecretコントローラーPodにIAM権限を付与したService Accountを紐づける必要があります。一方でESOはコントローラーに付与することもできますが、SecretStore ごとにService Accountを指定することもできます。

このため、KESで使用していたのと同じService Accountを SecretStore に指定したり、新しいService Accountを用意することもできます。