コンテントトラストの委任鍵ペア

読む時間の目安: 11 分

Docker コンテントトラスト (Docker content trust; DCT) における委任鍵ペア(delegations)は、イメージタグへのサインを、誰ができて誰ができないのかを制御するものです。 委任鍵は、委任を行う秘密鍵と公開鍵のペアによって構成されます。 委任鍵には、鍵とその提供者の組み合わせを複数含めることができます。 これにより a) 委任鍵のユーザーを複数にすることができ、b) 鍵のローテーションを可能にします。

Docker コンテントトラストにおける委任にあたり、最も重要なものはtargets/releasesです。 これは信頼された(trusted)イメージタグの標準的なソースとして見ることができます。 この委任情報のもとに提供者の鍵が存在していないと、提供者はタグにサインすることができません。

$ docker trustコマンドを使えば、リポジトリの初期化、リポジトリ鍵の管理を簡単に行うことができます。 またdocker trust signer addによってtargets/releases内の委任情報に共同作業者の鍵を含めることができます。

Docker クライアントの設定

デフォルトで$ docker trustコマンドは、イメージタグ内にて指定されているレジストリ URL と Notary サーバーの URL が同一であるものとして扱います(これは$ docker pushに対するロジックに対応するものです)。 Docker Hub や DTR を利用する際には、Notary サーバーの URL はレジストリ URL と同じです。 しかし独自に立ち上げたサーバー環境やサードパーティー製のレジストリの場合、Notary サーバーには別の URL を指定する必要があります。 これは以下のようにして行います。

$ export DOCKER_CONTENT_TRUST_SERVER=https://<URL>:<PORT>

独自に立ち上げているサーバー環境において、この変数を設定していないと、以下のようなエラーが発生します。

$ docker trust signer add --key cert.pem jeff registry.example.com/admin/demo
Adding signer "jeff" to registry.example.com/admin/demo...
<...>
Error: trust data missing for remote repository registry.example.com/admin/demo or remote repository not found: timestamp key trust data unavailable.  Has a notary repository been initialized?

$ docker trust inspect registry.example.com/admin/demo --pretty
WARN[0000] Error while downloading remote metadata, using cached timestamp - this might not be the latest version available remotely
<...>

Notary サーバーに対して認証機能を設定済みである場合、あるいは DTR を利用する場合は、Notary サーバーへのデータプッシュの前にログインする必要があります。

$ docker login registry.example.com/user/repo
Username: admin
Password:

Login Succeeded

$ docker trust signer add --key cert.pem jeff registry.example.com/user/repo
Adding signer "jeff" to registry.example.com/user/repo...
Initializing signed repository for registry.example.com/user/repo...
Successfully initialized "registry.example.com/user/repo"
Successfully added signer: jeff to registry.example.com/user/repo

ログインしていなければ、以下のようなメッセージになります。

$ docker trust signer add --key cert.pem jeff registry.example.com/user/repo
Adding signer "jeff" to registry.example.com/user/repo...
Initializing signed repository for registry.example.com/user/repo...
you are not authorized to perform this operation: server returned 401.

Failed to add signer to: registry.example.com/user/repo

Notary クライアントの設定

DCT にはさらに高度な機能があって、これを利用するためには Notary CLI が必要になります。 Notary CLI のインストールと設定は以下のようにします。

  1. クライアント をダウンロードし、パス上に配置して利用できるようにします。

  2. ~/.notary/config.jsonに設定ファイルを生成し、その内容を以下のようにします。

{
  "trust_dir" : "~/.docker/trust",
  "remote_server": {
    "url": "https://registry.example.com",
    "root_ca": "../.docker/ca.pem"
  }
}

上で新たに生成した設定ファイルでは、ローカルの Docker トラストデータの場所と Notary サーバーの URL が定義しています。

Docker コンテントトラストの利用とは別に、Notary を利用する方法に関しては ここ にある Notary CLI ドキュメントを参照してください。

委任鍵ペアの生成

提供者の情報を追加するにあたって必要となるのは、委任鍵 (delegation keys) のペアです。 この鍵は$ docker trustを使ってローカル環境で生成することができ、あるいは認証局により生成することもできます。

Docker トラストを用いた鍵生成

Docker トラストには、委任鍵ペアを生成するビルトインのコマンド$ docker trust generate <name>があります。 このコマンドを実行すると、Docker トラストのローカルな保存場所に、委任鍵ペアの秘密鍵を自動的にロードします。

$ docker trust key generate jeff

Generating key for jeff...
Enter passphrase for new jeff key with ID 9deed25:
Repeat passphrase for new jeff key with ID 9deed25:
Successfully generated and loaded private key. Corresponding public key available: /home/ubuntu/Documents/mytrustdir/jeff.pub

手動での鍵生成

手動によって秘密鍵(RSA か ECDSA)と x509 証明書(公開鍵を含む)を生成する必要がある場合は、ローカルの、あるいは企業保有の認証局を使って openssl や cfssl などのツールを利用します。

以下は、2048 ビットの RSA 鍵を生成する例です(RSA 鍵は最低でも 2048 ビットが必要)。

$ openssl genrsa -out delegation.key 2048

Generating RSA private key, 2048 bit long modulus
....................................................+++
............+++
e is 65537 (0x10001)

delegation.keyは秘密鍵として保持しておきます。 これを使って、タグへのサインを行います。

次に公開鍵を含む x509 証明書を生成する必要があります。 ここから必要となるものが公開鍵です。 以下は CSR (certificate signing request) を生成する例です。

$ openssl req -new -sha256 -key delegation.key -out delegation.csr

Then they can send it to whichever CA you trust to sign certificates, or they can self-sign the certificate (in this example, creating a certificate that is valid for 1 year):

$ openssl x509 -req -sha256 -days 365 -in delegation.csr -signkey delegation.key -out delegation.crt

Then they need to give you delegation.crt, whether it is self-signed or signed by a CA.

最後に Docker トラストのローカルの保存場所に秘密鍵を追加します。

$ docker trust key load delegation.key --name jeff

Loading key from "delegation.key"...
Enter passphrase for new jeff key with ID 8ae710e:
Repeat passphrase for new jeff key with ID 8ae710e:
Successfully imported key from delegation.key

ローカルの委任鍵ペアの確認

Docker トラストのローカルの保存場所にインポートされている鍵は、Notary CLI を利用して一覧表示することができます。

$ notary key list

ROLE       GUN                          KEY ID                                                              LOCATION
----       ---                          ------                                                              --------
root                                    f6c6a4b00fefd8751f86194c7d87a3bede444540eb3378c4a11ce10852ab1f96    /home/ubuntu/.docker/trust/private
jeff                                    9deed251daa1aa6f9d5f9b752847647cf8d705da0763aa5467650d0987ed5306    /home/ubuntu/.docker/trust/private

Notary サーバー上の委任鍵の管理

$ docker trustコマンドを使って Notary サーバーに委任鍵を追加すると、リポジトリにおけるトラストデータは、自動的に初期化されます。 この際にはターゲット鍵とスナップショット鍵も生成され、Notary サーバーが管理できるようにスナップショット鍵をローテートします。 これらの鍵に関する詳細は こちら を参照してください。

リポジトリの初期化にあたっては、ローカルの Notary 標準ルート鍵とそのパスフレーズが必要になります。 まだリポジトリを初期化していない場合は、つまり Notary ルート鍵がないので、$ docker trustコマンドの実行がこれを生成します。

Notary 標準ルート鍵 は、しっかりと保護しバックアップをとっておいてください。

リポジトリの初期化

To upload the first key to a delegation, at the same time initiating a repository, you can use the $ docker trust signer add command. This will add the contributor’s public key to the targets/releases delegation, and create a second targets/<name> delegation.

For DCT the name of the second delegation, in the below example jeff, is there to help you keep track of the owner of the keys. In more advanced use cases of Notary additional delegations are used for hierarchy.

$ docker trust signer add --key cert.pem jeff registry.example.com/admin/demo

Adding signer "jeff" to registry.example.com/admin/demo...
Initializing signed repository for registry.example.com/admin/demo...
Enter passphrase for root key with ID f6c6a4b:
Enter passphrase for new repository key with ID b0014f8:
Repeat passphrase for new repository key with ID b0014f8:
Successfully initialized "registry.example.com/admin/demo"
Successfully added signer: jeff to registry.example.com/admin/demo

You can see which keys have been pushed to the Notary server for each repository with the $ docker trust inspect command.

$ docker trust inspect --pretty registry.example.com/admin/demo

No signatures for registry.example.com/admin/demo


List of signers and their keys for registry.example.com/admin/demo

SIGNER              KEYS
jeff                1091060d7bfd

Administrative keys for registry.example.com/admin/demo

  Repository Key:	b0014f8e4863df2d028095b74efcb05d872c3591de0af06652944e310d96598d
  Root Key:	64d147e59e44870311dd2d80b9f7840039115ef3dfa5008127d769a5f657a5d7

You could also use the Notary CLI to list delegations and keys. Here you can clearly see the keys were attached to targets/releases and targets/jeff.

$ notary delegation list registry.example.com/admin/demo

ROLE                PATHS             KEY IDS                                                             THRESHOLD
----                -----             -------                                                             ---------
targets/jeff        "" <all paths>    1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1    1

targets/releases    "" <all paths>    1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1    1

Adding Additional Signers

Docker Trust allows you to configure multiple delegations per repository, allowing you to manage the lifecycle of delegations. When adding additional delegations with $ docker trust the collaborators key is once again added to the targets/release role.

Note you will need the passphrase for the repository key; this would have been configured when you first initiated the repository.

$ docker trust signer add --key ben.pub ben registry.example.com/admin/demo

Adding signer "ben" to registry.example.com/admin/demo...
Enter passphrase for repository key with ID b0014f8:
Successfully added signer: ben to registry.example.com/admin/demo

Check to prove that there are now 2 delegations (Signer).

$ docker trust inspect --pretty registry.example.com/admin/demo

No signatures for registry.example.com/admin/demo

List of signers and their keys for registry.example.com/admin/demo

SIGNER              KEYS
ben                 afa404703b25
jeff                1091060d7bfd

Administrative keys for registry.example.com/admin/demo

  Repository Key:	b0014f8e4863df2d028095b74efcb05d872c3591de0af06652944e310d96598d
  Root Key:	64d147e59e44870311dd2d80b9f7840039115ef3dfa5008127d769a5f657a5d7

Adding Keys to an Existing Delegation

To support things like key rotation and expiring / retiring keys you can publish multiple contributor keys per delegation. The only prerequisite here is to make sure you use the same the delegation name, in this case jeff. Docker trust will automatically handle adding this new key to targets/releases.

Note you will need the passphrase for the repository key; this would have been configured when you first initiated the repository.

$ docker trust signer add --key cert2.pem jeff registry.example.com/admin/demo

Adding signer "jeff" to registry.example.com/admin/demo...
Enter passphrase for repository key with ID b0014f8:
Successfully added signer: jeff to registry.example.com/admin/demo

Check to prove that the delegation (Signer) now contains multiple Key IDs.

$ docker trust inspect --pretty registry.example.com/admin/demo

No signatures for registry.example.com/admin/demo


List of signers and their keys for registry.example.com/admin/demo

SIGNER              KEYS
jeff                1091060d7bfd, 5570b88df073

Administrative keys for registry.example.com/admin/demo

  Repository Key:	b0014f8e4863df2d028095b74efcb05d872c3591de0af06652944e310d96598d
  Root Key:	64d147e59e44870311dd2d80b9f7840039115ef3dfa5008127d769a5f657a5d7

Removing a Delegation

If you need to remove a delegation, including the contributor keys that are attached to the targets/releases role, you can use the $ docker trust signer remove command.

Note tags that were signed by the removed delegation will need to be resigned by an active delegation

$ docker trust signer remove registry.example.com/admin/demo
Removing signer "ben" from registry.example.com/admin/demo...
Enter passphrase for repository key with ID b0014f8:
Successfully removed ben from registry.example.com/admin/demo

Troubleshooting

1) If you see an error that there are no usable keys in targets/releases, you will need to add additional delegations using docker trust signer add before resigning images.

WARN[0000] role targets/releases has fewer keys than its threshold of 1; it will not be usable until keys are added to it

2) If you have added additional delegations already and are seeing an error message that there are no valid signatures in targest/releases, you will need to resign the targets/releases delegation file with the Notary CLI.

WARN[0000] Error getting targets/releases: valid signatures did not meet threshold for targets/releases

Resigning the delegation file is done with the $ notary witness command

$ notary witness registry.example.com/admin/demo targets/releases --publish

More information on the $ notary witness command can be found here

Removing a Contributor’s Key from a Delegation

As part of rotating keys for a delegation, you may want to remove an individual key but retain the delegation. This can be done with the Notary CLI.

Remember you will have to remove the key from both the targets/releases role and the role specific to that signer targets/<name>.

1) We will need to grab the Key ID from the Notary Server

$ notary delegation list registry.example.com/admin/demo

ROLE                PATHS             KEY IDS                                                             THRESHOLD
----                -----             -------                                                             ---------
targets/jeff        "" <all paths>    8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    1
                                      1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1
targets/releases    "" <all paths>    8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    1
                                      1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1

2) Remove from the targets/releases delegation

$ notary delegation remove registry.example.com/admin/demo targets/releases 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1 --publish

Auto-publishing changes to registry.example.com/admin/demo
Enter username: admin
Enter password:
Enter passphrase for targets key with ID b0014f8:
Successfully published changes for repository registry.example.com/admin/demo

3) Remove from the targets/<name> delegation

$ notary delegation remove registry.example.com/admin/demo targets/jeff 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1 --publish

Removal of delegation role targets/jeff with keys [5570b88df0736c468493247a07e235e35cf3641270c944d0e9e8899922fc6f99], to repository "registry.example.com/admin/demo" staged for next publish.

Auto-publishing changes to registry.example.com/admin/demo
Enter username: admin
Enter password:
Enter passphrase for targets key with ID b0014f8:
Successfully published changes for repository registry.example.com/admin/demo

4) Check the remaining delegation list

$ notary delegation list registry.example.com/admin/demo

ROLE                PATHS             KEY IDS                                                             THRESHOLD
----                -----             -------                                                             ---------
targets/jeff        "" <all paths>    8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    1
targets/releases    "" <all paths>    8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    1

Removing a local Delegation Private Key

As part of rotating delegation keys, you may need to remove a local delegation key from the local Docker trust store. This is done with the Notary CLI, using the $ notary key remove command.

1) We will need to get the Key ID from the local Docker Trust store

$ notary key list

ROLE       GUN                          KEY ID                                                              LOCATION
----       ---                          ------                                                              --------
root                                    f6c6a4b00fefd8751f86194c7d87a3bede444540eb3378c4a11ce10852ab1f96    /home/ubuntu/.docker/trust/private
admin                                   8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    /home/ubuntu/.docker/trust/private
jeff                                    1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1    /home/ubuntu/.docker/trust/private
targets    ...example.com/admin/demo    c819f2eda8fba2810ec6a7f95f051c90276c87fddfc3039058856fad061c009d    /home/ubuntu/.docker/trust/private

2) Remove the key from the local Docker Trust store

$ notary key remove 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1

Are you sure you want to remove 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1 (role jeff) from /home/ubuntu/.docker/trust/private?  (yes/no)  y

Deleted 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1 (role jeff) from /home/ubuntu/.docker/trust/private.

Removing all trust data from a Repository

You can remove all trust data from a repository, including repository, target, snapshot and all delegations keys using the Notary CLI.

This is often required by a container registry before a particular repository can be deleted.

$ notary delete registry.example.com/admin/demo --remote

Deleting trust data for repository registry.example.com/admin/demo
Enter username: admin
Enter password:
Successfully deleted local and remote trust data for repository registry.example.com/admin/demo

$ docker trust inspect --pretty registry.example.com/admin/demo

No signatures or cannot access registry.example.com/admin/demo
trust, security, delegations, keys, repository