Chapter 4. Rotate your certificates and keys As a systems administrator, you can proactively rotate the certificates and signer keys used by the Red Hat Trusted Artifact Signer (RHTAS) service running on Red Hat OpenShift. Rotating your keys regularly can prevent key tampering, and theft. These procedures guide you through expiring your old certificates and signer keys, and replacing them with a new certificate and signer key for the underlying services that make up RHTAS. You can rotate keys and certificates for the following services: Rekor Certificate Transparency log Fulcio Timestamp Authority 4.1. Rotating the Rekor signer key You can proactively rotate Rekor's signer key by using the sharding feature to freeze the log tree, and create a new log tree with a new signer key. This procedure walks you through expiring your old Rekor signer key, and replacing it with a new signer key for Red Hat Trusted Artifact Signer (RHTAS) to use. Expiring your old Rekor signer key still allows you to verify artifacts signed by the old key. Important This procedure requires downtime to the Rekor service. Prerequisites Installation of the RHTAS operator running on Red Hat OpenShift Container Platform. A running Securesign instance. A workstation with the oc , openssl , and cosign binaries installed. Procedure Download the rekor-cli binary from the OpenShift cluster to your workstation. Login to the OpenShift web console. From the home page, click the ? icon, click Command line tools , go to the rekor-cli download section, and click the link for your platform. Open a terminal on your workstation, decompress the binary .gz file, and set the execute bit: Example USD gunzip rekor-cli-amd64.gz USD chmod +x rekor-cli-amd64 Move and rename the binary to a location within your USDPATH environment: Example USD sudo mv rekor-cli-amd64 /usr/local/bin/rekor-cli Download the tuftool binary from the OpenShift cluster to your workstation. Important The tuftool binary is only available for Linux operating systems. From the home page, click the ? icon, click Command line tools , go to the tuftool download section, and click the link for your platform. From a terminal on your workstation, decompress the binary .gz file, and set the execute bit: Example USD gunzip tuftool-amd64.gz USD chmod +x tuftool-amd64 Move and rename the binary to a location within your USDPATH environment: Example USD sudo mv tuftool-amd64 /usr/local/bin/tuftool Log in to OpenShift from the command line: Syntax oc login --token= TOKEN --server= SERVER_URL_AND_PORT Example USD oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443 Note You can find your login token and URL for use on the command line from the OpenShift web console. Log in to the OpenShift web console. Click your user name, and click Copy login command . Offer your user name and password again, if asked, and click Display Token to view the command. Switch to the RHTAS project: Example USD oc project trusted-artifact-signer Get the Rekor URL: Example USD export REKOR_URL=USD(oc get rekor -o jsonpath='{.items[0].status.url}') Get the log tree identifier for the active shard: Example USD export OLD_TREE_ID=USD(rekor-cli loginfo --rekor_server USDREKOR_URL --format json | jq -r .TreeID) Scale down the Rekor instance, and set the log tree to the DRAINING state: Example USD 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=USD{OLD_TREE_ID} --tree_state=DRAINING While draining, the tree log will not accept any new entries. Watch and wait for the queue to empty. Important You must wait for the queues to be empty before proceeding to the step. If leaves are still integrating while draining, then freezing the log tree during this process can cause the log path to exceed the maximum merge delay (MMD). Freeze the log tree: Example USD 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=USD{OLD_TREE_ID} --tree_state=FROZEN Get the length of the frozen log tree: Example USD export OLD_SHARD_LENGTH=USD(rekor-cli loginfo --rekor_server USDREKOR_URL --format json | jq -r .ActiveTreeSize) Get Rekor's public key for the old shard: Example USD export OLD_PUBLIC_KEY=USD(curl -s USDREKOR_URL/api/v1/log/publicKey | base64 | tr -d '\n') Create a new log tree: Example USD export NEW_TREE_ID=USD(oc 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=rekor-tree) Now you have two log trees, one frozen tree, and a new tree that will become the active shard. Create a new private key: Example USD openssl ecparam -genkey -name secp384r1 -noout -out new-rekor.pem Important The new key must have a unique file name. Create a new secret resource with the new signer key: Example USD oc create secret generic rekor-signer-key --from-file=private=new-rekor.pem Update the Securesign Rekor configuration with the new tree identifier and the old sharding information: Example USD read -r -d '' SECURESIGN_PATCH_1 <<EOF [ { "op": "replace", "path": "/spec/rekor/treeID", "value": USDNEW_TREE_ID }, { "op": "add", "path": "/spec/rekor/sharding/-", "value": { "treeID": USDOLD_TREE_ID, "treeLength": USDOLD_SHARD_LENGTH, "encodedPublicKey": "USDOLD_PUBLIC_KEY" } }, { "op": "replace", "path": "/spec/rekor/signer/keyRef", "value": {"name": "rekor-signer-key", "key": "private"} } ] EOF Note If you have /spec/rekor/signer/keyPasswordRef set with a value, then create a new separate update to remove it: Example USD read -r -d '' SECURESIGN_PATCH_2 <<EOF [ { "op": "remove", "path": "/spec/rekor/signer/keyPasswordRef" } ] EOF Apply this update after applying the first update. Update the Securesign instance: Example USD oc patch Securesign securesign-sample --type='json' -p="USDSECURESIGN_PATCH_1" Wait for the Rekor server to redeploy with the new signer key: Example USD oc wait pod -l app.kubernetes.io/name=rekor-server --for=condition=Ready Get the new public key: Example USD export NEW_KEY_NAME=new-rekor.pub USD curl USD(oc get rekor -o jsonpath='{.items[0].status.url}')/api/v1/log/publicKey -o USDNEW_KEY_NAME Configure The Update Framework (TUF) service to use the new Rekor public key. Set up your shell environment: Example USD export WORK="USD{HOME}/trustroot-example" USD export ROOT="USD{WORK}/root/root.json" USD export KEYDIR="USD{WORK}/keys" USD export INPUT="USD{WORK}/input" USD export TUF_REPO="USD{WORK}/tuf-repo" USD export TUF_SERVER_POD="USD(oc get pod --selector=app.kubernetes.io/component=tuf --no-headers -o custom-columns=":metadata.name")" Create a temporary TUF directory structure: Example USD mkdir -p "USD{WORK}/root/" "USD{KEYDIR}" "USD{INPUT}" "USD{TUF_REPO}" Download the TUF contents to the temporary TUF directory structure: Example USD oc extract --to "USD{KEYDIR}/" secret/tuf-root-keys USD oc cp "USD{TUF_SERVER_POD}:/var/www/html" "USD{TUF_REPO}" USD cp "USD{TUF_REPO}/root.json" "USD{ROOT}" Find the active Rekor signer key file name. Open the latest target file, for example, 1.target.json , within the local TUF repository. In this file you will find the active Rekor signer key file name, for example, rekor.pub . Set an environment variable with this active Rekor signer key file name: Example USD export ACTIVE_KEY_NAME=rekor.pub Update the Rekor signer key with the old public key: Example USD echo USDOLD_PUBLIC_KEY | base64 -d > USDACTIVE_KEY_NAME Expire the old Rekor signer key: Example USD tuftool rhtas \ --root "USD{ROOT}" \ --key "USD{KEYDIR}/snapshot.pem" \ --key "USD{KEYDIR}/targets.pem" \ --key "USD{KEYDIR}/timestamp.pem" \ --set-rekor-target "USD{ACTIVE_KEY_NAME}" \ --rekor-uri "https://rekor.rhtas" \ --rekor-status "Expired" \ --outdir "USD{TUF_REPO}" \ --metadata-url "file://USD{TUF_REPO}" Add the new Rekor signer key: Example USD tuftool rhtas \ --root "USD{ROOT}" \ --key "USD{KEYDIR}/snapshot.pem" \ --key "USD{KEYDIR}/targets.pem" \ --key "USD{KEYDIR}/timestamp.pem" \ --set-rekor-target "USD{NEW_KEY_NAME}" \ --rekor-uri "https://rekor.rhtas" \ --outdir "USD{TUF_REPO}" \ --metadata-url "file://USD{TUF_REPO}" Upload these changes to the TUF server: Example USD oc rsync "USD{TUF_REPO}/" "USD{TUF_SERVER_POD}:/var/www/html" Delete the working directory: Example USD rm -r USDWORK Update the cosign configuration with the updated TUF configuration: Example USD cosign initialize --mirror=USDTUF_URL --root=USDTUF_URL/root.json Now, you are ready to sign and verify your artifacts with the new Rekor signer key. 4.2. Rotating the Certificate Transparency log signer key You can proactively rotate Certificate Transparency (CT) log signer key by using the sharding feature to freeze the log tree, and create a new log tree with a new signer key. This procedure walks you through expiring your old CT log signer key, and replacing it with a new signer key for Red Hat Trusted Artifact Signer (RHTAS) to use. Expiring your old CT log signer key still allows you to verify artifacts signed by the old key. Prerequisites Installation of the RHTAS operator running on Red Hat OpenShift Container Platform. A running Securesign instance. A workstation with the oc , openssl , and cosign binaries installed. Procedure Download the tuftool binary from the OpenShift cluster to your workstation. Important The tuftool binary is only available for Linux operating systems. From the home page, click the ? icon, click Command line tools , go to the tuftool download section, and click the link for your platform. Open a terminal on your workstation, decompress the binary .gz file, and set the execute bit: Example USD gunzip tuftool-amd64.gz USD chmod +x tuftool-amd64 Move and rename the binary to a location within your USDPATH environment: Example USD sudo mv tuftool-amd64 /usr/local/bin/tuftool Log in to OpenShift from the command line: Syntax oc login --token= TOKEN --server= SERVER_URL_AND_PORT Example USD oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443 Note You can find your login token and URL for use on the command line from the OpenShift web console. Log in to the OpenShift web console. Click your user name, and click Copy login command . Offer your user name and password again, if asked, and click Display Token to view the command. Switch to the RHTAS project: Example USD oc project trusted-artifact-signer Make a backup of the current CT log configuration, and keys: Example USD export SERVER_CONFIG_NAME=USD(oc get ctlog -o jsonpath='{.items[0].status.serverConfigRef.name}') USD oc get secret USDSERVER_CONFIG_NAME -o jsonpath="{.data.config}" | base64 --decode > config.txtpb USD oc get secret USDSERVER_CONFIG_NAME -o jsonpath="{.data.fulcio-0}" | base64 --decode > fulcio-0.pem USD oc get secret USDSERVER_CONFIG_NAME -o jsonpath="{.data.private}" | base64 --decode > private.pem USD oc get secret USDSERVER_CONFIG_NAME -o jsonpath="{.data.public}" | base64 --decode > public.pem Capture the current tree identifier: Example USD export OLD_TREE_ID=USD(oc get ctlog -o jsonpath='{.items[0].status.treeID}') Set the log tree to the DRAINING state: Example USD 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=USD{OLD_TREE_ID} --tree_state=DRAINING While draining, the tree log will not accept any new entries. Watch and wait for the queue to empty. Important You must wait for the queues to be empty before proceeding to the step. If leaves are still integrating while draining, then freezing the log tree during this process can cause the log path to exceed the maximum merge delay (MMD). Once the queue has been fully drained, freeze the log: Example USD 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=USD{OLD_TREE_ID} --tree_state=FROZEN Create a new Merkle tree, and capture the new tree identifier: Example USD export NEW_TREE_ID=USD(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) Generate a new certificate, along with new public and private keys: Example USD openssl ecparam -genkey -name prime256v1 -noout -out new-ctlog.pem USD openssl ec -in new-ctlog.pem -pubout -out new-ctlog-public.pem USD openssl ec -in new-ctlog.pem -out new-ctlog.pass.pem -des3 -passout pass:" CHANGE_ME " Replace CHANGE_ME with a new password. Important The certificate and new keys must have unique file names. Update the CT log configuration. Open the config.txtpb file for editing. For the frozen log, add the not_after_limit field to the frozen log entry, rename the prefix value to a unique name, and replace the old path to the private key with ctfe-keys/private-0 : Example Note You can get the current time value for seconds and nanoseconds, by running the following commands: date +%s , and date +%N . Important The not_after_limit field defines the end of the timestamp range for the frozen log only. Certificates beyond this point in time are no longer accepted for inclusion in this log. Copy and paste the frozen log config block, appending it to the configuration file to create a new entry. Change the following lines in the new config block. Set the log_id to the new tree identifier, change the prefix to trusted-artifact-signer , change the private_key path to ctfe-keys/private , remove the public_key line, and change not_after_limit to not_after_start and set the timestamp range: Example Add the NEW_TREE_ID , and replace CHANGE_ME with the new private key password. The password here must match the password used for generating the new private and public keys. Important The not_after_start field defines the beginning of the timestamp range inclusively. This means the log will start accepting certificates at this point in time. Create a new secret resource: Example USD 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 Replace CHANGE_ME with the new private key password. Configure The Update Framework (TUF) service to use the new CT log public key. Set up your shell environment: Example USD export WORK="USD{HOME}/trustroot-example" USD export ROOT="USD{WORK}/root/root.json" USD export KEYDIR="USD{WORK}/keys" USD export INPUT="USD{WORK}/input" USD export TUF_REPO="USD{WORK}/tuf-repo" USD export TUF_SERVER_POD="USD(oc get pod --selector=app.kubernetes.io/component=tuf --no-headers -o custom-columns=":metadata.name")" Create a temporary TUF directory structure: Example USD mkdir -p "USD{WORK}/root/" "USD{KEYDIR}" "USD{INPUT}" "USD{TUF_REPO}" Download the TUF contents to the temporary TUF directory structure: Example USD oc extract --to "USD{KEYDIR}/" secret/tuf-root-keys USD oc cp "USD{TUF_SERVER_POD}:/var/www/html" "USD{TUF_REPO}" USD cp "USD{TUF_REPO}/root.json" "USD{ROOT}" Find the active CT log public key file name. Open the latest target file, for example, 1.targets.json , within the local TUF repository. In this target file you will find the active CT log public key file name, for example, ctfe.pub . Set an environment variable with this active CT log public key file name: Example USD export ACTIVE_CTFE_NAME=ctfe.pub Extract the active CT log public key from OpenShift: Example USD oc get secret USD(oc get ctlog securesign-sample -o jsonpath='{.status.publicKeyRef.name}') -o jsonpath='{.data.public}' | base64 -d > USDACTIVE_CTFE_NAME Expire the old CT log signer key: Example USD tuftool rhtas \ --root "USD{ROOT}" \ --key "USD{KEYDIR}/snapshot.pem" \ --key "USD{KEYDIR}/targets.pem" \ --key "USD{KEYDIR}/timestamp.pem" \ --set-ctlog-target "USDACTIVE_CTFE_NAME" \ --ctlog-uri "https://ctlog.rhtas" \ --ctlog-status "Expired" \ --outdir "USD{TUF_REPO}" \ --metadata-url "file://USD{TUF_REPO}" Add the new CT log signer key: Example USD tuftool rhtas \ --root "USD{ROOT}" \ --key "USD{KEYDIR}/snapshot.pem" \ --key "USD{KEYDIR}/targets.pem" \ --key "USD{KEYDIR}/timestamp.pem" \ --set-ctlog-target "new-ctlog-public.pem" \ --ctlog-uri "https://ctlog.rhtas" \ --outdir "USD{TUF_REPO}" \ --metadata-url "file://USD{TUF_REPO}" Upload these changes to the TUF server: Example USD oc rsync "USD{TUF_REPO}/" "USD{TUF_SERVER_POD}:/var/www/html" Delete the working directory: Example USD rm -r USDWORK Update the Securesign CT log configuration with the new tree identifier: Example USD read -r -d '' SECURESIGN_PATCH <<EOF [ { "op": "replace", "path": "/spec/ctlog/serverConfigRef", "value": {"name": "ctlog-config"} }, { "op": "replace", "path": "/spec/ctlog/treeID", "value": USDNEW_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 Patch the Securesign instance: Example USD oc patch Securesign securesign-sample --type='json' -p="USDSECURESIGN_PATCH" Wait for the CT log server to redeploy: Example USD oc wait pod -l app.kubernetes.io/name=ctlog --for=condition=Ready Update the cosign configuration with the updated TUF configuration: Example USD cosign initialize --mirror=USDTUF_URL --root=USDTUF_URL/root.json Now, you are ready to sign and verify your artifacts with the new CT log signer key. 4.3. Rotating the Fulcio certificate You can proactively rotate the certificate used by the Fulcio service. This procedure walks you through expiring your old Fulcio certificate, and replacing it with a new certificate for Red Hat Trusted Artifact Signer (RHTAS) to use. Expiring your old Fulcio certificate still allows you to verify artifacts signed by the old certificate. Prerequisites Installation of the RHTAS operator running on Red Hat OpenShift Container Platform. A running Securesign instance. A workstation with the oc , openssl , and cosign binaries installed. Procedure Download the tuftool binary from the OpenShift cluster to your workstation. Important The tuftool binary is only available for Linux operating systems. From the home page, click the ? icon, click Command line tools , go to the tuftool download section, and click the link for your platform. Open a terminal on your workstation, decompress the binary .gz file, and set the execute bit: Example USD gunzip tuftool-amd64.gz USD chmod +x tuftool-amd64 Move and rename the binary to a location within your USDPATH environment: Example USD sudo mv tuftool-amd64 /usr/local/bin/tuftool Log in to OpenShift from the command line: Syntax oc login --token= TOKEN --server= SERVER_URL_AND_PORT Example USD oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443 Note You can find your login token and URL for use on the command line from the OpenShift web console. Log in to the OpenShift web console. Click your user name, and click Copy login command . Offer your user name and password again, if asked, and click Display Token to view the command. Switch to the RHTAS project: Example USD oc project trusted-artifact-signer Generate a new certificate, along with new public and private keys: Example USD openssl ecparam -genkey -name prime256v1 -noout -out new-fulcio.pem USD openssl ec -in new-fulcio.pem -pubout -out new-fulcio-public.pem USD openssl ec -in new-fulcio.pem -out new-fulcio.pass.pem -des3 -passout pass:" CHANGE_ME " USD openssl req -new -x509 -key new-fulcio.pass.pem -out new-fulcio.cert.pem Replace CHANGE_ME with a new password. Important The certificate and new keys must have unique file names. Create a new secret: Example USD oc create secret generic fulcio-config \ --from-file=private=new-fulcio.pass.pem \ --from-file=cert=new-fulcio.cert.pem \ --from-literal=password= CHANGE_ME Replace CHANGE_ME with a new password. Note The password here must match the password used for generating the new private and public keys. Configure The Update Framework (TUF) service to use the new Fulcio certificate. Set up your shell environment: Example USD export WORK="USD{HOME}/trustroot-example" USD export ROOT="USD{WORK}/root/root.json" USD export KEYDIR="USD{WORK}/keys" USD export INPUT="USD{WORK}/input" USD export TUF_REPO="USD{WORK}/tuf-repo" USD export TUF_SERVER_POD="USD(oc get pod --selector=app.kubernetes.io/component=tuf --no-headers -o custom-columns=":metadata.name")" Create a temporary TUF directory structure: Example USD mkdir -p "USD{WORK}/root/" "USD{KEYDIR}" "USD{INPUT}" "USD{TUF_REPO}" Download the TUF contents to the temporary TUF directory structure: Example USD oc extract --to "USD{KEYDIR}/" secret/tuf-root-keys USD oc cp "USD{TUF_SERVER_POD}:/var/www/html" "USD{TUF_REPO}" USD cp "USD{TUF_REPO}/root.json" "USD{ROOT}" Find the active Fulcio certificate file name. Open the latest target file, for example, 1.targets.json , within the local TUF repository. In this file you will find the active Fulcio certificate file name, for example, fulcio_v1.crt.pem . Set an environment variable with this active Fulcio certificate file name: Example USD export ACTIVE_CERT_NAME=fulcio_v1.crt.pem Extract the active Fulico certificate from OpenShift: Example USD oc get secret USD(oc get fulcio securesign-sample -o jsonpath='{.status.certificate.caRef.name}') -o jsonpath='{.data.cert}' | base64 -d > USDACTIVE_CERT_NAME Expire the old certificate: Example USD tuftool rhtas \ --root "USD{ROOT}" \ --key "USD{KEYDIR}/snapshot.pem" \ --key "USD{KEYDIR}/targets.pem" \ --key "USD{KEYDIR}/timestamp.pem" \ --set-fulcio-target "USDACTIVE_CERT_NAME" \ --fulcio-uri "https://fulcio.rhtas" \ --fulcio-status "Expired" \ --outdir "USD{TUF_REPO}" \ --metadata-url "file://USD{TUF_REPO}" Add the new Fulcio certificate: Example USD tuftool rhtas \ --root "USD{ROOT}" \ --key "USD{KEYDIR}/snapshot.pem" \ --key "USD{KEYDIR}/targets.pem" \ --key "USD{KEYDIR}/timestamp.pem" \ --set-fulcio-target "new-fulcio.cert.pem" \ --fulcio-uri "https://fulcio.rhtas" \ --outdir "USD{TUF_REPO}" \ --metadata-url "file://USD{TUF_REPO}" Upload these changes to the TUF server: Example USD oc rsync "USD{TUF_REPO}/" "USD{TUF_SERVER_POD}:/var/www/html" Delete the working directory: Example USD rm -r USDWORK Update the Securesign Fulcio configuration: Example USD read -r -d '' SECURESIGN_PATCH <<EOF [ { "op": "replace", "path": "/spec/fulcio/certificate/privateKeyRef", "value": {"name": "fulcio-config", "key": "private"} }, { "op": "replace", "path": "/spec/fulcio/certificate/privateKeyPasswordRef", "value": {"name": "fulcio-config", "key": "password"} }, { "op": "replace", "path": "/spec/fulcio/certificate/caRef", "value": {"name": "fulcio-config", "key": "cert"} }, { "op": "replace", "path": "/spec/ctlog/rootCertificates", "value": [{"name": "fulcio-config", "key": "cert"}] } ] EOF Patch the Securesign instance: Example USD oc patch Securesign securesign-sample --type='json' -p="USDSECURESIGN_PATCH" Wait for the Fulcio server to redeploy: Example USD oc wait pod -l app.kubernetes.io/name=fulcio-server --for=condition=Ready USD oc wait pod -l app.kubernetes.io/name=ctlog --for=condition=Ready Update the cosign configuration with the updated TUF configuration: Example USD cosign initialize --mirror=USDTUF_URL --root=USDTUF_URL/root.json Now, you are ready to sign and verify your artifacts with the new Fulcio certificate. 4.4. Rotating the Timestamp Authority signer key and certificate chain You can proactively rotate the Timestamp Authority (TSA) signer key and certificate chain. This procedure walks you through expiring your old TSA signer key and certificate chain, and replacing them with a new ones for Red Hat Trusted Artifact Signer (RHTAS) to use. Expiring your old TSA signer key and certificate chain still allows you to verify artifacts signed by the old key and certificate chain. Prerequisites Installation of the RHTAS operator running on Red Hat OpenShift Container Platform. A running Securesign instance. A workstation with the oc and openssl binaries installed. Procedure Download the tuftool binary from the OpenShift cluster to your workstation. Important The tuftool binary is only available for Linux operating systems. From the home page, click the ? icon, click Command line tools , go to the tuftool download section, and click the link for your platform. Open a terminal on your workstation, decompress the binary .gz file, and set the execute bit: Example USD gunzip tuftool-amd64.gz USD chmod +x tuftool-amd64 Move and rename the binary to a location within your USDPATH environment: Example USD sudo mv tuftool-amd64 /usr/local/bin/tuftool Log in to OpenShift from the command line: Syntax oc login --token= TOKEN --server= SERVER_URL_AND_PORT Example USD oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443 Note You can find your login token and URL for use on the command line from the OpenShift web console. Log in to the OpenShift web console. Click your user name, and click Copy login command . Offer your user name and password again, if asked, and click Display Token to view the command. Switch to the RHTAS project: Example USD oc project trusted-artifact-signer Generate a new certificate chain, and a new signer key. Important The new certificate and keys must have unique file names. Create a temporary working directory: Example USD mkdir certs && cd certs Create the root certificate authority (CA) private key, and set a password: Example USD openssl req -x509 -newkey rsa:2048 -days 365 -sha256 -nodes \ -keyout rootCA.key.pem -out rootCA.crt.pem \ -passout pass:" CHANGE_ME " \ -subj "/C=CC/ST=state/L=Locality/O=RH/OU=RootCA/CN=RootCA" \ -addext "basicConstraints=CA:true" -addext "keyUsage=cRLSign, keyCertSign" Replace CHANGE_ME with a new password. Create the intermediate CA private key and certificate signing request (CSR), and set a password: Example USD openssl req -newkey rsa:2048 -sha256 \ -keyout intermediateCA.key.pem -out intermediateCA.csr.pem \ -passout pass:" CHANGE_ME " \ -subj "/C=CC/ST=state/L=Locality/O=RH/OU=IntermediateCA/CN=IntermediateCA" Replace CHANGE_ME with a new password. Sign the intermediate CA certificate with the root CA: Example USD openssl x509 -req -in intermediateCA.csr.pem -CA rootCA.crt.pem -CAkey rootCA.key.pem \ -CAcreateserial -out intermediateCA.crt.pem -days 365 -sha256 \ -extfile <(echo -e "basicConstraints=CA:true\nkeyUsage=cRLSign, keyCertSign\nextendedKeyUsage=critical,timeStamping") \ -passin pass:" CHANGE_ME " Replace CHANGE_ME with the root CA private key password to sign the intermediate CA certificate. Create the leaf CA private key and CSR, and set a password: Example USD openssl req -newkey rsa:2048 -sha256 \ -keyout leafCA.key.pem -out leafCA.csr.pem \ -passout pass:" CHANGE_ME " \ -subj "/C=CC/ST=state/L=Locality/O=RH/OU=LeafCA/CN=LeafCA" Sign the leaf CA certificate with the intermediate CA: Example USD openssl x509 -req -in leafCA.csr.pem -CA intermediateCA.crt.pem -CAkey intermediateCA.key.pem \ -CAcreateserial -out leafCA.crt.pem -days 365 -sha256 \ -extfile <(echo -e "basicConstraints=CA:false\nkeyUsage=cRLSign, keyCertSign\nextendedKeyUsage=critical,timeStamping") \ -passin pass:" CHANGE_ME " Replace CHANGE_ME with the intermediate CA private key password to sign the leaf CA certificate. Create the certificate chain by combining the newly created certificates: Example USD cat leafCA.crt.pem intermediateCA.crt.pem rootCA.crt.pem > new-cert-chain.pem Create a new secret resource with the signer key: Example USD oc create secret generic rotated-signer-key --from-file=rotated-signer-key=certs/leafCA.key.pem Create a new secret resource with the new certificate chain: Example USD oc create secret generic rotated-cert-chain --from-file=rotated-cert-chain=certs/new-cert-chain.pem Create a new secret resource with for the password: Example USD oc create secret generic rotated-password --from-literal=rotated-password= CHANGE_ME Replace CHANGE_ME with the intermediate CA private key password. Find your active TSA certificate file name, the TSA URL string, and configure your shell environment with these values: Example USD export ACTIVE_CERT_CHAIN_NAME=tsa.certchain.pem USD export TSA_URL=USD(oc get timestampauthority securesign-sample -o jsonpath='{.status.url}')/api/v1/timestamp USD curl USDTSA_URL/certchain -o USDACTIVE_CERT_CHAIN_NAME Update the Securesign TSA configuration: Example USD read -r -d '' SECURESIGN_PATCH <<EOF [ { "op": "replace", "path": "/spec/tsa/signer/certificateChain", "value": { "certificateChainRef" : {"name": "rotated-cert-chain", "key": "rotated-cert-chain"} } }, { "op": "replace", "path": "/spec/tsa/signer/file", "value": { "privateKeyRef": {"name": "rotated-signer-key", "key": "rotated-signer-key"}, "passwordRef": {"name": "rotated-password", "key": "rotated-password"} } } ] EOF Patch the Securesign instance: Example USD oc patch Securesign securesign-sample --type='json' -p="USDSECURESIGN_PATCH" Wait for the TSA server to redeploy with the new signer key and certificate chain: Example USD oc get pods -w -l app.kubernetes.io/name=tsa-server Get the new certificate chain: Example USD export NEW_CERT_CHAIN_NAME=new_tsa.certchain.pem USD curl USDTSA_URL/certchain -o USDNEW_CERT_CHAIN_NAME Configure The Update Framework (TUF) service to use the new TSA certificate chain. Set up your shell environment: Example USD export WORK="USD{HOME}/trustroot-example" USD export ROOT="USD{WORK}/root/root.json" USD export KEYDIR="USD{WORK}/keys" USD export INPUT="USD{WORK}/input" USD export TUF_REPO="USD{WORK}/tuf-repo" USD export TUF_SERVER_POD="USD(oc get pod --selector=app.kubernetes.io/component=tuf --no-headers -o custom-columns=":metadata.name")" Create a temporary TUF directory structure: Example USD mkdir -p "USD{WORK}/root/" "USD{KEYDIR}" "USD{INPUT}" "USD{TUF_REPO}" Download the TUF contents to the temporary TUF directory structure: Example USD oc extract --to "USD{KEYDIR}/" secret/tuf-root-keys USD oc cp "USD{TUF_SERVER_POD}:/var/www/html" "USD{TUF_REPO}" USD cp "USD{TUF_REPO}/root.json" "USD{ROOT}" Expire the old TSA certificate: Example USD tuftool rhtas \ --root "USD{ROOT}" \ --key "USD{KEYDIR}/snapshot.pem" \ --key "USD{KEYDIR}/targets.pem" \ --key "USD{KEYDIR}/timestamp.pem" \ --set-tsa-target "USDACTIVE_CERT_CHAIN_NAME" \ --tsa-uri "USDTSA_URL" \ --tsa-status "Expired" \ --outdir "USD{TUF_REPO}" \ --metadata-url "file://USD{TUF_REPO}" Add the new TSA certificate: Example USD tuftool rhtas \ --root "USD{ROOT}" \ --key "USD{KEYDIR}/snapshot.pem" \ --key "USD{KEYDIR}/targets.pem" \ --key "USD{KEYDIR}/timestamp.pem" \ --set-tsa-target "USDNEW_CERT_CHAIN_NAME" \ --tsa-uri "USDTSA_URL" \ --outdir "USD{TUF_REPO}" \ --metadata-url "file://USD{TUF_REPO}" Upload these changes to the TUF server: Example USD oc rsync "USD{TUF_REPO}/" "USD{TUF_SERVER_POD}:/var/www/html" Delete the working directory: Example USD rm -r USDWORK Update the cosign configuration with the updated TUF configuration: Example USD cosign initialize --mirror=USDTUF_URL --root=USDTUF_URL/root.json Now, you are ready to sign and verify your artifacts that uses the new TSA signer key, and certificate.

Commands:
gunzip rekor-cli-amd64.gz chmod +x rekor-cli-amd64
sudo mv rekor-cli-amd64 /usr/local/bin/rekor-cli
gunzip tuftool-amd64.gz chmod +x tuftool-amd64
sudo mv tuftool-amd64 /usr/local/bin/tuftool
login --token= TOKEN --server= SERVER_URL_AND_PORT
oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443
oc project trusted-artifact-signer
export REKOR_URL=USD(oc get rekor -o jsonpath='{.items[0].status.url}')
export OLD_TREE_ID=USD(rekor-cli loginfo --rekor_server USDREKOR_URL --format json | jq -r .TreeID)
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=USD{OLD_TREE_ID} --tree_state=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=USD{OLD_TREE_ID} --tree_state=FROZEN
export OLD_SHARD_LENGTH=USD(rekor-cli loginfo --rekor_server USDREKOR_URL --format json | jq -r .ActiveTreeSize)
export OLD_PUBLIC_KEY=USD(curl -s USDREKOR_URL/api/v1/log/publicKey | base64 | tr -d '\n')
export NEW_TREE_ID=USD(oc 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=rekor-tree)
openssl ecparam -genkey -name secp384r1 -noout -out new-rekor.pem
oc create secret generic rekor-signer-key --from-file=private=new-rekor.pem
read -r -d '' SECURESIGN_PATCH_1 <<EOF [ { "op": "replace", "path": "/spec/rekor/treeID", "value": USDNEW_TREE_ID }, { "op": "add", "path": "/spec/rekor/sharding/-", "value": { "treeID": USDOLD_TREE_ID, "treeLength": USDOLD_SHARD_LENGTH, "encodedPublicKey": "USDOLD_PUBLIC_KEY" } }, { "op": "replace", "path": "/spec/rekor/signer/keyRef", "value": {"name": "rekor-signer-key", "key": "private"} } ] EOF
read -r -d '' SECURESIGN_PATCH_2 <<EOF [ { "op": "remove", "path": "/spec/rekor/signer/keyPasswordRef" } ] EOF
oc patch Securesign securesign-sample --type='json' -p="USDSECURESIGN_PATCH_1"
oc wait pod -l app.kubernetes.io/name=rekor-server --for=condition=Ready
export NEW_KEY_NAME=new-rekor.pub curl USD(oc get rekor -o jsonpath='{.items[0].status.url}')/api/v1/log/publicKey -o USDNEW_KEY_NAME
export WORK="USD{HOME}/trustroot-example" export ROOT="USD{WORK}/root/root.json" export KEYDIR="USD{WORK}/keys" export INPUT="USD{WORK}/input" export TUF_REPO="USD{WORK}/tuf-repo" export TUF_SERVER_POD="USD(oc get pod --selector=app.kubernetes.io/component=tuf --no-headers -o custom-columns=":metadata.name")"
mkdir -p "USD{WORK}/root/" "USD{KEYDIR}" "USD{INPUT}" "USD{TUF_REPO}"
oc extract --to "USD{KEYDIR}/" secret/tuf-root-keys oc cp "USD{TUF_SERVER_POD}:/var/www/html" "USD{TUF_REPO}" cp "USD{TUF_REPO}/root.json" "USD{ROOT}"
export ACTIVE_KEY_NAME=rekor.pub
echo USDOLD_PUBLIC_KEY | base64 -d > USDACTIVE_KEY_NAME
tuftool rhtas --root "USD{ROOT}" --key "USD{KEYDIR}/snapshot.pem" --key "USD{KEYDIR}/targets.pem" --key "USD{KEYDIR}/timestamp.pem" --set-rekor-target "USD{ACTIVE_KEY_NAME}" --rekor-uri "https://rekor.rhtas" --rekor-status "Expired" --outdir "USD{TUF_REPO}" --metadata-url "file://USD{TUF_REPO}"
tuftool rhtas --root "USD{ROOT}" --key "USD{KEYDIR}/snapshot.pem" --key "USD{KEYDIR}/targets.pem" --key "USD{KEYDIR}/timestamp.pem" --set-rekor-target "USD{NEW_KEY_NAME}" --rekor-uri "https://rekor.rhtas" --outdir "USD{TUF_REPO}" --metadata-url "file://USD{TUF_REPO}"
oc rsync "USD{TUF_REPO}/" "USD{TUF_SERVER_POD}:/var/www/html"
rm -r USDWORK
cosign initialize --mirror=USDTUF_URL --root=USDTUF_URL/root.json
gunzip tuftool-amd64.gz chmod +x tuftool-amd64
sudo mv tuftool-amd64 /usr/local/bin/tuftool
login --token= TOKEN --server= SERVER_URL_AND_PORT
oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443
oc project trusted-artifact-signer
export SERVER_CONFIG_NAME=USD(oc get ctlog -o jsonpath='{.items[0].status.serverConfigRef.name}') oc get secret USDSERVER_CONFIG_NAME -o jsonpath="{.data.config}" | base64 --decode > config.txtpb oc get secret USDSERVER_CONFIG_NAME -o jsonpath="{.data.fulcio-0}" | base64 --decode > fulcio-0.pem oc get secret USDSERVER_CONFIG_NAME -o jsonpath="{.data.private}" | base64 --decode > private.pem oc get secret USDSERVER_CONFIG_NAME -o jsonpath="{.data.public}" | base64 --decode > public.pem
export OLD_TREE_ID=USD(oc get ctlog -o jsonpath='{.items[0].status.treeID}')
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=USD{OLD_TREE_ID} --tree_state=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=USD{OLD_TREE_ID} --tree_state=FROZEN
export NEW_TREE_ID=USD(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 "
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\xdcewty\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" }
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" }
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
export WORK="USD{HOME}/trustroot-example" export ROOT="USD{WORK}/root/root.json" export KEYDIR="USD{WORK}/keys" export INPUT="USD{WORK}/input" export TUF_REPO="USD{WORK}/tuf-repo" export TUF_SERVER_POD="USD(oc get pod --selector=app.kubernetes.io/component=tuf --no-headers -o custom-columns=":metadata.name")"
mkdir -p "USD{WORK}/root/" "USD{KEYDIR}" "USD{INPUT}" "USD{TUF_REPO}"
oc extract --to "USD{KEYDIR}/" secret/tuf-root-keys oc cp "USD{TUF_SERVER_POD}:/var/www/html" "USD{TUF_REPO}" cp "USD{TUF_REPO}/root.json" "USD{ROOT}"
export ACTIVE_CTFE_NAME=ctfe.pub
oc get secret USD(oc get ctlog securesign-sample -o jsonpath='{.status.publicKeyRef.name}') -o jsonpath='{.data.public}' | base64 -d > USDACTIVE_CTFE_NAME
tuftool rhtas --root "USD{ROOT}" --key "USD{KEYDIR}/snapshot.pem" --key "USD{KEYDIR}/targets.pem" --key "USD{KEYDIR}/timestamp.pem" --set-ctlog-target "USDACTIVE_CTFE_NAME" --ctlog-uri "https://ctlog.rhtas" --ctlog-status "Expired" --outdir "USD{TUF_REPO}" --metadata-url "file://USD{TUF_REPO}"
tuftool rhtas --root "USD{ROOT}" --key "USD{KEYDIR}/snapshot.pem" --key "USD{KEYDIR}/targets.pem" --key "USD{KEYDIR}/timestamp.pem" --set-ctlog-target "new-ctlog-public.pem" --ctlog-uri "https://ctlog.rhtas" --outdir "USD{TUF_REPO}" --metadata-url "file://USD{TUF_REPO}"
oc rsync "USD{TUF_REPO}/" "USD{TUF_SERVER_POD}:/var/www/html"
rm -r USDWORK
read -r -d '' SECURESIGN_PATCH <<EOF [ { "op": "replace", "path": "/spec/ctlog/serverConfigRef", "value": {"name": "ctlog-config"} }, { "op": "replace", "path": "/spec/ctlog/treeID", "value": USDNEW_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
oc patch Securesign securesign-sample --type='json' -p="USDSECURESIGN_PATCH"
oc wait pod -l app.kubernetes.io/name=ctlog --for=condition=Ready
cosign initialize --mirror=USDTUF_URL --root=USDTUF_URL/root.json
gunzip tuftool-amd64.gz chmod +x tuftool-amd64
sudo mv tuftool-amd64 /usr/local/bin/tuftool
login --token= TOKEN --server= SERVER_URL_AND_PORT
oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443
oc project trusted-artifact-signer
openssl ecparam -genkey -name prime256v1 -noout -out new-fulcio.pem openssl ec -in new-fulcio.pem -pubout -out new-fulcio-public.pem openssl ec -in new-fulcio.pem -out new-fulcio.pass.pem -des3 -passout pass:" CHANGE_ME " openssl req -new -x509 -key new-fulcio.pass.pem -out new-fulcio.cert.pem
oc create secret generic fulcio-config --from-file=private=new-fulcio.pass.pem --from-file=cert=new-fulcio.cert.pem --from-literal=password= CHANGE_ME
export WORK="USD{HOME}/trustroot-example" export ROOT="USD{WORK}/root/root.json" export KEYDIR="USD{WORK}/keys" export INPUT="USD{WORK}/input" export TUF_REPO="USD{WORK}/tuf-repo" export TUF_SERVER_POD="USD(oc get pod --selector=app.kubernetes.io/component=tuf --no-headers -o custom-columns=":metadata.name")"
mkdir -p "USD{WORK}/root/" "USD{KEYDIR}" "USD{INPUT}" "USD{TUF_REPO}"
oc extract --to "USD{KEYDIR}/" secret/tuf-root-keys oc cp "USD{TUF_SERVER_POD}:/var/www/html" "USD{TUF_REPO}" cp "USD{TUF_REPO}/root.json" "USD{ROOT}"
export ACTIVE_CERT_NAME=fulcio_v1.crt.pem
oc get secret USD(oc get fulcio securesign-sample -o jsonpath='{.status.certificate.caRef.name}') -o jsonpath='{.data.cert}' | base64 -d > USDACTIVE_CERT_NAME
tuftool rhtas --root "USD{ROOT}" --key "USD{KEYDIR}/snapshot.pem" --key "USD{KEYDIR}/targets.pem" --key "USD{KEYDIR}/timestamp.pem" --set-fulcio-target "USDACTIVE_CERT_NAME" --fulcio-uri "https://fulcio.rhtas" --fulcio-status "Expired" --outdir "USD{TUF_REPO}" --metadata-url "file://USD{TUF_REPO}"
tuftool rhtas --root "USD{ROOT}" --key "USD{KEYDIR}/snapshot.pem" --key "USD{KEYDIR}/targets.pem" --key "USD{KEYDIR}/timestamp.pem" --set-fulcio-target "new-fulcio.cert.pem" --fulcio-uri "https://fulcio.rhtas" --outdir "USD{TUF_REPO}" --metadata-url "file://USD{TUF_REPO}"
oc rsync "USD{TUF_REPO}/" "USD{TUF_SERVER_POD}:/var/www/html"
rm -r USDWORK
read -r -d '' SECURESIGN_PATCH <<EOF [ { "op": "replace", "path": "/spec/fulcio/certificate/privateKeyRef", "value": {"name": "fulcio-config", "key": "private"} }, { "op": "replace", "path": "/spec/fulcio/certificate/privateKeyPasswordRef", "value": {"name": "fulcio-config", "key": "password"} }, { "op": "replace", "path": "/spec/fulcio/certificate/caRef", "value": {"name": "fulcio-config", "key": "cert"} }, { "op": "replace", "path": "/spec/ctlog/rootCertificates", "value": [{"name": "fulcio-config", "key": "cert"}] } ] EOF
oc patch Securesign securesign-sample --type='json' -p="USDSECURESIGN_PATCH"
oc wait pod -l app.kubernetes.io/name=fulcio-server --for=condition=Ready oc wait pod -l app.kubernetes.io/name=ctlog --for=condition=Ready
cosign initialize --mirror=USDTUF_URL --root=USDTUF_URL/root.json
gunzip tuftool-amd64.gz chmod +x tuftool-amd64
sudo mv tuftool-amd64 /usr/local/bin/tuftool
login --token= TOKEN --server= SERVER_URL_AND_PORT
oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443
oc project trusted-artifact-signer
mkdir certs && cd certs
openssl req -x509 -newkey rsa:2048 -days 365 -sha256 -nodes -keyout rootCA.key.pem -out rootCA.crt.pem -passout pass:" CHANGE_ME " -subj "/C=CC/ST=state/L=Locality/O=RH/OU=RootCA/CN=RootCA" -addext "basicConstraints=CA:true" -addext "keyUsage=cRLSign, keyCertSign"
openssl req -newkey rsa:2048 -sha256 -keyout intermediateCA.key.pem -out intermediateCA.csr.pem -passout pass:" CHANGE_ME " -subj "/C=CC/ST=state/L=Locality/O=RH/OU=IntermediateCA/CN=IntermediateCA"
openssl x509 -req -in intermediateCA.csr.pem -CA rootCA.crt.pem -CAkey rootCA.key.pem -CAcreateserial -out intermediateCA.crt.pem -days 365 -sha256 -extfile <(echo -e "basicConstraints=CA:true\nkeyUsage=cRLSign, keyCertSign\nextendedKeyUsage=critical,timeStamping") -passin pass:" CHANGE_ME "
openssl req -newkey rsa:2048 -sha256 -keyout leafCA.key.pem -out leafCA.csr.pem -passout pass:" CHANGE_ME " -subj "/C=CC/ST=state/L=Locality/O=RH/OU=LeafCA/CN=LeafCA"
openssl x509 -req -in leafCA.csr.pem -CA intermediateCA.crt.pem -CAkey intermediateCA.key.pem -CAcreateserial -out leafCA.crt.pem -days 365 -sha256 -extfile <(echo -e "basicConstraints=CA:false\nkeyUsage=cRLSign, keyCertSign\nextendedKeyUsage=critical,timeStamping") -passin pass:" CHANGE_ME "
cat leafCA.crt.pem intermediateCA.crt.pem rootCA.crt.pem > new-cert-chain.pem
oc create secret generic rotated-signer-key --from-file=rotated-signer-key=certs/leafCA.key.pem
oc create secret generic rotated-cert-chain --from-file=rotated-cert-chain=certs/new-cert-chain.pem
oc create secret generic rotated-password --from-literal=rotated-password= CHANGE_ME
export ACTIVE_CERT_CHAIN_NAME=tsa.certchain.pem export TSA_URL=USD(oc get timestampauthority securesign-sample -o jsonpath='{.status.url}')/api/v1/timestamp curl USDTSA_URL/certchain -o USDACTIVE_CERT_CHAIN_NAME
read -r -d '' SECURESIGN_PATCH <<EOF [ { "op": "replace", "path": "/spec/tsa/signer/certificateChain", "value": { "certificateChainRef" : {"name": "rotated-cert-chain", "key": "rotated-cert-chain"} } }, { "op": "replace", "path": "/spec/tsa/signer/file", "value": { "privateKeyRef": {"name": "rotated-signer-key", "key": "rotated-signer-key"}, "passwordRef": {"name": "rotated-password", "key": "rotated-password"} } } ] EOF
oc patch Securesign securesign-sample --type='json' -p="USDSECURESIGN_PATCH"
oc get pods -w -l app.kubernetes.io/name=tsa-server
export NEW_CERT_CHAIN_NAME=new_tsa.certchain.pem curl USDTSA_URL/certchain -o USDNEW_CERT_CHAIN_NAME
export WORK="USD{HOME}/trustroot-example" export ROOT="USD{WORK}/root/root.json" export KEYDIR="USD{WORK}/keys" export INPUT="USD{WORK}/input" export TUF_REPO="USD{WORK}/tuf-repo" export TUF_SERVER_POD="USD(oc get pod --selector=app.kubernetes.io/component=tuf --no-headers -o custom-columns=":metadata.name")"
mkdir -p "USD{WORK}/root/" "USD{KEYDIR}" "USD{INPUT}" "USD{TUF_REPO}"
oc extract --to "USD{KEYDIR}/" secret/tuf-root-keys oc cp "USD{TUF_SERVER_POD}:/var/www/html" "USD{TUF_REPO}" cp "USD{TUF_REPO}/root.json" "USD{ROOT}"
tuftool rhtas --root "USD{ROOT}" --key "USD{KEYDIR}/snapshot.pem" --key "USD{KEYDIR}/targets.pem" --key "USD{KEYDIR}/timestamp.pem" --set-tsa-target "USDACTIVE_CERT_CHAIN_NAME" --tsa-uri "USDTSA_URL" --tsa-status "Expired" --outdir "USD{TUF_REPO}" --metadata-url "file://USD{TUF_REPO}"
tuftool rhtas --root "USD{ROOT}" --key "USD{KEYDIR}/snapshot.pem" --key "USD{KEYDIR}/targets.pem" --key "USD{KEYDIR}/timestamp.pem" --set-tsa-target "USDNEW_CERT_CHAIN_NAME" --tsa-uri "USDTSA_URL" --outdir "USD{TUF_REPO}" --metadata-url "file://USD{TUF_REPO}"
oc rsync "USD{TUF_REPO}/" "USD{TUF_SERVER_POD}:/var/www/html"
rm -r USDWORK
cosign initialize --mirror=USDTUF_URL --root=USDTUF_URL/root.json