Kubernetesのシークレット管理方法とVaultとの統合方法について整理

# 本記事の目的

* Kubernetesのシークレット管理方法をまとめる
* Vaultを利用する場合のKubernetes(以降K8s)との統合方法をまとめる

# 出発点の課題 → 安全に Secret リソースを Kubernetes 上にデプロイするために「シークレット管理」が必要

K8sのSecretリソースを普通にManifestで管理しようとするとBase64でエンコードされただけの秘匿データもGitに含まれてしまう。

# OSSの「シークレット管理」の仕組み

OSSとして以下のようなシークレット管理の仕組みが公開されている。

1. [External Secrets Operator](https://external-secrets.io/v0.8.1/introduction/overview/)
2. [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html)
3. [Sealed Secrets](https://sealed-secrets.netlify.app/)

## 1. [External Secrets Operator](https://external-secrets.io/v0.8.1/introduction/overview/) について

#### 概要

AWS Secrets Manager や HashiCorp Vault などのexternal secret管理システムからデータを取得しK8s Secretリソースに入れ込む動きをする。

#### 仕組み

K8sの[カスタムリソース](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)によって専用のリソースとして提供される。
リソースは、`kind=ExternalSecret`は`kind=SecretStore`の2つがある。
2つの役割はそれぞれ`ExternalSecret`は何をフェッチするか、`SecretStore`はどうやってアクセスするか、を指定するという分担になっている。

#### GitHub

https://github.com/external-secrets/external-secrets/

#### 図[^1]

[^1]: https://external-secrets.io/v0.8.1/introduction/overview/

![image](https://external-secrets.io/v0.8.1/pictures/diagrams-resource-mapping.png)

## 2. [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/concepts.html) について

#### 概要

Secretデータを保存するVolumeとそのVolumeへアクセスするインターフェースを提供する。AWS Secrets Manager や HashiCorp Vault などのexternal secret管理システムはそれぞれSecrets Store CSI Driverのインターフェースを利用するProviderを提供している。Volumeへ入ったデータはK8sクライアントがマウントすることで利用される。

#### 仕組み

K8sのカスタムリソースとしてSecrets Store CSI DriverのVolume用Podとインターフェースは提供されている。

#### GitHub

  * [Secrets Store CSI Driver](https://github.com/kubernetes-sigs/secrets-store-csi-driver)
  * [Vault CSI Provider](https://github.com/hashicorp/vault-csi-provider)
  * [AWS CSI Provider](https://github.com/aws/secrets-store-csi-driver-provider-aws)

#### 図[^2]

[^2]: https://secrets-store-csi-driver.sigs.k8s.io/concepts.html

![image](https://secrets-store-csi-driver.sigs.k8s.io/images/diagram.png)

## 3. [Sealed Secrets](https://sealed-secrets.netlify.app/) について

#### 概要

Gitで管理するK8sのSecretリソースを公開鍵で暗号化する。秘密鍵を持ったK8sコントローラーのみが複合化でき実際のSecretリソースへ入れる。

#### 仕組み

K8sのカスタムリソースとして`kind: SealedSecret`というリソースで暗号化してGit管理する。helmを使い専用のK8sコントローラーを動作させることで複合化しSecretリソースに入れるようになる。

#### GitHub

https://github.com/bitnami-labs/sealed-secrets

#### ref: 

https://aws.amazon.com/blogs/opensource/managing-secrets-deployment-in-kubernetes-using-sealed-secrets/

#### 図[^3]

[^3]: https://aws.amazon.com/blogs/opensource/managing-secrets-deployment-in-kubernetes-using-sealed-secrets/

![image](https://d2908q01vomqb2.cloudfront.net/ca3512f4dfa95a03169c5a670a4c91a19b3077b4/2020/04/10/Screen-Shot-2020-04-09-at-8.06.32-PM.png)

# VaultをK8sのExternal Secret管理システムとして利用するための実現方法3パターン

2023年4月の以下のVault公式記事で以下の3パターンの実装方法がK8sとVaultの統合にあると示された。

https://www.hashicorp.com/blog/kubernetes-vault-integration-via-sidecar-agent-injector-vs-csi-provider

1. The Vault Sidecar Agent Injector
2. The Vault Container Storage Interface (CSI) provider
3. The Vault Secrets Operator

記事ではそれぞれの比較について書かれている。結論の表だけ拝借すると以下とのこと[^4]

[^4]: https://www.hashicorp.com/blog/kubernetes-vault-integration-via-sidecar-agent-injector-vs-csi-provider

![image](https://www.hashicorp.com/_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F2885%2F1680644640-csi-vs-sidecar-vs-operator-chart.png&w=3840&q=75)

## 1. Sidecar Agent Injector について

概要図が以下になる[^4]

![image](https://www.hashicorp.com/_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F2885%2F1643214443-sidecar-workflow-v1.png&w=3840&q=75)

### 詳細なK8sとVaultとの全体シーケンス

Sider Agent InjectorによってVault AgentがサイドカーとしてPodに入るケースの全体シーケンス図として以下の図が理解しやすい[^5]

[^5]: https://developer.hashicorp.com/vault/tutorials/kubernetes/agent-kubernetes#start-vault-agent-with-auto-auth
  
![image](https://content.hashicorp.com/api/assets?product=tutorials&version=main&asset=public%2Fimg%2Fvault%2Fdiagram-kubernetes_auth-workflow.png)

上図のシーケンスの各ステップの詳細をまとめると以下になる。

* 1st Phase: Vaultへ[K8s認証Method](https://developer.hashicorp.com/vault/docs/auth/kubernetes)のConfigurationを設定する
  * Step1: K8s Pub CA Certを登録する
    * これは2nd PhaseでのStep2でのVaultがK8s APIを叩く"TokenReview API Called"にて使うK8sサーバ側の証明書である。
  * Step2: ロール設定
    * K8s認証メソッド設定におけるK8sクライアントのService AccountとNamespaceを設定する。
  * Step3: ポリシー設定
    * Step2で設定したロールに対して設定するVaultポリシー
* 2nd Phase: Podをデプロイするとき、Vaultのトークンを取得する
  * Step1: K8sクライアントのService AccountのJWTをVaultへ渡す
  * Step2-3: Vaultが渡されたJWTを引数に __K8sコントローラーの[TokenReview API](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-review-v1/)を呼び__ 、データを受け取る。
  * Step4: K8sコントローラーから渡された情報と1st Phaseで設定していたロール・ポリシー情報とで検証する。
  * Step5: 認証OKならばK8sクライアントへVaultトークンを渡す。
* 3rd Phase: Vualtトークンを使ってK8sクライアントがVaultから必要なデータを取得する。

### Vault Agent がやること

【実現したいこと】VaultのトークンのライフサイクルをK8sクライアントが専用ロジックを実装すること無く管理したい。

【ソリューション】[Vault Agent](https://developer.hashicorp.com/vault/docs/agent#example-configuration) というデーモンを立てることでロジックを吸収させる。

> Vault Agent is a client daemon that provides the following features:
> * Auto-Auth - Automatically authenticate to Vault and manage the token renewal process for locally-retrieved dynamic secrets.
> * API Proxy - Allows Vault Agent to act as a proxy for Vault's API, optionally using (or forcing the use of) the Auto-Auth token.
> * Caching - Allows client-side caching of responses containing newly created tokens and responses containing leased secrets generated off of these newly created tokens. The agent also manages the renewals of the cached tokens and leases.
> * Windows Service - Allows running the Vault Agent as a Windows service.
> * Templating - Allows rendering of user-supplied templates by Vault Agent, using the token generated by the Auto-Auth step.

### vault-k8s がやること

【実現したいこと】Vault AgentをサイドカーとしてK8sクライアントのPodに注入する仕組みを持ちたい。

【ソリューション】[Agent Sidecar Injector](https://developer.hashicorp.com/vault/docs/platform/k8s/injector) のリソースをK8sに持たせ、 [Kubernetes Mutation Webhook Controller](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/)のK8sの機能を利用することでInjectionを実現する。実装は [vault-k8s](https://github.com/hashicorp/vault-k8s) である。

【仕組み概要】

> The Vault Agent Injector works by intercepting pod CREATE and UPDATE events in Kubernetes. The controller parses the event and looks for the metadata annotation vault.hashicorp.com/agent-inject: true. If found, the controller will alter the pod specification based on other annotations present.

また、K8sクライアントManifestのAnnotationでのSecretデータ取得指定は以下のように特殊な記述方法になるので留意が必要。

```
vault.hashicorp.com/agent-inject-secret-<unique-name>: /path/to/secret
```

## 2. Container Storage Interface (CSI) provider について

上述の[Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/)のVault側のProvider実装である。

GitHub: https://github.com/hashicorp/vault-csi-provider

概要図は以下[^4]

![image](https://www.hashicorp.com/_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F2885%2F1643214470-csi-workflow-v1.png&w=3840&q=75)

## 3. Secrets Operator について

上述の[External Secrets Operator](https://external-secrets.io/v0.8.1/introduction/overview/)とは別の実装としてVault側が専用のOperatorとして提供しているもの、(のように見える)。

GitHub: https://github.com/hashicorp/vault-secrets-operator/