Rotate 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.
Before you begin
For OpenShift:
- Installation of the RHTAS operator running on Red Hat OpenShift Container Platform.
- A running Securesign instance.
- A workstation with the
oc,openssl, andcosignbinaries installed.
For Red Hat Enterprise Linux:
- Installation of RHTAS running on Red Hat Enterprise Linux managed by Ansible.
- A workstation with the
rsync,openssl, andcosignbinaries installed. - A SSH connection to the managed node, with root-level privileges on the managed node.
About this task
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. When expiring your old Rekor signer key you can still verify artifacts signed by the old key.
Procedure
-
For OpenShift: 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
.gzfile, and set the execute bit:$ gunzip rekor-cli-amd64.gz $ chmod +x rekor-cli-amd64 -
Move and rename the binary to a location within your
$PATHenvironment:$ sudo mv rekor-cli-amd64 /usr/local/bin/rekor-cli
-
For Red Hat Enterprise Linux: Download the rekor-cli binary from the Red Hat developers portal.
Note The binaries are available at Red Hat Trusted Artifact Signer download page.- From the download page, go to the rekor-cli download section, and click the link for your platform.
-
Open a terminal on your workstation, decompress the binary
.gzfile, and set the execute bit:$ gunzip rekor-cli-amd64.gz $ chmod +x rekor-cli-amd64 -
Move and rename the binary to a location within your
$PATHenvironment:$ sudo mv rekor-cli-amd64 /usr/local/bin/rekor-cli
-
For OpenShift: Download the tufcli binary from the OpenShift cluster to your workstation.
- From the home page, click the ? icon, click Command line tools, go to the tufcli download section, and click the link for your platform.
-
For Red Hat Enterprise Linux: Download the tufcli binary from the Red Hat developers portal.
Note The binaries are available at Red Hat Trusted Artifact Signer download page.- From the download page, go to the tufcli download section, and click the link for your platform.
-
Open a terminal on your workstation, extract the
.tar.gzarchive, and set the execution bit:$ tar -xzf tufcli_linux_amd64.tar.gz $ chmod +x tufcli -
Move the binary to a location within your
$PATHenvironment:$ sudo mv tufcli /usr/local/bin/tufcli -
For OpenShift: Log in to OpenShift from the command line:
oc login --token=TOKEN --server=SERVER_URL_AND_PORT$ oc login --token=sha256~ZvFDBvoIYAbVECixS4-WmkN4RfnNd8Neh3y1WuiFPXC --server=https://example.com:6443Note 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. -
For OpenShift: Switch to the RHTAS project:
$ oc project trusted-artifact-signer -
For OpenShift: Make a backup of the current Rekor configuration and keys:
$ export SERVER_CONFIG_NAME=$(oc get rekor -o jsonpath='{.items[0].status.serverConfigRef.name}') $ 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 -
For OpenShift: Capture the current tree identifier:
$ export OLD_TREE_ID=$(oc get rekor -o jsonpath='{.items[0].status.treeID}') -
For OpenShift: Set the log tree to the
DRAININGstate:$ oc run updatetree --image registry.redhat.io/rhtas/updatetree-rhel9:1.1.0 --restart=Never --attach=true --rm=true -q -- --admin_server=trillian-logserver.trusted-artifact-signer.svc:8091 --tree_id=${OLD_TREE_ID} --tree_state=DRAINING --tls_cert_file=/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crtWhile 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 next 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) threshold. -
For OpenShift: Once the queue has been fully drained, freeze the log:
$ oc run updatetree --image registry.redhat.io/rhtas/updatetree-rhel9:1.1.0 --restart=Never --attach=true --rm=true -q -- --admin_server=trillian-logserver.trusted-artifact-signer.svc:8091 --tree_id=${OLD_TREE_ID} --tree_state=FROZEN --tls_cert_file=/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt -
For OpenShift: Create a new Merkle tree, and capture the new tree identifier:
$ oc run createtree --image registry.redhat.io/rhtas/createtree-rhel9:1.1.0 --restart=Never -q -- -logtostderr=false --admin_server=trillian-logserver.trusted-artifact-signer.svc:8091 --display_name=rekor-tree --tls_cert_file=/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt $ oc wait pod/createtree --for=jsonpath='{.status.phase}'=Succeeded --timeout=5m $ export NEW_TREE_ID=$(oc logs pod/createtree | tail -n 1 | tr -d '[:space:]') $ oc delete pod/createtree -
For OpenShift: Generate a new certificate, along with new public and private keys:
$ openssl ecparam -genkey -name prime256v1 -noout -out new-rekor.pem $ openssl ec -in new-rekor.pem -pubout -out new-rekor-public.pemImportant The certificate and new keys must have unique file names. -
Configure The Update Framework (TUF) service to use the new Rekor signer key.
-
For OpenShift: Set up your shell environment:
$ export WORK="${HOME}/trustroot-example" $ export ROOT="${WORK}/root/root.json" $ export KEYDIR="${WORK}/keys" $ export INPUT="${WORK}/input" $ export REKOR_URL="$(oc get rekor -o jsonpath='{.items[0].status.url}')" $ export TUF_REPO="${WORK}/tuf-repo" $ export TUF_SERVER_POD="$(oc get pods -l app.kubernetes.io/component=tuf,\!job-name -o jsonpath='{.items[0].metadata.name}')" $ export TUF_URL="$(oc get tuf -o jsonpath='{.items[0].status.url}')" -
For Red Hat Enterprise Linux: Set up your shell environment:
$ export BASE_HOSTNAME=BASE_HOSTNAME_OF_RHTAS_SERVICE $ export WORK="${HOME}/trustroot-example" $ export ROOT="${WORK}/root/root.json" $ export KEYDIR="${WORK}/keys" $ export INPUT="${WORK}/input" $ export REKOR_URL="https://rekor.${BASE_HOSTNAME}" $ export TUF_REPO="${WORK}/tuf-repo" $ export TUF_URL="https://tuf.${BASE_HOSTNAME}" $ export MANAGED_NODE_IP=IP_OF_ANSIBLE_MANAGED_NODE $ export MANAGED_NODE_SSH_USER=USER_TO_CONNECT_TO_MANAGED_NODE $ export REMOTE_KEYS_VOLUME=$(ssh ${MANAGED_NODE_SSH_USER}@${MANAGED_NODE_IP} -t "sudo podman volume mount tuf-signing-keys" | tr -d '[:space:]') $ export REMOTE_TUF_VOLUME=$(ssh ${MANAGED_NODE_SSH_USER}@${MANAGED_NODE_IP} -t "sudo podman volume mount tuf-repository" | tr -d '[:space:]') -
Create a temporary TUF directory structure:
$ mkdir -p "${WORK}/root/" "${KEYDIR}" "${INPUT}" "${TUF_REPO}" -
For OpenShift: Download the TUF contents to the temporary TUF directory structure:
$ oc extract --confirm --to "${KEYDIR}/" secret/tuf-root-keys $ oc cp "${TUF_SERVER_POD}:/var/www/html" "${TUF_REPO}" $ cp "${TUF_REPO}/root.json" "${ROOT}" -
For Red Hat Enterprise Linux: Download the TUF contents to the temporary TUF directory structure:
$ rsync -r --rsync-path="sudo rsync" ${MANAGED_NODE_SSH_USER}@${MANAGED_NODE_IP}:"${REMOTE_KEYS_VOLUME}/" "${KEYDIR}" $ rsync -r --rsync-path="sudo rsync" ${MANAGED_NODE_SSH_USER}@${MANAGED_NODE_IP}:"${REMOTE_TUF_VOLUME}/" "${TUF_REPO}" $ cp "${TUF_REPO}/root.json" "${ROOT}" -
Expire the old Rekor signer key:
$ tufcli rhtas \ --root "${ROOT}" \ --key "${KEYDIR}/snapshot.pem" \ --key "${KEYDIR}/targets.pem" \ --key "${KEYDIR}/timestamp.pem" \ --set-rekor-target "public.pem" \ --rekor-uri "${REKOR_URL}" \ --rekor-status "Expired" \ --outdir "${TUF_REPO}" \ --metadata-url "file://${TUF_REPO}" -
Add the new Rekor signer key:
$ tufcli rhtas \ --root "${ROOT}" \ --key "${KEYDIR}/snapshot.pem" \ --key "${KEYDIR}/targets.pem" \ --key "${KEYDIR}/timestamp.pem" \ --set-rekor-target "new-rekor-public.pem" \ --rekor-uri "${REKOR_URL}" \ --outdir "${TUF_REPO}" \ --metadata-url "file://${TUF_REPO}" -
For OpenShift: Upload these changes to the TUF server:
$ oc rsync --no-perms "${TUF_REPO}/" "${TUF_SERVER_POD}:/var/www/html" -
For Red Hat Enterprise Linux: Create a compressed archive file of the updated TUF repository:
$ tar -C "${WORK}" -czvf repository.tar.gz tuf-repo -
For Red Hat Enterprise Linux: Update the RHTAS Ansible playbook by adding the new compressed archive file content to the
tas_single_node_trust_rootvariable:tas_single_node_trust_root: full_archive: "{{ lookup('file', 'repository.tar.gz') | b64encode }}" -
Delete the working directory:
$ rm -r $WORK
-
For OpenShift: Set up your shell environment:
-
For OpenShift: Create a new ConfigMap for the new Rekor signer keys:
$ oc create configmap rekor-keys --from-file=private=new-rekor.pem --from-file=public=new-rekor-public.pem -
For OpenShift: Update the Securesign Rekor configuration:
$ read -r -d '' SECURESIGN_PATCH <<EOF [ { "op": "replace", "path": "/spec/rekor/treeID", "value": ${NEW_TREE_ID} }, { "op": "replace", "path": "/spec/rekor/signer/privateKeyRef", "value": {"name": "rekor-keys", "key": "private"} }, { "op": "replace", "path": "/spec/rekor/signer/publicKeyRef", "value": {"name": "rekor-keys", "key": "public"} } ] EOF -
For OpenShift: Patch the Securesign instance:
$ oc patch Securesign securesign-sample --type='json' -p="$SECURESIGN_PATCH" -
For OpenShift: Wait for the Rekor server to redeploy:
$ oc wait pod -l app.kubernetes.io/name=rekor-server,\!job-name --for=condition=Ready -
For OpenShift: Accept the updated Rekor trust material:
$ oc annotate rekor securesign-sample rhtas.redhat.com/refresh-trust-material=true --overwriteNote After you rotate the signer, the Rekor instance stays unready until you annotate the resource to accept the new trust material. -
For OpenShift: Wait until the Rekor instance is ready:
$ oc wait rekor securesign-sample --for=condition=Ready -
For Red Hat Enterprise Linux: Run the RHTAS Ansible Playbook to apply the changes:
$ ansible-playbook -i inventory play.yml -
Update the
cosignconfiguration with the updated TUF configuration:$ : "${TAS_TUF_ROOT_CHECKSUM:?Set the pinned TAS_TUF_ROOT_CHECKSUM}" $ cosign initialize --mirror=$TUF_URL --root=$TUF_URL/1.root.json --root-checksum=$TAS_TUF_ROOT_CHECKSUMThe
--root-checksumoption ensures that the TUF root metadata is valid and has not been tampered with. -
For OpenShift, confirm the new public key:
$ oc annotate rekor securesign-sample rhtas.redhat.com/refresh-trust-material=true --overwriteThe operator processes the annotation and updates the trust material.
Results
$ oc get rekor securesign-sample -o jsonpath='{.status.conditions[?(@.type=="TrustMaterialAvailable")].status}'
True.Now, you are ready to sign and verify your artifacts with the new CT log signer key.
What to do next
For Red Hat Enterprise Linux:
Additional resources
- Running your playbook with Ansible Automation Platform