Configure Metadata Signing¶
It is possible to sign Pulp's metadata so that users can verify the authenticity of an object. This is done by enabling the Signing Services feature. The steps to enable it are:
- create a gpg key
- create a Secret with a gpg key
- create a Secret with the signing script(s)
- configure Pulp CR
See pulpcore documentation for details on Content Signing: https://docs.pulpproject.org/pulpcore/workflows/signed-metadata.html#metadata-signing
See pulp_container documentation for details on Container Image Signing: https://docs.pulpproject.org/pulp_container/workflows/sign-images.html
Create a gpg key¶
-
create the key
$ GPG_EMAIL=pulp@example.com $ cat >/tmp/gpg.txt <<EOF %echo Generating a basic OpenPGP key Key-Type: DSA Key-Length: 1024 Subkey-Type: ECDSA Subkey-Curve: nistp256 Name-Real: Collection Signing Service Name-Comment: with no passphrase Name-Email: $GPG_EMAIL Expire-Date: 0 %no-ask-passphrase %no-protection # Do a commit here, so that we can later print "done" :-) %commit %echo done EOF $ gpg --batch --gen-key /tmp/gpg.txt
-
verify the list of available keyrings
$ gpg --list-keys /var/lib/pulp/.gnupg/pubring.kbx -------------------------------- pub rsa4096 2022-12-14 [SC] 66BBFE010CF70CC92826D9AB71684D7912B09BC1 uid [ultimate] Collection Signing Service (with no passphrase) <pulp@example.com> sub rsa2048 2022-12-14 [E]
See the GnuPG official documentation for more information on how to generate a new keypair: https://www.gnupg.org/gph/en/manual/c14.html
Create a Secret with the gpg key¶
$ gpg --export-secret-keys -a pulp@example.com > /tmp/gpg_private_key.gpg
$ kubectl create secret generic signing-secret --from-file=signing_service.gpg=/tmp/gpg_private_key.gpg
Create a Secret with the signing scripts¶
-
example of a collection signing script
$ SIGNING_SCRIPT_PATH=/tmp $ COLLECTION_SIGNING_SCRIPT=collection_script.sh $ cat<<EOF> "$SIGNING_SCRIPT_PATH/$COLLECTION_SIGNING_SCRIPT" #!/usr/bin/env bash set -u FILE_PATH=\$1 SIGNATURE_PATH="\$1.asc" ADMIN_ID="\$PULP_SIGNING_KEY_FINGERPRINT" PASSWORD="password" # Create a detached signature gpg --quiet --batch --pinentry-mode loopback --yes --passphrase \ \$PASSWORD --homedir ~/.gnupg/ --detach-sign --default-key \$ADMIN_ID \ --armor --output \$SIGNATURE_PATH \$FILE_PATH # Check the exit status STATUS=\$? if [ \$STATUS -eq 0 ]; then echo {\"file\": \"\$FILE_PATH\", \"signature\": \"\$SIGNATURE_PATH\"} else exit \$STATUS fi EOF
-
example of a container signing script
$ SIGNING_SCRIPT_PATH=/tmp $ CONTAINER_SIGNING_SCRIPT=container_script.sh $ cat<<EOF> "$SIGNING_SCRIPT_PATH/$CONTAINER_SIGNING_SCRIPT" #!/usr/bin/env bash set -u MANIFEST_PATH=\$1 IMAGE_REFERENCE="\$REFERENCE" SIGNATURE_PATH="\$SIG_PATH" skopeo standalone-sign \ \$MANIFEST_PATH \ \$IMAGE_REFERENCE \ \$PULP_SIGNING_KEY_FINGERPRINT \ --output \$SIGNATURE_PATH # Check the exit status STATUS=\$? if [ \$STATUS -eq 0 ]; then echo {\"signature_path\": \"\$SIGNATURE_PATH\"} else exit \$STATUS fi EOF
Warning
Make sure to set collection_script.sh
and/or container_script.sh
as key names (using different names would fail operator's execution)
$ kubectl create secret generic signing-scripts --from-file=collection_script.sh=/tmp/collection_script.sh --from-file=container_script.sh=/tmp/container_script.sh
Configure Pulp CR¶
- configure Pulp CR with the Secrets created in the previous steps
$ kubectl edit pulp ... spec: signing_secret: "signing-secret" signing_scripts: "signing-scripts" ...
After configuring Pulp CR the operator should create a new job to store the new signing services into the database:
$ kubectl get jobs
NAME COMPLETIONS DURATION AGE
pulp-signing-metadata-54mtp 1/1 15s 30s
$ kubectl logs job/pulp-signing-metadata-54mtp
...
Signing service 'collection-signing-service' has been successfully removed.
Successfully added signing service collection-signing-service for key 66BBFE010CF70CC92826D9AB71684D7912B09BC1.
Signing service 'container-signing-service' has been successfully removed.
Successfully added signing service container-signing-service for key 66BBFE010CF70CC92826D9AB71684D7912B09BC1.
double-checking if the signing services are stored in the database:
$ PULP_PWD=$(kubectl get secrets pulp-admin-password -ojsonpath='{.data.password}'|base64 -d)
$ kubectl exec deployment/pulp-api -- curl -suadmin:$PULP_PWD localhost:24817/pulp/api/v3/signing-services/|jq
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"pulp_href": "/pulp/api/v3/signing-services/018c0126-1f0c-7803-868d-1a1ee7210db1/",
"pulp_created": "2023-11-22T11:45:25.042451Z",
"name": "container-signing-service",
"public_key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGJFjREBEACS1aBb6sqz1kfO/Ii...",
"pubkey_fingerprint": "66BBFE010CF70CC92826D9AB71684D7912B09BC1",
"script": "/var/lib/pulp/scripts/container_script.sh"
},
{
"pulp_href": "/pulp/api/v3/signing-services/018c0126-1226-7d7d-abae-aebdc040743c/",
"pulp_created": "2023-11-22T11:45:21.522412Z",
"name": "collection-signing-service",
"public_key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGJFjREBE...",
"pubkey_fingerprint": "66BBFE010CF70CC92826D9AB71684D7912B09BC1",
"script": "/var/lib/pulp/scripts/collection_script.sh"
}
]
}
and it should also redeploy pulpcore pods and mount the gpg key:
$ kubectl exec deployment/pulp-api -- gpg -k
------------------------------
pub rsa4096 2022-12-14 [SC]
66BBFE010CF70CC92826D9AB71684D7912B09BC1
uid [ultimate] Collection Signing Service (with no passphrase) <pulp@example.com>
sub rsa2048 2022-12-14 [E]
$ kubectl exec deployment/pulp-worker -- gpg -k
------------------------------
pub rsa4096 2022-12-14 [SC]
66BBFE010CF70CC92826D9AB71684D7912B09BC1
uid [ultimate] Collection Signing Service (with no passphrase) <pulp@example.com>
sub rsa2048 2022-12-14 [E]