Sealed SecretsでGCPのサービスアカウントキーを扱う

# 背景
- [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets)を利用している環境でGCPのサービスアカウントキーSecretリソースとして扱う方法について記載する
- KubernetesでのGCP認証は[Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity?hl=ja)を使用することが推奨されている
    - Workload Identityを使用すればSecretリソースを払い出す必要がない
    - しかし、オンプレのKubernetes環境など、Workload Identityが使用できない場合もある

# Sealed Secretsとは
- Bitnamiが開発しているOSS
- Sealed SecretsをKubernetesクラスタにデプロイすることで、クラスタ内に公開鍵と秘密鍵が作成される
    - 開発者は公開鍵で機密情報を暗号化した文字列をSealed Secretリソースとしてデプロイする(クラスタで保持している秘密鍵でした複合できないためGithubなどのリポジトリで管理できる)
    - Sealed SecretリソースがデプロイされるとSealed Secrets Controllerが秘密鍵で複合し、クラスタ内にSecretリソースが払い出される
- 合わせてkubesealというコマンドラインツールも提供されており、SecretリソースからSealed Secretリソースを生成する際に使用する

# 環境
- macOS Big Sur 11.4
- Kubernetes 1.21.3 (Docker Desktop)
- Sealed Secrets [CHART:sealed-secrets-1.16.1, APP:v0.16.0]
- kubeseal v0.16.0

# 事前準備
## Sealed Secretsのinstall(Helmを使用)
```
$ helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
$ helm install --namespace kube-system my-release sealed-secrets/sealed-secrets 
```

- installすると以下のようにSealed SecretのControllerがデプロイされる

```
$ kubectl get pod
NAME                                        READY   STATUS    RESTARTS   AGE
my-release-sealed-secrets-dd998d6cd-bvdld   1/1     Running   0          2m13s
```

## kubesealのinstall
- brewでkubesealをインストールする

```
$ brew install kubeseal
```

## サービスアカウントと鍵の作成

- GCPのコンソールからサービスアカウントの鍵(json)をダウンロードする
    - [サービス アカウントの認証情報を作成する
](https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform?hl=ja#step_3_create_service_account_credentials)

# サービスアカウントの鍵をSealedSecretsとして扱う
- ダウンロードしたjsonを基にSecretリソースを作成
   -  PATH-TO-KEY-FILE.jsonをダウンロードされたパスに変更する
 
```
$ kubectl create secret generic sample-key --from-file=key.json=PATH-TO-KEY-FILE.json
secret/sample-key created
```

- kubesealでSealedSecretリソースを払い出すためにはmanifest形式でSecretの情報が必要になる
- そのため、`$ kubectl edit secret sample-key`で先程作成したsecretの情報を表示し、それを以下のようにyamlファイルとして保存する

```secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: sample-key
  namespace: kube-system
type: Opaque
data:
  key.json: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

- Secretリソースは不要なので削除する

```
$ kubectl delete secret sample-key
secret "sample-key" deleted
```

- このSecretリソースの内容を基に、kubesealからSealedSecretリソースを作成する
    - `controller-name` はHelmで作成されたDeploymentの名前に対応させる
    - 基になるSecretファイルは<>で指定し、出力するファイル名をその後に指定する

```
$ kubeseal --format=yaml --controller-name my-release-sealed-secrets <secrets.yaml> sealedsecret.yaml
```

- 以下のようなファイルが作成される(クラスタ内に保存されている鍵でしかdecryptできない)

```sealedsecret.yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: sample-key
  namespace: kube-system
spec:
  encryptedData:
    key.json: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  template:
    data: null
    metadata:
      creationTimestamp: null
      name: sample-key
      namespace: kube-system
    type: Opaque
```

- このファイルをapplyすればSealedSecretリソースが作成される

```
$ kubectl apply -f sealedsecret.yaml                                             
sealedsecret.bitnami.com/sample-key created
```

- これを基にSecretリソースが払い出されているのが確認できればOK

```
$ kubectl get secret
NAME               TYPE              DATA   AGE
sample-key         Opaque            1      30s
```

- あとは一般的な方法でPodからこのSecretを読み取らせる
    - [Secretの使用 ](https://kubernetes.io/ja/docs/concepts/configuration/secret/#secret%E3%81%AE%E4%BD%BF%E7%94%A8)

# 参考
- https://github.com/bitnami-labs/sealed-secrets
- [Sealed Secretsを利用したKubernetes Secretリソースのセキュアな管理](https://tech.uzabase.com/entry/2020/03/10/171733)