[調査] K8SのSecretの内容が環境変数展開されるならばConfigMapと同じでは？

:::note warn
2024/12/06追加
本記事はsecretのtypeがopaqueであることについて限定して記述しています🙇
他のtypeについては適宜、公式ドキュメントを参考にしていただけると幸いです。
:::


# TL;DR

- 暗号方式や保管場所について、SecretとConfigMapに違いはない
    - etcdに保存され、両方とも暗号化することができる
    - RBACの制限もかけられる
- SecretやConfigMapの値を参照するPodにアクセスできる人を制限することができる
- RBACを管理しやすくするために、ConfigMapとSecretが分かれていると考えられる


# 初めに

「シークレットの値は環境変数に入れましょう！」

というのは、よく言われることですが、環境変数に入れてしまうということはそのDeploymentsやPodsが動いているホストにログインできる人はその値を見ることができてしまいます。

特に、`SecretKeyRef`を使うことでSecretの値を環境変数に入れることができますが、これはSecretの中で隠れていたものを見えるようにしてしまうことと同じであるため、
結局ConfigMapと変わらないのではと感じることがあります。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">secretkeyrefって変じゃね？<br><br>secretで頑張って隠してたものを、大っぴらに環境変数で展開してるのに、configmapと同等扱いされてない訳で…</p>&mdash; Nozomi (@NozomiMaki2) <a href="https://twitter.com/NozomiMaki2/status/1860331349980381267?ref_src=twsrc%5Etfw">November 23, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

そこで、今回は上記の問題が本当かどうか、どれだけのリスクがあるのかを公式ドキュメントをもとに調査をしてみました。

# Podから環境変数は見れるのか確認

まずは、Podから環境変数を見ることができるのかを確認してみました（詳細：[makinzm/hajimeteno-terraform-with-secret](https://github.com/makinzm/hajimeteno-terraform-with-secret/tree/main)　）。

secretKeyRefやConfigMapKeyRefを使って環境変数を設定した場合([該当コード](https://github.com/makinzm/hajimeteno-terraform-with-secret/blob/b0176a417df17b5bff4cdf92d3ff35db57fa3cdc/main.tf#L48-L86))、Podから環境変数を見ることができます。

`CONFIG_***`がConfigMapから展開された環境変数で、`SECRET_***`がSecretから展開された環境変数です。

```bash
> sh -c env

SECRET_PASSWORD=password
CONFIG_PASSWORD=myPassword
SECRET_USERNAME=user
CONFIG_USERNAME=myUser
```

こうなるとConfigMapとSecretは同じように見えます。

# ConfigMap vs Secret

## 公式ドキュメントでConfigMapとSecretの違いを確認

公式ドキュメントを確認してみると、以下のように記載されていました。

> Secrets are similar to ConfigMaps but are specifically intended to hold confidential data.
[Secrets | Kubernetes](https://kubernetes.io/docs/concepts/configuration/secret/)　より引用

ただ、この記載だけではSecretとConfigMapの違いがよくわかりません。
内部ロジックがどう違うのでしょうか。

なんの驚異からデータを守るためにSecretとConfigMapはわかれているのでしょうか。

## kubectlで確認

ConfigMapとSecretを表示してみると以下のような形になっています。

まず、ConfigMapを表示してみます。

```bash
kubectl describe configmap my-config -n secret-test
```

```bash
Name:         my-config
Namespace:    secret-test
Labels:       <none>
Annotations:  <none>

Data
====
password:
----
myPassword
username:
----
myUser

BinaryData
====

Events:  <none>
```

次に、Secretを表示してみます。

```bash
kubectl describe secret my-secret -n secret-test
```

```bash
Name:         my-secret
Namespace:    secret-test
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  8 bytes
user:      4 bytes
```

これを見ると、Secretについては値が表示されていない違いがあります。

## 保存場所

Secretはデフォルトではetcdに保存されます。

> By default, Secret objects are stored unencrypted in etcd. 
> [Good practices for Kubernetes Secrets | Kubernetes](https://kubernetes.io/docs/concepts/security/secrets-good-practices/) より

ConfigMapも同じくetcdに保存されるようです(公式ドキュメントに記載はありませんでしたが、[Cluster Architecture | Kubernetes](https://kubernetes.io/docs/concepts/architecture/#etcd)や[kubernetes - Where does ConfigMap data gets stored? - Stack Overflow](https://stackoverflow.com/questions/53935597/where-does-configmap-data-gets-stored)を参考にしています)。

そのため、SecretとConfigMapの保存場所は同じであるため、SecretとConfigMapの違いは保存場所にはないと考えられます。

## 保管方法

Secretはデフォルトでは、暗号化されていません。

> Kubernetes Secrets are, by default, stored unencrypted in the API server's underlying data store (etcd). 
> [Secrets | Kubernetes](https://kubernetes.io/docs/concepts/configuration/secret/) より

ただ、[Encrypting Confidential Data at Rest | Kubernetes](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)に記載の方法で、
クラスター全体でSecretを暗号化することができます（ただし、namespaceごとではなくクラスター全体での設定になることに注意してください）。

しかし、上記の設定値の`resources`に`configmaps`も含めることができるため、ConfigMapも暗号化することができるようです。


## 結局同じ？

私の調べた限りでは、kubectlでの表示のされ方以外については、SecretとConfigMapの違いはないように感じました。 

一方で、KubernetesのResourceの区切りとして、SecretとConfigMapが分かれていることは、Kubernetesの利用者にとって使いやすいと感じました。

例えば、一律でRBACに指定できるresourceが一つだけだと、不便であることもあるように伺えます。
そのため、SecretとConfigMapが分かれているのは、Kubernetesの利用者が使いやすいように設計されているように思えました。

適宜、公式から出ているベストプラクティスを参考にしてください。
[Good practices for Kubernetes Secrets | Kubernetes](https://kubernetes.io/docs/concepts/security/secrets-good-practices/)

# Podにアクセスできることの驚異

[Encrypting Confidential Data at Rest | Kubernetes](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) から、
ConfigMapやSecretの内容はetcd内では、暗号化できることを確認しましたが、結局Podにアクセスできる人はその値を見ることができてしまいます。

ここの驚異に対しては、どのような対策があるのでしょうか。

これに対しては、先程のRBACの設定と同様に設定することができます。

> resources: ["pods"]
> [Using RBAC Authorization | Kubernetes](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-example)

Kubernetesで設定できるリソースは下記のページから見れますが、Secretと同様にPodに対しても制御を加えることができます。

- [リソースタイプ < コマンドラインツール(kubectl) | Kubernetes](https://kubernetes.io/ja/docs/reference/kubectl/?utm_source=chatgpt.com#resource-types)

よって、Podにアクセスできる人を制限することで、SecretやConfigMapの値を見ることを防ぐことができます。

ただ、`EncryptionConfiguration` は key-value storeの暗号化にしか対応していないことに注意してください。

> you can encrypt Secret objects, including the key-value data they contain.
> [Encrypting Confidential Data at Rest | Kubernetes](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) より

# 余談 ~ etcdの暗号化は必要か？ ~

etcdに保管する内容は暗号化する必要はあるのでしょうか？
というのも、そもそもk8sのクラスターにアクセスできる人だけがetcdにアクセスできるため、入られてしまったらもう手遅れなのではないかと思えるからです。

現状の調べをもとにセキュリティを頑丈にしても、etcdのアクセスについては、RBACと暗号化の両方ですが、PodはRBACのみです。
もし、Podの環境変数としてSecretの値が展開されている場合は、Podにアクセスされるとetcdの暗号化はほとんど意味がなくなってしまいます。

一方で、セキュリティのレイヤーは増やすことは悪いことではなく、その意味でetcdの暗号化は有用です。

> You can enable etcd encryption for your cluster to provide an additional layer of data security.
> [Encrypting etcd data | Security and compliance | OpenShift Container Platform 4.9](https://docs.openshift.com/container-platform/4.9/security/encrypting-etcd.html#:~:text=You%20can%20enable%20etcd%20encryption,exposed%20to%20the%20incorrect%20parties.)　より

> Each layer adds another layer of security, so the more layers you have, the more difficult it will be for hackers to infiltrate your network. 
> [Why it is important to use multi-layered security | LinkedIn | EmpowerIT.ca](https://www.linkedin.com/pulse/why-important-use-multi-layered-security-empowerit-ca/) より

また、ここでは考慮しきれていない未知の脆弱性があるかもしれないため、セキュリティのレイヤーを増やすことが重要です。

無知の知を大切に、なるべく多くのセキュリティ対策を取ることが重要だと感じました。

# 注意書き

記事についてはすべて、2024/12/01時点にアクセスした内容です。