第35章 データストア層でのデータの暗号化
35.1. 概要
このトピックでは、データストア層でシークレットデータの暗号化を有効にし、これを設定する方法について説明します。サンプルでは secrets
リソースを使用していますが、configmaps
などのすべてのリソースを暗号化することができます。
この機能を使用するには、etcd v3 以降が必要になります。
35.2. 設定および暗号がすでに有効にされているかどうかの判別
データ暗号化をアクティブにするには、--experimental-encryption-provider-config
引数を Kubernetes API サーバーに渡します。
master-config.yaml の抜粋
kubernetesMasterConfig: apiServerArguments: experimental-encryption-provider-config: - /path/to/encryption-config.yaml
master-config.yaml およびその形式についての詳細は、「マスター設定ファイル」のトピックを参照してください。
35.3. 暗号化設定について
すべての利用可能なプロバイダーを含む暗号化設定ファイル
kind: EncryptionConfig apiVersion: v1 resources: 1 - resources: 2 - secrets providers: 3 - aescbc: 4 keys: - name: key1 5 secret: c2VjcmV0IGlzIHNlY3VyZQ== 6 - name: key2 secret: dGhpcyBpcyBwYXNzd29yZA== - secretbox: keys: - name: key1 secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= - aesgcm: keys: - name: key1 secret: c2VjcmV0IGlzIHNlY3VyZQ== - name: key2 secret: dGhpcyBpcyBwYXNzd29yZA== - identity: {}
- 1
resources
のそれぞれの配列項目は分離した設定であり、詳細な設定が含まれます。- 2
resources.resources
フィールドは暗号化が必要な Kubernetes リソース名 (resource
またはresource.group
) の配列です。- 3
providers
配列は、順序付けられた使用可能な暗号化プロバイダーの一覧です。エントリーごとに 1 つのプロバイダータイプ (identity
またはaescbc
)のみを指定できますが、同じ項目に両方を指定することはできません。- 4
- 一覧の最初のプロバイダーがストレージに移動するリソースを暗号化するために使用されます。
- 5
- シークレットの任意の名前です。
- 6
- Base64 のエンコーディングされたランダムキーです。異なるプロバイダーが異なるキーの長さを指定します。詳細は、「キーの生成方法」についての説明を参照してください。
ストレージからのリソースの読み取り時に、保存されたデータに一致する各プロバイダーはデータの復号化を順番に試行します。情報またはシークレットキーの不一致により保存データを読み取れるプロバイダーがない場合にエラーが返され、クライアントがそのリソースにアクセスできなくなります。
リソースが暗号化設定で読み取れない場合 (キーの変更により)、キーを基礎となる etcd ディレクトリーから削除することのみが必要になります。そのリソースの読み取りを試行する呼び出しは、キーが削除されるか、または有効な復号化キーが提供されない限り失敗します。
35.3.1. 利用可能なプロバイダー
名前 | 暗号化 | 強度 | 速度 | キーの長さ | 他の考慮事項 |
---|---|---|---|---|---|
identity |
なし |
該当なし |
該当なし |
該当なし |
暗号化なしのそのままの状態で作成されたリソースです。最初のプロバイダーとして設定される場合、リソースは新規の値が書き込まれるときに復号化されます。 |
aescbc |
PKCS#7 パディングが設定された AES-CBC |
最も強い |
高速 |
32 バイト |
暗号化に推奨されるオプションですが、secretbox よりも若干遅くなる可能性があります。 |
secretbox |
XSalsa20 および Poly1305 |
強い |
より高速 |
32 バイト |
より新しい標準であり、高レベルのレビューが必要な環境では受け入れ可能と見なされない可能性があります。 |
aesgcm |
AES-GCM およびランダム初期化ベクター (IV) |
200,000 回の書き込みごとにローテーションが必要です。 |
最速 |
16、24、または 32 バイト |
自動化されたキーの回転スキームが実行される場合以外には、使用することが推奨されません。 |
各プロバイダーは複数のキーをサポートします。キーは復号化の順序で試行されます。プロバイダーが最初のプロバイダーの場合、最初のキーが暗号化に使用されます。
Kubernetes には適切な nonce ジェネレーターがないため、AES-GCM の nonce としてランダム IV を使用します。AES-GCM では適切な nonce がセキュアな状態であることが求められるため、AES-GCM は推奨されません。200,000 回の書き込み制限は nonce の致命的な誤用の可能性を比較的低く抑えます。
35.4. データの暗号化
新規の暗号化設定ファイルを作成します。
kind: EncryptionConfig apiVersion: v1 resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: <BASE 64 ENCODED SECRET> - identity: {}
新規シークレットを作成するには、以下を実行します。
32 バイトのランダムキーを生成し、これを base64 でエンコーディングします。たとえば、Linux および macOS では、以下を使用します。
$ head -c 32 /dev/urandom | base64
重要暗号化キーは、/dev/urandom などの暗号で保護された乱数ジェネレーターで生成する必要があります。Golang の
math/random
や Python のrandom.random()
などは適していません。-
この値を
secret
フィールドに配置します。 API サーバーを再起動します。
# master-restart api # master-restart controllers
暗号化プロバイダー設定ファイルには、etcd の内容を復号化できるキーが含まれるため、マスター API サーバーを実行するユーザーのみがこれを読み取れるようにマスターでパーミッションを適切に制限する必要があります。
35.5. データが暗号化されていることの確認
データは etcd に書き込まれる際に暗号化されます。API サーバーの再起動後、新たに作成されたか、または更新されたシークレットは保存時に暗号化されます。これを確認するには、etcdctl
コマンドラインプログラムを使用してシークレットの内容を検索できます。
default
の namespace に、secret1
という新規シークレットを作成します。$ oc create secret generic secret1 -n default --from-literal=mykey=mydata
etcdctl
コマンドラインを使用し、etcd からシークレットを読み取ります。$ ETCDCTL_API=3 etcdctl get /kubernetes.io/secrets/default/secret1 -w fields [...] | grep Value
[…]
には、etcd サーバーに接続するために追加の引数を指定する必要があります。最終的なコマンドは以下と同様になります。
$ ETCDCTL_API=3 etcdctl get /kubernetes.io/secrets/default/secret1 -w fields \ --cacert=/var/lib/origin/openshift.local.config/master/ca.crt \ --key=/var/lib/origin/openshift.local.config/master/master.etcd-client.key \ --cert=/var/lib/origin/openshift.local.config/master/master.etcd-client.crt \ --endpoints 'https://127.0.0.1:4001' | grep Value
- 上記のコマンド出力には、aescbc プロバイダーが結果として生成されるデータを暗号化したことを示す k8s:enc:aescbc:v1: のプレフィックスが付けられます。
シークレットが API 経由で取得される場合は、正しく復号化されていることを確認します。
$ oc get secret secret1 -n default -o yaml | grep mykey
これは mykey: bXlkYXRh と一致するはずです。
35.6. すべてのシークレットが暗号化されていることの確認
シークレットは書き込み時に暗号化されるため、シークレットの更新を実行するとその内容は暗号化されることになります。
$ oc adm migrate storage --include=secrets --confirm
このコマンドはすべてのシークレットを読み取り、次にサーバー側の暗号化を適用するようにそれらを更新します。書き込みの競合のためにエラーが発生する場合は、コマンドを再試行してください。
大規模クラスターの場合、シークレットを namespace 別に細分化するか、または更新をスクリプト化することができます。
35.7. 復号化キーのローテーション
複数の API サーバーが実行されている高可用デプロイメントがある場合などに、ダウンタイムを発生させずにシークレットを変更するには、複数の手順からなる操作が必要になります。
- 新規キーを生成し、これをすべてのサーバーで同時プロバイダーの 2 つ目のキーエントリーとして追加します。
すべての API サーバーを再起動し、各サーバーが新規キーを使用して復号化できるようにします。
注記単一 API サーバーを使用している場合は、この手順を省略できます。
# master-restart api # master-restart controllers
-
新規キーを
keys
配列の最初のエントリーにし、これが設定で暗号化に使用されるようにします。 すべての API サーバーを再起動し、各サーバーが新規キーを使用して暗号化できるようにします。
# master-restart api # master-restart controllers
以下を実行し、新規キーですべての既存シークレットを暗号化します。
$ oc adm migrate storage --include=secrets --confirm
- 新規キーを使用して etcd をバックアップし、すべてのシークレットを更新した後に、古い復号化キーを設定から削除します。
35.8. データの復号化
データストア層で暗号化を無効にするには、以下を実行します。
- identity プロバイダーを、設定の最初のエントリーとして配置します。
kind: EncryptionConfig apiVersion: v1 resources: - resources: - secrets providers: - identity: {} - aescbc: keys: - name: key1 secret: <BASE 64 ENCODED SECRET>
すべての API サーバーを再起動します。
# master-restart api
以下を実行し、すべてのシークレットの復号化を強制的に実行します。
$ oc adm migrate storage --include=secrets --confirm