4.2. Certificate Transparency ログ署名者アギのローテーション
シャーディング機能を使用してログツリーをフリーズし、新しい署名者鍵を使用して新しいログツリーを作成することにより、Certificate Transparency (CT) ログ署名者鍵をプロアクティブにローテーションできます。この手順では、古い CT ログ署名者鍵を期限切れにし、Red Hat Trusted Artifact Signer (RHTAS) が使用する新しい署名者鍵に置き換える手順を説明します。古い CT ログ署名者鍵の有効期限が切れても、古い鍵で署名されたアーティファクトを検証することは可能です。
前提条件
- Red Hat OpenShift Container Platform 上で実行される RHTAS Operator をインストールする。
- Securesign インスタンスを実行する。
-
oc
、openssl
、cosign
バイナリーがインストールされたワークステーション。
手順
OpenShift クラスターからワークステーションに
tuftool
バイナリーをダウンロードします。重要tuftool
バイナリーは Linux オペレーティングシステムでのみ使用できます。- ホームページから ? アイコンをクリックして、Command line tools をクリックし、tuftool ダウンロードセクションに移動し、プラットフォームのリンクをクリックします。
ワークステーションでターミナルを開き、バイナリー
.gz
ファイルを展開し、実行ビットを設定します。例
$ gunzip tuftool-amd64.gz $ chmod +x tuftool-amd64
バイナリーを
$PATH
環境内の場所に移動し、名前を変更します。例
$ sudo mv tuftool-amd64 /usr/local/bin/tuftool
コマンドラインから OpenShift にログインします。
構文
oc login --token=TOKEN --server=SERVER_URL_AND_PORT
例
$ oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443
注記OpenShift Web コンソールからコマンドラインで使用するログイントークンと URL を確認できます。OpenShift Web コンソールにログインします。ユーザー名をクリックし、Copy login command をクリックします。入力を求められた場合はユーザー名とパスワードをもう一度入力し、Display Token をクリックしてコマンドを表示します。
RHTAS プロジェクトに切り替えます。
例
$ oc project trusted-artifact-signer
現在の CT ログ設定と鍵のバックアップを作成します。
例
$ export SERVER_CONFIG_NAME=$(oc get ctlog -o jsonpath='{.items[0].status.serverConfigRef.name}') $ oc get secret $SERVER_CONFIG_NAME -o jsonpath="{.data.config}" | base64 --decode > config.txtpb $ oc get secret $SERVER_CONFIG_NAME -o jsonpath="{.data.fulcio-0}" | base64 --decode > fulcio-0.pem $ oc get secret $SERVER_CONFIG_NAME -o jsonpath="{.data.private}" | base64 --decode > private.pem $ oc get secret $SERVER_CONFIG_NAME -o jsonpath="{.data.public}" | base64 --decode > public.pem
現在のツリー識別子を取得します。
例
$ export OLD_TREE_ID=$(oc get ctlog -o jsonpath='{.items[0].status.treeID}')
ログツリーを
DRAINING
状態に設定します。例
$ oc run --image registry.redhat.io/rhtas/updatetree-rhel9:1.1.0 --restart=Never --attach=true --rm=true -q -- updatetree --admin_server=trillian-logserver:8091 --tree_id=${OLD_TREE_ID} --tree_state=DRAINING
ツリーログは、ドレイン中に新しいエントリーを受け入れません。キューが空になるまで待ちます。
重要次のステップに進む前に、キューが空になるまで待つ必要があります。ドレイン中にリーフがまだ統合中の場合、このプロセス中にログツリーをフリーズすると、ログパスが最大マージ遅延 (MMD) を超える可能性があります。
キューが完全に空になったら、ログをフリーズします。
例
$ oc run --image registry.redhat.io/rhtas/updatetree-rhel9:1.1.0 --restart=Never --attach=true --rm=true -q -- updatetree --admin_server=trillian-logserver:8091 --tree_id=${OLD_TREE_ID} --tree_state=FROZEN
新しい Merkle ツリーを作成し、新しいツリー識別子を取得します。
例
$ export NEW_TREE_ID=$(kubectl run createtree --image registry.redhat.io/rhtas/createtree-rhel9:1.1.0 --restart=Never --attach=true --rm=true -q -- -logtostderr=false --admin_server=trillian-logserver:8091 --display_name=ctlog-tree)
新しい証明書と新しい公開鍵および秘密鍵を生成します。
例
$ openssl ecparam -genkey -name prime256v1 -noout -out new-ctlog.pem $ openssl ec -in new-ctlog.pem -pubout -out new-ctlog-public.pem $ openssl ec -in new-ctlog.pem -out new-ctlog.pass.pem -des3 -passout pass:"CHANGE_ME"
CHANGE_ME は、新しいパスワードに置き換えます。
重要証明書と新しい鍵には一意のファイル名が必要です。
CT ログ設定を更新します。
-
config.txtpb
ファイルを開いて編集します。 ログをフリーズした場合、フリーズされたログエントリーに
not_after_limit
フィールドを追加し、接頭辞値を一意の名前に変更し、秘密鍵への古いパスをctfe-keys/private-0
に置き換えます。例
... log_configs:{ # frozen log config:{ log_id:2066075212146181968 prefix:"trusted-artifact-signer-0" roots_pem_file:"/ctfe-keys/fulcio-0" private_key:{[type.googleapis.com/keyspb.PEMKeyFile]:{path:"/ctfe-keys/private-0" password:"Example123"}} public_key:{der:"0Y0\x13\x06\x07*\x86H\xce=\x02\x01\x06\x08*\x86H\xce=\x03\x01\x07\x03B\x00\x04)'.\xffUJ\xe2s)\xefR\x8a\xfcO\xdcewȶy\xa7\x9d<\x13\xb0\x1c\x99\x96\xe4'\xe3v\x07:\xc8I+\x08J\x9d\x8a\xed\x06\xe4\xaeI:q\x98\xf4\xbc<o4VD\x0cr\xf9\x9c\xecxT\x84"} not_after_limit:{seconds:1728056285 nanos:012111000} ext_key_usages:"CodeSigning" log_backend_name:"trillian" }
注記date +%s
、およびdate +%N
のコマンドを実行すると、秒とナノ秒の現在の時刻値を取得できます。重要not_after_limit
フィールドは、フリーズされたログだけのタイムスタンプ範囲の終了を定義します。この時点以降の証明書は、このログに含めることができなくなります。-
凍結されたログ
config
ブロックをコピーして貼り付け、設定ファイルに追加して新しいエントリーを作成します。 新しい
config
ブロック内の次の行を変更します。log_id
を新しいツリー識別子に設定し、prefix
をtrusted-artifact-signer
、private_key
パスをctfe-keys/private
に変更します。public_key
行は削除し、not_after_limit
はnot_after_start
に変更して、タイムスタンプの範囲を設定します。例
... log_configs:{ # frozen log ... # new active log config:{ log_id: NEW_TREE_ID prefix:"trusted-artifact-signer" roots_pem_file:"/ctfe-keys/fulcio-0" private_key:{[type.googleapis.com/keyspb.PEMKeyFile]:{path:"ctfe-keys/private" password:"CHANGE_ME"}} ext_key_usages:"CodeSigning" not_after_start:{seconds:1713201754 nanos:155663000} log_backend_name:"trillian" }
NEW_TREE_ID を追加し、CHANGE_ME は、新しい秘密鍵のパスワードに置き換えます。ここでのパスワードは、新しい秘密鍵と公開鍵を生成するために使用したパスワードと同じものに指定する必要があります。
重要not_after_start
フィールドは、タイムスタンプ範囲の開始 (開始地点を含む) を定義します。これは、この時点でログが証明書の受け入れを開始することを意味します。
-
新しいシークレットリソースを作成します。
例
$ oc create secret generic ctlog-config \ --from-file=config=config.txtpb \ --from-file=private=new-ctlog.pass.pem \ --from-file=public=new-ctlog-public.pem \ --from-file=fulcio-0=fulcio-0.pem \ --from-file=private-0=private.pem \ --from-file=public-0=public.pem \ --from-literal=password=CHANGE_ME
CHANGE_ME は、新しい秘密鍵のパスワードに置き換えます。
新しい CT ログ公開鍵を使用するように The Update Framework (TUF) サービスを設定します。
シェル環境を設定します。
例
$ export WORK="${HOME}/trustroot-example" $ export ROOT="${WORK}/root/root.json" $ export KEYDIR="${WORK}/keys" $ export INPUT="${WORK}/input" $ export TUF_REPO="${WORK}/tuf-repo" $ export TUF_SERVER_POD="$(oc get pod --selector=app.kubernetes.io/component=tuf --no-headers -o custom-columns=":metadata.name")"
一時的な TUF ディレクトリー構造を作成します。
例
$ mkdir -p "${WORK}/root/" "${KEYDIR}" "${INPUT}" "${TUF_REPO}"
TUF コンテンツを一時的な TUF ディレクトリー構造にダウンロードします。
例
$ oc extract --to "${KEYDIR}/" secret/tuf-root-keys $ oc cp "${TUF_SERVER_POD}:/var/www/html" "${TUF_REPO}" $ cp "${TUF_REPO}/root.json" "${ROOT}"
アクティブな CT ログの公開鍵ファイル名を見つけます。ローカル TUF リポジトリー内の最新のターゲットファイル (例:
1.targets.json
) を開きます。このターゲットファイルには、アクティブな CT ログ公開鍵ファイル名 (例:ctfe.pub
) が含まれます。次のアクティブな CT ログ公開鍵ファイル名で環境変数を設定します。例
$ export ACTIVE_CTFE_NAME=ctfe.pub
OpenShift からアクティブな CT ログ公開鍵を抽出します。
例
$ oc get secret $(oc get ctlog securesign-sample -o jsonpath='{.status.publicKeyRef.name}') -o jsonpath='{.data.public}' | base64 -d > $ACTIVE_CTFE_NAME
古い CT ログ署名者鍵を期限切れにします。
例
$ tuftool rhtas \ --root "${ROOT}" \ --key "${KEYDIR}/snapshot.pem" \ --key "${KEYDIR}/targets.pem" \ --key "${KEYDIR}/timestamp.pem" \ --set-ctlog-target "$ACTIVE_CTFE_NAME" \ --ctlog-uri "https://ctlog.rhtas" \ --ctlog-status "Expired" \ --outdir "${TUF_REPO}" \ --metadata-url "file://${TUF_REPO}"
新しい CT ログ署名者鍵を追加します。
例
$ tuftool rhtas \ --root "${ROOT}" \ --key "${KEYDIR}/snapshot.pem" \ --key "${KEYDIR}/targets.pem" \ --key "${KEYDIR}/timestamp.pem" \ --set-ctlog-target "new-ctlog-public.pem" \ --ctlog-uri "https://ctlog.rhtas" \ --outdir "${TUF_REPO}" \ --metadata-url "file://${TUF_REPO}"
これらの変更を TUF サーバーにアップロードします。
例
$ oc rsync "${TUF_REPO}/" "${TUF_SERVER_POD}:/var/www/html"
作業ディレクトリーを削除します。
例
$ rm -r $WORK
新しいツリー識別子を使用して Securesign CT ログ設定を更新します。
例
$ read -r -d '' SECURESIGN_PATCH <<EOF [ { "op": "replace", "path": "/spec/ctlog/serverConfigRef", "value": {"name": "ctlog-config"} }, { "op": "replace", "path": "/spec/ctlog/treeID", "value": $NEW_TREE_ID }, { "op": "replace", "path": "/spec/ctlog/privateKeyRef", "value": {"name": "ctlog-config", "key": "private"} }, { "op": "replace", "path": "/spec/ctlog/privateKeyPasswordRef", "value": {"name": "ctlog-config", "key": "password"} }, { "op": "replace", "path": "/spec/ctlog/publicKeyRef", "value": {"name": "ctlog-config", "key": "public"} } ] EOF
Securesign インスタンスにパッチを適用します。
例
$ oc patch Securesign securesign-sample --type='json' -p="$SECURESIGN_PATCH"
CT ログサーバーが再びデプロイされるまで待ちます。
例
$ oc wait pod -l app.kubernetes.io/name=ctlog --for=condition=Ready
更新された TUF 設定で
cosign
設定を更新します。例
$ cosign initialize --mirror=$TUF_URL --root=$TUF_URL/root.json
これで、新しい CT ログ署名者鍵を使用してアーティファクトに署名し、検証する準備が整いました。