Red Hat Training

A Red Hat training course is available for OpenShift Container Platform

第32章 データストア層でのデータの暗号化

32.1. 概要

このトピックでは、データストア層でシークレットデータの暗号化を有効にし、これを設定する方法について説明します。サンプルでは secrets リソースを使用していますが、configmaps などのすべてのリソースを暗号化することができます。

重要

この機能を使用するには、etcd v3 以降が必要になります。

32.2. 設定および暗号がすでに有効にされているかどうかの判別

データ暗号化をアクティブにするには、--experimental-encryption-provider-config 引数を Kubernetes API サーバーに渡します。

master-config.yaml の抜粋

kubernetesMasterConfig:
  apiServerArguments:
    experimental-encryption-provider-config:
    - /path/to/encryption-config.yaml

For more information about master-config.yaml and its format, see the Master Configuration Files topic.

32.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 ディレクトリーから削除することのみが必要になります。そのリソースの読み取りを試行する呼び出しは、キーが削除されるか、または有効な復号化キーが提供されない限り失敗します。

32.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 の致命的な誤用の可能性を比較的低く抑えます。

32.4. データの暗号化

新規の暗号化設定ファイルを作成します。

kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
    - secrets
    providers:
    - aescbc:
        keys:
        - name: key1
          secret: <BASE 64 ENCODED SECRET>
    - identity: {}

新規シークレットを作成するには、以下を実行します。

  1. 32 バイトのランダムキーを生成し、これを base64 でエンコーディングします。たとえば、Linux および macOS では、以下を使用します。

    $ head -c 32 /dev/urandom | base64
    重要

    暗号化キーは、/dev/urandom などの暗号で保護された乱数ジェネレーターで生成する必要があります。Golang の math/random や Python の random.random() などは適していません。

  2. この値を secret フィールドに配置します。
  3. API サーバーを再起動します。

    # systemctl restart atomic-openshift-master-api
重要

暗号化プロバイダー設定ファイルには、etcd の内容を復号化できるキーが含まれるため、マスター API サーバーを実行するユーザーのみがこれを読み取れるようにマスターでパーミッションを適切に制限する必要があります。

32.5. データが暗号化されていることの確認

データは etcd に書き込まれる際に暗号化されます。API サーバーの再起動後、新たに作成されたか、または更新されたシークレットは保存時に暗号化されます。これを確認するには、etcdctl コマンドラインプログラムを使用してシークレットの内容を検索できます。

  1. default の namespace に、secret1 という新規シークレットを作成します。

    $ oc create secret generic secret1 -n default --from-literal=mykey=mydata
  2. 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
  3. 上記のコマンド出力には、aescbc プロバイダーが結果として生成されるデータを暗号化したことを示す k8s:enc:aescbc:v1: のプレフィックスが付けられます。
  4. シークレットが API 経由で取得される場合は、正しく復号化されていることを確認します。

    $ oc get secret secret1 -n default -o yaml | grep mykey

    これは mykey: bXlkYXRh と一致するはずです。

32.6. すべてのシークレットが暗号化されていることの確認

シークレットは書き込み時に暗号化されるため、シークレットの更新を実行するとその内容は暗号化されることになります。

$ oc adm migrate storage --include=secrets --confirm

このコマンドはすべてのシークレットを読み取り、次にサーバー側の暗号化を適用するようにそれらを更新します。書き込みの競合のためにエラーが発生する場合は、コマンドを再試行してください。

大規模クラスターの場合、シークレットを namespace 別に細分化するか、または更新をスクリプト化することができます。

32.7. 復号化キーのローテーション

複数の API サーバーが実行されている高可用デプロイメントがある場合などに、ダウンタイムを発生させずにシークレットを変更するには、複数の手順からなる操作が必要になります。

  1. 新規キーを生成し、これをすべてのサーバーで同時プロバイダーの 2 つ目のキーエントリーとして追加します。
  2. すべての API サーバーを再起動し、各サーバーが新規キーを使用して復号化できるようにします。

    注記

    単一 API サーバーを使用している場合は、この手順を省略できます。

    # systemctl restart atomic-openshift-master-api
  3. 新規キーを keys 配列の最初のエントリーにし、これが設定で暗号化に使用されるようにします。
  4. すべての API サーバーを再起動し、各サーバーが新規キーを使用して暗号化できるようにします。

    # systemctl restart atomic-openshift-master-api
  5. 以下を実行し、新規キーですべての既存シークレットを暗号化します。

    $ oc adm migrate storage --include=secrets --confirm
  6. 新規キーを使用して etcd をバックアップし、すべてのシークレットを更新した後に、古い復号化キーを設定から削除します。

32.8. データの復号化

データストア層で暗号化を無効にするには、以下を実行します。

  1. identity プロバイダーを、設定の最初のエントリーとして配置します。
kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
    - secrets
    providers:
    - identity: {}
    - aescbc:
        keys:
        - name: key1
          secret: <BASE 64 ENCODED SECRET>
  1. すべての API サーバーを再起動します。

    # systemctl restart atomic-openshift-master-api
  2. 以下を実行し、すべてのシークレットの復号化を強制的に実行します。

    $ oc adm migrate storage --include=secrets --confirm