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, and cosign binaries installed.

For Red Hat Enterprise Linux:

  • Installation of RHTAS running on Red Hat Enterprise Linux managed by Ansible.
  • A workstation with the rsync, openssl, and cosign binaries 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

  1. For OpenShift: Download the tufcli binary from the OpenShift cluster to your workstation.
    1. From the home page, click the ? icon, click Command line tools, go to the tufcli download section, and click the link for your platform.
  2. 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.
    1. From the download page, go to the tufcli download section, and click the link for your platform.
  3. Open a terminal on your workstation, extract the .tar.gz archive, and set the execution bit:
    $ tar -xzf tufcli_linux_amd64.tar.gz
    $ chmod +x tufcli
  4. Move the binary to a location within your $PATH environment:
    $ sudo mv tufcli /usr/local/bin/tufcli
  5. 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: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.
  6. For OpenShift: Switch to the RHTAS project:
    $ oc project trusted-artifact-signer
  7. 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.pem

    For 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.pem

    Replace CHANGE_ME with a new password.

    Important
    The certificate and new keys must have unique file names.
  8. 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
  9. 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_fulcio variable:
    tas_single_node_fulcio:
      root_ca: "{{ lookup('file', 'new-fulcio.cert.pem') }}"
      private_key: "{{ lookup('file', 'new-fulcio.pass.pem') }}"
      ca_passphrase: 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.
    Note
    We recommend sourcing the passphrase either from a file or encrypted by using Ansible Vault.
  10. Configure The Update Framework (TUF) service to use the new Fulcio certificate.
    1. 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}')"
    2. 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_hostname variable.

    3. Create a temporary TUF directory structure:
      $ mkdir -p "${WORK}/root/" "${KEYDIR}" "${INPUT}" "${TUF_REPO}"
    4. 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}"
    5. 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}"
    6. 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
    7. 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
    8. 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}"
    9. 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}"
    10. 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}"
    11. For OpenShift: Upload these changes to the TUF server:
      $ oc rsync --no-perms "${TUF_REPO}/" "${TUF_SERVER_POD}:/var/www/html"
    12. For Red Hat Enterprise Linux: Create a compressed archive file of the updated TUF repository:
      $ tar -C "${WORK}" -czvf repository.tar.gz tuf-repo
    13. For Red Hat Enterprise Linux: Update the RHTAS Ansible playbook by adding the new compressed archive file content to the tas_single_node_trust_root variable:
      tas_single_node_trust_root:
        full_archive: "{{ lookup('file', 'repository.tar.gz') | b64encode }}"
    14. Delete the working directory:
      $ rm -r $WORK
  11. 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
  12. For OpenShift: Patch the Securesign instance:
    $ oc patch Securesign securesign-sample --type='json' -p="$SECURESIGN_PATCH"
  13. 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
  14. 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 --overwrite
    Note
    After you rotate the certificate, the Fulcio and CT log instances stay unready until you annotate the resources to accept the new trust material.
  15. 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
  16. For Red Hat Enterprise Linux: Run the RHTAS Ansible Playbook to apply the changes:
    $ ansible-playbook -i inventory play.yml
  17. Update the cosign configuration 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_CHECKSUM

    The --root-checksum option ensures that the TUF root metadata is valid and has not been tampered with.

  18. For OpenShift, confirm the new certificate:
    $ oc annotate fulcio securesign-sample rhtas.redhat.com/refresh-trust-material=true --overwrite

    The operator processes the annotation and updates the trust material.

Results

For Openshift, verify that the trust material refresh completed successfully:
$ oc get fulcio securesign-sample -o jsonpath='{.status.conditions[?(@.type=="TrustMaterialAvailable")].status}'
This command should return 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