kubernetesのSecretでクレデンシャル管理

kubernetesの Secretは、クレデンシャル類をコンテナイメージなどから分離して供給するための標準機能です。

よく知られている通りSecretは暗号化されてはいないため、権限があれば内容は確認できます。
Secretの主眼は、クレデンシャルを含む設定ファイルなどを他のコードリポジトリと分離できる点にあります。

Secretにはいくつかの型があり、用途により使いわけます。
DeploymentServiceなど他リソースがマニフェストを直接編集するケースが多いのに対して、Secretは各アプリ固有の設定ファイルなどをkubectl create secretコマンドに入力して生成します。

設定ファイル

アプリケーションの設定ファイルにパスワードを記述するケースでは、設定ファイルやディレクトリをkubectl create secret [generic] --from-fileオプションでOpaque型のSecretにエンコードします。
Opaque型は、語彙が異なるもののConfigMapと使い方は同じです。

Secretの更新

Secretには直接のapplyサブコマンドがないため、更新をしたい場合には、次のようにエンコードした新リソースをシェルのパイプでkubectl applyに供給します。

$ kubectl create secret generic <secret-name> --dry-run=client --save-config --from-file=<source-directory> -o yaml | kubectl apply -f -

なお、kubectl applyによりコンテナ内の該当ファイルも更新されるものの、シンボリックリンクを介した実装であることもあり、アプリケーションが必ずしも変更を自動で検出するわけではないという点には注意が必要です。
コンテナ再起動を必要とする場合が多々あります。

マニフェストのバックアップ

Secretは主に入力リソースを変換して生成するため、稼働中のクラスタと一致するマニフェストが必要な場合には、ファイルにダンプします。

$ kubectl get secret [-n <namespace> | --all-namespaces] -o yaml > <secret-manifest.yaml>

最新のバックアップマニフェストがあれば、他のリソースと同様にkubectl applySecretを一括セットアップできます。

多くの場合、PodがSecretに依存する構成となるため、クラスタ移行の初期作業としてSecretセットアップが必要になるでしょう。

環境変数

Podのspec.containers.[].envには環境変数を定義できますが、これは平文で記載するものでクレデンシャルには適していません。
spec.containers.[].envFromを用いるとSecretに定義した変数を環境変数としてインポートできます。

    spec:
      containers:
      - name:
        envFrom:
        - secretRef:
            name: <secret-name>
        env:
        - name: ACCOUNT_ID
          value: "[email protected]"

このenvFromに指定するSecretは、次のようなenvファイル形式から専用オプションで作成します。この例では1変数のみですが、改行区切りで複数定義できます。

PASSWORD=some-password

このファイルからSecretを作成するコマンドは、kubectl create secret [generic] <secret-name> --from-env-file <input.env>です。 --from-env-fileオプションで作成したSecretをkubectl get secret -oyamlで確認すると、dataに環境変数のキーが直接リストされています。この形式になっていない場合、envFromでインポートしても該当の環境変数が未定義になります。

適切にセットアップできていれば、コンテナ内のシェルで$PASSWORDのように参照できます。
なおenvenvFromは併用でき、環境変数のキーが異なるものは両方の定義をコンテナ内で参照できます。

Ingress用SSL証明書

SSL証明書にはkubernetes.io/tls型を利用でき、TLS型のSecretはingressの証明書に指定できます。

Let’s Encryptで取得できる証明書の例では、以下のようなコマンドでTLS型のsecretを作成します。

kubectl create secret tls <cert-example.com> --key=privkey.pem --cert=fullchain.pem

Webサーバーの証明書に流用

TLS型のSecretは素朴なOpaque型としてマウントも可能です。コンテナのWebサーバー向けの証明書ファイルとして用います。
任意のPathにvolumeMountしたうえで、Webサーバーのconfigから参照します。

    spec:
      containers:
      - name: nginx
        # skip general configs
        #
        volumeMounts:
        - name: tls-cert
          mountPath: /etc/certs
      volumes:
      - name: tls-cert
        secret:
          secretName: cert-example.com

この例では、証明書は/etc/certs/tls.crt、鍵は/etc/certs/tls.keyになります。
なおSecretの中身を変更した場合、コンテナのファイルも更新されますが、それによりWebサーバーが新しい証明書を参照するか否かは実装依存です。
Secretはシンボリックリンクとして実装されているため、inotifyが伝わらず変更検知しない実装もあります。

プライベートレジストリ認証のためのSecret

Google Artifact Regisryなどのクローズドなコンテナイメージレジストリへのアクセスにdocker-registry型のSecretを利用する場合があります。
これはコンテナ内部で参照するものではなく、クラスタに設定するものです。

詳細は、 プライベートレジストリへのアクセス権を設定で解説しています。

中馬崇尋
Chuma Takahiro