【入門編】 KubernetesにおけるSecretsの平文保存リスクと暗号化 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!インフラやアプリの開発に日々奮闘されている皆さん、Kubernetes(K8s)使っていますか?

コンテナを上手にまとめて管理してくれるKubernetesは、現代の開発現場ではなくてはならない存在ですよね。「デプロイがすごく楽になった!」「スケールも自動でやってくれて最高!」と感じている方も多いはずです。

さて、そんなKubernetesでアプリを動かすとき、必ずと言っていいほど直面するのが「機密情報(Secrets)の管理」という問題です。パスワードやデータベースの接続文字列、APIの秘密鍵など、絶対に外に漏らしてはいけない大切なデータ、皆さんどうやって扱っていますか?

今回は、このKubernetesのSecrets管理に潜むちょっと怖い「落とし穴」と、それをピシャリと防ぐための対策について、身近な防犯の例えを交えながら優しく紐解いていきたいと思います。一歩ずつ一緒に学んでいきましょう!

—

1. 家の鍵を「透明なアクリルケース」に入れて置いていませんか?

まずは、私たちの身近な防犯のたとえからお話しさせてくださいね。

皆さんが大切なお家の鍵や、通帳、へそくりをしまっておくとき、どんな場所に置くでしょうか? 普通は、頑丈な金庫の中に入れたり、鍵付きの引き出しの奥深くに隠したりしますよね。「透明なアクリルケース」に入れて、リビングの真ん中にドンと置いておく人なんて、まずいないはずです。そんなことをしたら、泥棒が入ってきたときに「どうぞ持っていってください!」と言っているようなものですからね。

実は、セキュリティ対策を始めたばかりの現場で、これと全く同じことが起きてしまっているケースがあるんです。

Kubernetesには、パスワードなどの機密情報を保存するための Secret という便利な機能があります。これを使えば、Base64という形式に変換(エンコード)されてK8sの中に保存されます。

ここで、セキュリティに初めて触れる方が一番勘違いしやすいポイントがあります。
「Base64でエンコードされているから、これで暗号化されて安全だよね?」……と。

残念ながら、これは大きな誤解なんです!
Base64というのは、データを「別の文字の並びに置き換えているだけ」のものです。これは鍵をかけた金庫ではなく、いわば「英語をローマ字で書いただけ」や「ちょっとした暗号ごっこ」のようなもの。誰でも一瞬で元の平文(普通の読める文字)に戻せてしまいます。

つまり、デフォルトのKubernetesの心臓部である etcd(データを保存しておくデータベース)の中では、あなたのパスワードが「誰でも読める平文の状態」でゴロンと転がっているのです。これが、今回お伝えしたい「Secrets平文保存のリスク」の正体なんですよ。

—

2. 攻撃者はどうやってその「宝箱」を狙うのか?

「でも、Kubernetesのクラスターの中って、そもそも外部からは守られているんじゃいの?」と思いますよね。確かに、外側からのファイアウォールなどはしっかり設定されていることが多いです。

しかし、レッドチーム(攻撃側)の視点から現実のインシデントを見てみると、攻撃者は次のようなルートでこの「透明なアクリルケース」にたどり着いてしまいます。

1. アプリの脆弱性を突かれる: 動かしているWebアプリケーションに別の脆弱性(例えば、ファイルの読み込みバグなど)があり、そこに侵入されてしまう。
2. K8sの権限奪取: 運悪く、そのコンテナに強い権限(ServiceAccount)が割り当てられていた場合、攻撃者はKubernetesのAPIサーバーにアクセスできるようになる。
3. Secretsの丸見え: APIサーバーを踏み台にして、etcd や Secrets のデータを覗き見ると、データベースの管理者パスワードやAWSの秘密鍵が丸裸で手に入ってしまう!

こうなると、もうお家の中のあらゆる部屋の合鍵が泥棒に渡ったようなものです。データベースも、外部のクラウドサービスも、すべて乗っ取られてしまいます。

—

3. 救世主登場!「Encryption at Rest(保存データの暗号化)」とは?

「うわ、怖い……じゃあどうすればいいの?」と不安になった方、安心してください! Kubernetesには、この etcd の中にあるデータをちゃんと「ガチガチの金庫(暗号化)」に守ってもらう機能がちゃんと用意されています。

それが、Encryption at Rest(保存データの暗号化)という仕組みです。

これは、etcd というデータベースに書き込む「直前」に、Kubernetesのシステム側でデータを強力な暗号に変換し、読むときは「取り出す瞬間」に復号(元の文字に戻す)するという素晴らしい機能です。

たとえ万が一、悪い人に etcd のデータファイルをごっそり盗み出されたとしても、中身はめちゃくちゃな暗号の羅列になっているため、絶対に解読できません。まさに、アクリルケースから頑丈な鉄の金庫に買い替えるようなものですね!

—

4. 実践!Encryption at Rest を設定してみよう

それでは実際に、どのように設定するのかを見ていきましょう。
「難しそう……」と思うかもしれませんが、設定ファイルを一つ用意して、APIサーバーに「この金庫(暗号化方式)を使ってね!」と教えてあげるだけです。一歩ずつ見ていきましょう!

ステップ1:暗号化設定ファイル(EncryptionConfiguration)の作成

まずは、どのような暗号化アルゴリズムを使い、どんな鍵で暗号化するのかを指定するYAMLファイルを作成します。マスターノードの適当な場所(例: /etc/kubernetes/enc/encryption-config.yaml)に配置します。

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets # 暗号化の対象とするリソースを指定します
    providers:
      - aescbc:
          keys:
            - name: key1
              # 32バイトのランダムな文字列をBase64エンコードしたものをここに書きます
              # 例としてダミーの値を載せています。実際には openssl 等で生成してくださいね!
              secret: c3VwZXJzZWNyZXRwYXNzd29yZGNvdWxkYmVzdHJvbmcK
      - identity: {} # 万が一古いデータにアクセスする場合のフォールバック(何もしないプロバイダー)

*ワンポイントアドバイス*: 上記の secret の部分には、強力なランダムな値を必ず設定してくださいね。Linuxのターミナルであれば、以下のコマンドで簡単に安全な鍵が作れます!

head -c 32 /dev/urandom | base64

ステップ2:APIサーバーの設定を変更する

次に、Kubernetesの心臓部であるAPIサーバー(kube-apiserver)に、先ほど作った暗号化設定ファイルを読み込ませるように指示します。

Kubeadmなどで構築した環境であれば、APIサーバーの静的ポッド定義ファイル(通常は /etc/kubernetes/manifests/kube-apiserver.yaml)を開き、以下のようにオプションを追加します。

spec:
  containers:
  - command:
    - kube-apiserver
    # --- ここから追加する設定です ---
    - --encryption-provider-config=/etc/kubernetes/enc/encryption-config.yaml
    # --- ここまで ---
    volumeMounts:
    - mountPath: /etc/kubernetes/enc
      name: encryption-conf
      readOnly: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/enc
      type: DirectoryOrCreate
    name: encryption-conf

この設定を行うと、APIサーバーが再起動し、これ以降に作成・更新される Secret は自動的に暗号化されて etcd に保存されるようになります!

—

5. すでに保存されている古いSecretsはどうなるの?

ここで、「新しい設定は分かったけど、すでに平文で保存されちゃっている過去のデータはどうなるの?」という疑問が湧きますよね。とても鋭い着眼点です!

実は、Encryption at Restを有効にしても、既存のデータは自動的には暗号化されません。古いデータは平文のまま etcd に残ってしまいます。

そのため、実務の現場では、設定を有効にした後にすべての既存Secretを書き換える(マイグレーションする)作業が必要になります。具体的には、以下のようなコマンドを実行して、データを一度読み込んでから保存し直すことで、新しい暗号化を適用させます。

# すべてのシークレットを強制的に上書き保存し、暗号化を適用するコマンドの例
kubectl get secrets --all-namespaces -o json | kubectl replace -f -

*※本番環境で実行する際は、必ず事前にバックアップを取ってから、影響の少ない時間帯にテストを行ってくださいね!*

—

まとめ

いかがでしたでしょうか? 今回はKubernetesにおけるSecretsの平文保存リスクと、それを守るための Encryption at Rest について解説しました。

  • KubernetesのSecretsは、デフォルトではただのBase64(見せかけの姿)であり、etcd内では平文である。
  • 攻撃者にクラスター内に入り込まれると、パスワードやAPIキーがすべて盗まれてしまうリスクがある。
  • EncryptionConfigurationを設定することで、etcd上のデータを強力に暗号化し、安全な金庫にしまうことができる。

セキュリティの対策と聞くと難しく身構えてしまいがちですが、「どこにどんなリスクがあって、どうやって鍵をかけるか」という基本の考え方は、私たちの現実世界の防犯と全く同じです。

今日学んだ一歩を、ぜひ皆さんの開発・運用しているKubernetes環境のチェックに使ってみてくださいね。より安全で安心なインフラライフを一緒に作っていきましょう!

コメント

タイトルとURLをコピーしました