Rotate the Fulcio certificate
Rotate the certificate used by the Fulcio service.
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
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.
Procedure
-
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 -
Generate a new certificate, along with new public and private keys:
For OpenShift:
$ openssl ecparam -genkey -name prime256v1 -noout -out new-fulcio.pem $ openssl ec -in new-fulcio.pem -pubout -out new-fulcio-public.pem $ openssl req -new -x509 -key new-fulcio.pem -out new-fulcio.cert.pemFor Red Hat Enterprise Linux:
$ 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.pemReplace CHANGE_ME with a new password.
Important The certificate and new keys must have unique file names. -
For OpenShift: Create a new secret:
$ oc create secret generic fulcio-config \ --from-file=private=new-fulcio.pem \ --from-file=cert=new-fulcio.cert.pem -
For Red Hat Enterprise Linux: Update the RHTAS Ansible playbook by adding the new private key file name, the new certificate content, and the password to the
tas_single_node_fulciovariable:tas_single_node_fulcio: root_ca: "{{ lookup('file', 'new-fulcio.cert.pem') }}" private_key: "{{ lookup('file', 'new-fulcio.pass.pem') }}" ca_passphrase: CHANGE_MEReplace CHANGE_ME with a new password.
Note The password here must match the password used for generating the new private and public keys.Note We recommend sourcing the passphrase either from a file or encrypted by using Ansible Vault. -
Configure The Update Framework (TUF) service to use the new Fulcio certificate.
-
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 FULCIO_URL=$(oc get fulcio securesign-sample -o jsonpath='{.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 FULCIO_URL="https://fulcio.${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:]')Replace BASE_HOSTNAME_OF_RHTAS_SERVICE with the value of the
tas_single_node_base_hostnamevariable. -
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}" -
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:$ export ACTIVE_CERT_NAME=fulcio_v1.crt.pem -
For OpenShift: Extract the active Fulcio certificate from OpenShift:
$ oc get secret $(oc get fulcio securesign-sample -o jsonpath='{.status.certificate.caRef.name}') -o jsonpath='{.data.cert}' | base64 -d > $ACTIVE_CERT_NAME -
For Red Hat Enterprise Linux: Get the active Fulcio certificate from the managed node:
$ rsync -r --rsync-path="sudo rsync" ${MANAGED_NODE_SSH_USER}@${MANAGED_NODE_IP}:/etc/rhtas/certs/fulcio.pem "${ACTIVE_CERT_NAME}" -
Expire the old certificate:
$ tufcli rhtas \ --root "${ROOT}" \ --key "${KEYDIR}/snapshot.pem" \ --key "${KEYDIR}/targets.pem" \ --key "${KEYDIR}/timestamp.pem" \ --set-fulcio-target "$ACTIVE_CERT_NAME" \ --fulcio-uri "${FULCIO_URL}" \ --fulcio-status "Expired" \ --outdir "${TUF_REPO}" \ --metadata-url "file://${TUF_REPO}" -
Add the new Fulcio certificate:
$ tufcli rhtas \ --root "${ROOT}" \ --key "${KEYDIR}/snapshot.pem" \ --key "${KEYDIR}/targets.pem" \ --key "${KEYDIR}/timestamp.pem" \ --set-fulcio-target "new-fulcio.cert.pem" \ --fulcio-uri "${FULCIO_URL}" \ --oidc-uri "${OIDC_URI}" \ --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: Update the Securesign Fulcio configuration:
$ read -r -d '' SECURESIGN_PATCH <<EOF [ { "op": "replace", "path": "/spec/fulcio/signer", "value": { "type": "file", "certificateChain": { "certificateChainRef": {"name": "fulcio-config", "key": "cert"} }, "file": { "privateKeyRef": {"name": "fulcio-config", "key": "private"} } } }, { "op": "replace", "path": "/spec/ctlog/rootCertificates", "value": [{"name": "fulcio-config", "key": "cert"}] } ] EOF -
For OpenShift: Patch the Securesign instance:
$ oc patch Securesign securesign-sample --type='json' -p="$SECURESIGN_PATCH" -
For OpenShift: Wait for the Fulcio server to redeploy:
$ oc wait pod -l app.kubernetes.io/name=fulcio-server --for=condition=Ready $ oc wait pod -l app.kubernetes.io/name=ctlog,\!job-name --for=condition=Ready -
For OpenShift: Accept the updated Fulcio and CT log trust material:
$ oc annotate fulcio securesign-sample rhtas.redhat.com/refresh-trust-material=true --overwrite $ oc annotate ctlog securesign-sample rhtas.redhat.com/refresh-trust-material=true --overwriteNote After you rotate the certificate, the Fulcio and CT log instances stay unready until you annotate the resources to accept the new trust material. -
For OpenShift: Wait until the Fulcio and CT log instances are ready:
$ oc wait fulcio securesign-sample --for=condition=Ready $ oc wait ctlog 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 certificate:
$ oc annotate fulcio securesign-sample rhtas.redhat.com/refresh-trust-material=true --overwriteThe operator processes the annotation and updates the trust material.
Results
$ oc get fulcio 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