Kubernetes で Pod が使用できる Secret を制限する方法

## Pod が使用できる Secret を制限する方法

Kubrenetes では、ServiceAccount リソースに [kubernetes.io/enforce-mountable-secrets](https://kubernetes.io/docs/reference/labels-annotations-taints/#enforce-mountable-secrets) アノテーションを true で設定することで、その ServiceAccount で実行する Pod が [secrets](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#serviceaccount-v1-core) フィールドで指定された同一 Namespace の Secret しか使用できない (マウントできない) ように制限する機能 [^1] が提供されています。

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-sa
  annotations:
    kubernetes.io/enforce-mountable-secrets: "true"
secrets:
  - name: mountable-secret-1
  - name: mountable-secret-2
  - name: mountable-secret-3
```

## 動作検証

検証環境は v1.27.2 です。

まずは `mountable-secret` と `unmountable-secret` という Secret を作成します。

```yaml
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: v1
kind: Secret
metadata:
  name: mountable-secret
  namespace: test
stringData:
  foo: mountable
---
apiVersion: v1
kind: Secret
metadata:
  name: unmountable-secret
  namespace: test
stringData:
  bar: unmountable
```

次に、`mountable-secret` のみが使用できる ServiceAccount を作成します。この際に `kubernetes.io/enforce-mountable-secrets` アノテーションが true で設定されていないと Secret 制限が機能しないことに注意してください。

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-sa
  namespace: test
  annotations:
    kubernetes.io/enforce-mountable-secrets: "true"
secrets:
  - name: mountable-secret
```

`mountable-secret` は Mountable secrets として登録されます。

```bash
$ kubectl -n test describe sa test-sa 
Name:                test-sa
Namespace:           test
Labels:              <none>
Annotations:         kubernetes.io/enforce-mountable-secrets: true
Image pull secrets:  <none>
Mountable secrets:   mountable-secret
Tokens:              <none>
Events:              <none>
```

次に、その ServiceAccount で `mountable-secret` をマウントした Pod を作成します。

```yaml:mountable-secret-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mountable-secret-pod
  namespace: test
spec:
  containers:
  - name: busybox
    image: busybox:1.36.1
    command: ["sleep", "infinity"]
    volumeMounts:
    - name: mountable-secret
      mountPath: "/etc/mountable-secret"
  serviceAccountName: test-sa
  volumes:
  - name: mountable-secret
    secret:
      secretName: mountable-secret # 使用が許可されたシークレット
```

この ServiceAccount では `mountable-secret` の使用が許可されているので、Pod は問題なく Apply できました。

```bash
$ kubectl apply -f mountable-secret-pod.yaml
pod/mountable-secret-pod created

$ kubectl -n test  exec mountable-secret-pod -- cat /etc/mountable-secret/foo
mountable
```

今度は ServiceAccount で使用が許可されていない `unmountable-secret` をマウントした Pod を作成します。

```yaml:unmountable-secret-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: unmountable-secret-pod
  namespace: test
spec:
  containers:
  - name: busybox
    image: busybox:1.36.1
    command: ["sleep", "infinity"]
    volumeMounts:
    - name: unmountable-secret
      mountPath: "/etc/unmountable-secret"
  serviceAccountName: test-sa
  volumes:
  - name: unmountable-secret
    secret:
      secretName: unmountable-secret # 使用が許可されていないシークレット
```

想定通り、使用が許可されていないため Pod の Apply が失敗しました。

```bash
$ kubectl apply -f unmountable-secret-pod.yaml
Error from server (Forbidden): error when creating "/Users/ryysud/Desktop/manifest.yaml": pods "unmountable-secret-pod" is forbidden: volume with secret.secretName="unmountable-secret" is not allowed because service account test-sa does not reference that secret
```

これで動作検証は完了です。

この機能を利用したい方は、ご自身の環境でも試してもらえればと思います。

[^1]: この機能を利用するには [ServiceAccount Admission Plugin](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#serviceaccount) が有効である必要があります (デフォルト有効)