IBM Cloud Blog

Red Hat OpenShift on IBM Cloudで暗号化されたイメージからコンテナをデプロイするには

記事をシェアする:

この投稿は、2021年1月15日に、米国 IBM Cloud Blog に掲載されたブログ(英語)の抄訳です。

2020年12月に、Red Hat OpenShift on IBM Cloud(*)で稼働する暗号化イメージからコンテナをデプロイできるようになりました(*バージョン4.4以降)

コンテナ・イメージは、業界標準で、アプリケーションとその依存関係をパッケージ化し、移動し、デプロイするために生み出されたものです。多くの場合、コンテナ・イメージには機密情報(独自のアルゴリズムなど)が含まれており、一般には共有されないようになっています。このようなプライベートなイメージを他からのアクセスから保護するために、企業内部のビルド・パイプラインを確立し、権限のないクライアントがアクセスできないプライベートなコンテナ・レジストリにコンテナ・イメージを保管しています。万一攻撃者がプライベート・コンテナ・レジストリに侵入した場合、プライベート・コンテナ・イメージを盗み出して他の場所で実行したり、その内容を調べたり、アプリケーションの弱点を見つけたりすることができます。

コンテナ・イメージの暗号化は、秘密鍵と公開鍵のペアを使用して、コンテナ・イメージ層の暗号化と復号化を行うことで、セキュリティー対策の高度化を支援することができます。暗号化されたコンテナ・イメージは、適切な復号鍵がなければアクセスできないため、情報流出の危険にさらされるリスクを減少させることができます。

これはコンテナ・イメージの暗号化のユースケースの一つに過ぎませんが、他にもいくつかあります。

 

コンテナ・イメージを暗号化する

コンテナの暗号化を構築するのに、既存のDockerfileを変更する必要はありませんが、 buildah(英語)やskopeo(英語)などの新しいツールが必要になります。また、暗号化に使用する秘密鍵と公開鍵のペアを生成する必要があります。

コンテナ・イメージのビルド、暗号化、プッシュのワークフローは複数あります:

  • buildahを使ってDockerfileからコンテナ・イメージをビルドし、それをレジストリにプッシュして暗号化キーを指定することができます。
  • skopeoを使って、既存のコンテナをレジストリにプッシュし、暗号化キーを指定することができます。

コンテナ・イメージのビルド、暗号化、プッシュの詳細な手順については、公式文書をご参照いただくことをお勧めします。

 

主な例

この例では、Dockerfileを使ってコンテナ・イメージを構築し、公開鍵ペアを生成し、その鍵ペアを使ってイメージを暗号化し、イメージをレジストリにプッシュする手順を示しています。

この例のコンテナのようなDockerfileから始めてください:

FROM docker/whalesay
RUN apt update && apt install fortune -y
CMD while true; do /usr/games/fortune | cowsay; sleep 10; done

 

buildah bud コマンドでイメージを作成してくださいc:

$ buildah bud -t us.icr.io/attila-fabian/mycontainer:latest .
...
979337e38c8e28491e14ba4d0fabaac5b49ff80380eeb2783ed1b06d14754542
$ buildah images
REPOSITORY                                             TAG      IMAGE ID       CREATED          SIZE
us.icr.io/attila-fabian/mycontainer                    latest   979337e38c8e   19 seconds ago   266 MB

 

コンテナを暗号化してプッシュする前に、暗号化に使用する秘密鍵と公開鍵のペアを生成します:

$ openssl genrsa --out private.pem
Generating RSA private key, 2048 bit long modulus (2 primes)
...
$ openssl rsa -in private.pem -pubout -out public.pem
writing RSA key
$ ls
private.pem  public.pem

 

buildah bud コマンドを使って、暗号化し、イメージをプッシュしてください:

$ buildah push --encryption-key jwe:public.pem us.icr.io/attila-fabian/mycontainer:latest
Getting image source signatures
...
Writing manifest to image destination
Storing signatures

 

ローカル・イメージを削除し、buildah budを使ってイメージをプルしてください :

$ buildah rmi us.icr.io/attila-fabian/mycontainer:latest
untagged: us.icr.io/attila-fabian/mycontainer:latest
979337e38c8e28491e14ba4d0fabaac5b49ff80380eeb2783ed1b06d14754542
$ buildah pull us.icr.io/attila-fabian/mycontainer:latest
Getting image source signatures
...
Error decrypting layer sha256:45a9fb9687e20fec30a55939219706470948ef11a4e4080a6df23e3726000470: missing private key needed for decryption
ERRO exit status 125

 

このエラーはあらかじめ予想されたものです。では、指定した秘密鍵でイメージをプルしてましょう:

$ buildah pull --decryption-key private.pem us.icr.io/attila-fabian/mycontainer:latest
Getting image source signatures
...
Writing manifest to image destination
Storing signatures
979337e38c8e28491e14ba4d0fabaac5b49ff80380eeb2783ed1b06d14754542

 

今度は無事にイメージがプルされました。

 

暗号化されたコンテナ・イメージからのアプリケーションのをデプロイする

ほとんどのコンテナ・ランタイムは、暗号化されたコンテナ・イメージを扱うことができます。Red Hat OpenShift on IBM Cloudの場合、バージョン1.17から暗号化コンテナ・イメージのサポートを提供しているため、 cri-o (英語)を使用しています。

暗号化されたコンテナ・イメージを使用する場合、適切な復号化キーをコンテナ・ランタイムに提供する必要があります。cri-oを使用する場合、これは秘密鍵を /etc/crio/keys ディレクトリーの下に配置することを意味します(デフォルトの設定)

OpenShiftクラスタの場合、復号鍵を提供するには2つの課題があります:

  • 復号キーはすべてのワーカー・ノード上のcri-oに提供する必要があります。
  • キーをワーカー・ノードのファイル・システムに手動でコピーしてはいけません。

これらの課題に対応するには、IBM Cloud Image Key Synchronizer 管理アドオンを使用します。この アドオンを使用すると、復号鍵を Kubernetes の秘密リソースの形で指定し、ワーカー ・ノード上でこれらの鍵の同期化をすることができます。

OpenShiftクラスタのアドオンを有効にした後は、鍵をシークレットに指定するだけで準備は完了です。

IBM Cloud Image Key Synchronizerの使用方法の詳細については、公式文書を参照されることをお勧めします。

 

標準的な秘密鍵を使用した例

この例では、IBM Cloud Image Key Synchronizer のマネージド・アドオンをテスト用 OpenShift クラスターにインストールし、前の例で構築したイメージを使用してポッドを作成する手順を示します。

まず、使用できるOpenShift 4.4以降のクラスタを特定します:

$ ibmcloud oc cluster ls
OK
Name
ID                     State     Created        Workers   Location
Version                 Resource Group Name 
  Provider
encrypted-containers-example
bvbs8g8s0akvcjht7f7g   normal    3 weeks ago    2         Sydney
4.5.18_1523_openshift 
  Default               classic

 

IBM Cloud Image Key Synchronizer マネージド・アドオンをクラスターにインストールします:

$ ibmcloud oc cluster addon enable image-key-synchronizer --cluster bvbs8g8s0akvcjht7f7g
Enabling add-on image-key-synchronizer for cluster bvbs8g8s0akvcjht7f7g...
The add-on might take several minutes to deploy and become ready for use.
OK

 

アドオンがデプロイされたら、 DaemonSet がimage-key-synchronizerという新規のプロジェクトに作成されます:

$ oc get daemonset -n image-key-synchronizer
NAME                           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
addon-image-key-synchronizer   2         2         2       2            2           <none>          14s

 

先ほどの例でビルドしてプッシュしたコンテナをデプロイしてみましょう:

$ oc apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - image: us.icr.io/attila-fabian/mycontainer:latest
    name: mycontainer
    imagePullPolicy: Always
EOF
pod/mypod created

 

復号鍵がまだ指定されていないため、ポッドは起動しないはずです:

$ oc describe pod mypod
Name:         mypod
Namespace:    default
...
Containers:
  mycontainer:
    Image:          us.icr.io/attila-fabian/mycontainer:latest
    ...
    State:          Waiting
      Reason:       ImagePullBackOff
    Ready:          False
    ...
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
...
Events:
  Type     Reason          Age                 From                     Message
  ----     ------          ----                ----                     -------
  ...
  Warning  Failed          45s (x3 over 102s)  kubelet, 10.138.107.220  Failed to pull image "us.icr.io/attila-fabian/mycontainer:latest":
rpc error: code = Unknown desc = Error decrypting layer
sha256:45a9fb9687e20fec30a55939219706470948ef11a4e4080a6df23e3726000470:
no suitable key unwrapper found or none of the private keys could be
used
for decryption
  Warning  Failed          45s (x3 over 102s)  kubelet, 10.138.107.220  Error: ErrImagePull
  Normal   BackOff         18s (x4 over 101s)  kubelet, 10.138.107.220  Back-off pulling image "us.icr.io/attila-fabian/mycontainer:latest"
  Warning  Failed          18s (x4 over 101s)  kubelet, 10.138.107.220  Error: ImagePullBackOff
  Normal   Pulling         5s (x4 over 114s)   kubelet, 10.138.107.220  Pulling image "us.icr.io/attila-fabian/mycontainer:latest"

 

よくできました。次に、シークレットで復号鍵を指定し、イメージ鍵同期プロジェクトでシークレットを作成します:

$ oc apply -f - <<EOF
apiVersion: v1
kind: Secret
type: key
metadata:
  name: mydecryptionsecret
  namespace: image-key-synchronizer
data:
  private.pem: $(cat private.pem | base64 | tr -d "\n")
EOF
secret/mydecryptionsecret created

 

さあ、ポッドを削除して再度作り直しましょう:

$ oc delete pod mypod
pod "mypod" deleted
$ oc apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - image: us.icr.io/attila-fabian/mycontainer:latest
    name: mycontainer
    imagePullPolicy: Always
EOF
pod/mypod created
$ oc get pods
NAME    READY   STATUS    RESTARTS   AGE
mypod   1/1     Running   0          35s
$ oc logs mypod
...
 ______________________________________
/ F.S. Fitzgerald to Hemingway:        \
|                                      |
| "Ernest, the rich are different from |
| us." Hemingway:                      |
|                                      |
\ "Yes. They have more money."         /
 --------------------------------------
    \
     \
      \
                    ##        .
              ## ## ##       ==
           ## ## ## ##      ===
       /""""""""""""""""___/ ===
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
       \______ o          __/
        \    \        __/
          \____\______/
...

 

これで完了です。今回は暗号化されたコンテナ・イメージがプルされ、無事にポッドが起動しました。

 

IBM Key Protect for IBM Cloudを使って秘密鍵をラップする例 

IBM Cloud Image Key Synchronizer のアドオンは、IBM Key Protect for IBM Cloud (英語)サービスとの統合機能を提供します。

Key Protect を使用すれば、暗号化キーをより安全に利用することができます。例えば、特定のルート鍵を使用して秘密鍵をラップし、プレーンな秘密鍵の代わりにラップされた鍵を指定することができます。

以下の例では、あらかじめ作成した Key Protect インスタンスとルートキーを使用しています。サービスインスタンスとルートキーの作成の詳細については、こちらの公式文書を参照されることをお勧めします。

$ ibmcloud kp keys --instance-id 832fdb1a-c3b3-exmp-847e-31f238f4767c
Retrieving keys...
OK
Key ID                                 Key Name
883cc3d3-d281-44f3-a1d5-372289491c77   test-root-key

 

IBM Cloud Image Key Synchronizerは、Key Protect インスタンスへの接続を解決するために、いくつかの設定が必要です:

oc apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: keyprotect-config
  namespace: image-key-synchronizer
type: Opaque
stringData:
  config.json: |
      {
          "keyprotect-url":"https://us-south.kms.cloud.ibm.com",
          "instance-id": "832fdb1a-c3b3-exmp-847e-31f238f4767c",
          "apikey": "5ZtsYoNA0zexamleD8Av7lDSuaof-w7examleKc_MGgE"
      }
EOF
secret/keyprotect-config created

 

設定を作成したら、Key Protect でラップされた鍵の指定を開始できます。次のスニペットはibmcloud kp key wrap コマンドを使用して、Key Protect インスタンスの下でルート・キーを使用して private.pem キー・ファイルの内容をラップしています。Key Protect は、ラップを解除しないと使用できない暗号文を返します。上記で提供された設定により、IBM Cloud Image Key Synchronizer は提供された秘密をアンラップすることができます。:

$ oc apply -f - <<EOF
apiVersion: v1
kind: Secret
type: kp-key
metadata:
  name: mywrappeddecryptionsecret
  namespace: image-key-synchronizer
data:
  private.pem: $(ibmcloud kp key wrap 883cc3d3-d281-44f3-a1d5-372289491c77 --plaintext "$(cat private.pem | base64)" --instance-id 832fdb1a-c3b3-exmp-847e-31f238f4767c -o json | jq -r .Ciphertext)
EOF
secret/mywrappeddecryptionsecret created

 

ここで、テスト・ポッドを削除して、それを再度作成してください:

$ oc delete pod mypod
pod "mypod" deleted
$ oc apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - image: us.icr.io/attila-fabian/mycontainer:latest
    name: mycontainer
    imagePullPolicy: Always
EOF
pod/mypod created
$ oc get pods
NAME    READY   STATUS    RESTARTS   AGE
mypod   1/1     Running   0          55s
$ oc logs mypod
...
 __________________________________
< Someone is speaking well of you. >
 ----------------------------------
    \
     \
      \
                    ##        .
              ## ## ##       ==
           ## ## ## ##      ===
       /""""""""""""""""___/ ===
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
       \______ o          __/
        \    \        __/
          \____\______/
...

 

よくできました。今回は、暗号化された画像をKey Protect でラップした秘密鍵を使ってプルすることに成功しました。

 

さらに詳しい情報は

暗号化されたコンテナ・イメージの詳細については、 Encrypted container images for container image security at rest (英文)と Advancing container image security with encrypted container images (英文)の記事をご参照ください。また、さらに詳しい情報については、こちらの公式文書もあわせてご参照ください。

 

お問い合わせは

ご質問やお問い合わせがございましたら、こちら(英語)に登録して、IBM Cloud Kubernetes Service の公開Slackの#generalチャンネルでディスカッションに参加してどしどしお寄せください。


翻訳:IBM Cloud Blog Japan 編集部

*このブログは、2021/1/15に発行された“IBM Named as a Forrester Wave Leader (and Why it matters to Your AI initiative)(英語)”の抄訳です。

More IBM Cloud Blog stories

セキュリティー・ロードマップ

IBM Cloud Blog

統合脅威管理、耐量子暗号化、半導体イノベーションにより、分散されているマルチクラウド環境が保護されます。 2023 安全な基盤モデルを活用した統合脅威管理により、価値の高い資産を保護 2023年には、統合された脅威管理と ...続きを読む


量子ロードマップ

IBM Cloud Blog

コンピューティングの未来はクォンタム・セントリックです。 2023 量子コンピューティングの並列化を導入 2023年は、Qiskit Runtimeに並列化を導入し、量子ワークフローの速度が向上する年になります。 お客様 ...続きを読む


ハイブリッドクラウド・ロードマップ

IBM Cloud Blog

コンポーザブルなアプリケーション、サービス、インフラストラクチャーにより、企業は複数のクラウドにまたがるダイナミックで信頼性の高い仮想コンピューティング環境の作成が可能になり、開発と運用をシンプルに行えるようになります。 ...続きを読む