Sigstore Self Hosted pour signer des artefacts
Hier, je vous ai présenté comment utiliser
Cosign pour signer et vérifier vos
images Docker. Par contre, j’avais désactivé le stockage des preuves de
signature dans le serveur de transparence rekor
publique. Aujourd’hui, je vous
propose de voir comment avoir un serveur Rekor
self-hosted. Attention au
moment de l’écriture de ce billet cette fonctionnalité est au status
Experimental
.
Installation de kind
Pour tester rekor
, j’ai choisi de le faire sur une instance de cluster kubernetes
créé avec kind
. Pour installer kind
, rien de plus facile avec asdf
.
asdf plugin add kind 13:49:33asdf install kind latestasdf set --home kind latest
Configuration kind pour ajouter un serveur d’ingress
Pour exposer mon service, je vais utiliser le controleur d’ingress nginx qui
peut être déployé dans kind
. Pour l’installer sur notre cluster kind
, il faut
créer un fichier de configuration kind.config
:
kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes: - role: control-plane kubeadmConfigPatches: - | kind: InitConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 80 hostPort: 80 protocol: TCP - containerPort: 443 hostPort: 443 protocol: TCP
On peut créer le cluster :
kind create cluster --config kind.configkubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
Au bout de quelques instants, vous devriez avoir un pod
ingress-nginx-controller-xxxxxxxxx-xxxx
dans le namespace
ingress-nginx
.
> kubectl get pods -n ingress-nginxNAME READY STATUS RESTARTS AGEingress-nginx-admission-create-5mbz8 0/1 Completed 0 5h5mingress-nginx-admission-patch-gsj58 0/1 Completed 1 5h5mingress-nginx-controller-6b7f45576b-qxfxc 1/1 Running 0 5h5m
Déploiement de la suite sigstore
Bon reste à déployer toute la suite Sigstore. Et bonne nouvelle, on a un chart
Helm
à notre disposition.
helm repo add sigstore https://sigstore.github.io/helm-chartshelm repo update
Avant de l’utiliser, nous allons créer le fichier de values.
helm show values sigstore/scaffold > values.yaml
Editer le fichier et activer les composants : fulcio, ctlog, tuf et
CopySecretjob : enabled: true
.
Un exemple de fichier de values:
---# Fulciofulcio: enabled: true namespace: name: fulcio-system create: true forceNamespace: fulcio-system createcerts: fullnameOverride: fulcio-createcerts ctlog: enabled: false createctconfig: logPrefix: sigstorescaffolding server: fullnameOverride: fulcio-server ingress: http: annotations: cert-manager.io/cluster-issuer: "vault-issuer" className: nginx hosts: - host: fulcio.robert.local path: / tls: - secretName: fulcio-tls hosts: - fulcio.robert.local config: contents: OIDCIssuers: https://oauth2.sigstore.dev/auth: IssuerURL: https://oauth2.sigstore.dev/auth ClientID: sigstore Type: email IssuerClaim: $.federated_claims.connector_id
# CTLogctlog: enabled: true namespace: name: ctlog-system create: true forceNamespace: ctlog-system fullnameOverride: ctlog createcerts: fullnameOverride: ctlog-createcerts createtree: fullnameOverride: ctlog-createtree displayName: ctlog-tree# Rekorrekor: enabled: true namespace: name: rekor-system create: true forceNamespace: rekor-system fullnameOverride: rekor server: fullnameOverride: rekor-server ingress: className: nginx annotations: cert-manager.io/cluster-issuer: "vault-issuer" hosts: - host: rekor.robert.local path: / tls: - secretName: rekor-tls hosts: - rekor.robert.local redis: fullnameOverride: rekor-redis trillian: enabled: false
# Trilliantrillian: enabled: true namespace: name: trillian-system create: true forceNamespace: trillian-system fullnameOverride: trillian logServer: name: trillian-logserver fullnameOverride: trillian-logserver portHTTP: 8090 portRPC: 8091 logSigner: name: trillian-logsigner fullnameOverride: trillian-logsigner mysql: fullnameOverride: trillian-mysql
tuf: enabled: true namespace: name: tuf-system create: true forceNamespace: tuf-system fullnameOverride: tuf ingress: className: nginx annotations: cert-manager.io/cluster-issuer: "vault-issuer" http: hosts: - host: tuf.robert.local path: / tls: - secretName: tuf-tls hosts: - tuf.robert.local
secrets: rekor: name: rekor-public-key path: rekor-pubkey fulcio: name: fulcio-server-secret path: fulcio-cert ctlog: name: ctlog-public-key path: ctlog-pubkey
copySecretJob: enabled: true name: copy-secrets-job registry: docker.io repository: alpine/k8s version: sha256:fb0d2db81fb0f98abb1adf5246d6f0f4d19f34031afe4759cb7ad8e2eb8d2c01 imagePullPolicy: IfNotPresent serviceaccount: tuf-secret-copy-job backoffLimit: 6
tsa: enabled: false namespace: name: tsa-system create: true forceNamespace: tsa-system server: fullnameOverride: tsa-server
Nous allons générer les certificats de rekor, fulcio et tuf avec mkcert:
for service_name in rekor fulcio tuf; domkcert ${service_name}.robert.local localhost 127.0.0.1 ::1done
On déploie la stack :
helm upgrade -i scaffold sigstore/scaffold -n sigstore --create-namespace --values scaffold.values.yaml
Release "scaffold" does not exist. Installing it now.NAME: scaffoldLAST DEPLOYED: Thu Aug 31 08:38:28 2023NAMESPACE: sigstoreSTATUS: deployedREVISION: 1TEST SUITE: None
Au bout de quelques minutes, vous trouverez en fait plusieurs composants :
- Le serveur
rekor
. - Un serveur
redis
. - Un serveur de bdd
mysql
. - Un serveur de log
trillian
, produit sigstore également. - Un serveur
ctflog
- Un serveur
fulcio
- Et quelques jobs dont certains en erreur mais c’est normal !
Attendez que tout soit démarré !
kubectcl get pod -A --watchNAMESPACE NAME READY STATUS RESTARTS AGEctlog-system ctlog-56fbc5595f-8trzt 1/1 Running 0 4m45sctlog-system ctlog-createtree-7vdgs 0/1 Completed 0 4m45sctlog-system scaffold-ctlog-createctconfig-chhmb 0/1 Completed 0 4m45sfulcio-system fulcio-createcerts-mrpkd 0/1 Completed 0 4m45sfulcio-system fulcio-server-7cd549dc9b-2hw4f 1/1 Running 0 4m45singress-nginx ingress-nginx-admission-create-n64qz 0/1 Completed 0 9m56singress-nginx ingress-nginx-admission-patch-k8tcv 0/1 Completed 0 9m56singress-nginx ingress-nginx-controller-6b7f45576b-pbxzb 1/1 Running 0 9m56skube-system coredns-5d78c9869d-659ns 1/1 Running 0 11mkube-system coredns-5d78c9869d-pgh42 1/1 Running 0 11mkube-system etcd-kind-control-plane 1/1 Running 0 12mkube-system kindnet-v4x9k 1/1 Running 0 11mkube-system kube-apiserver-kind-control-plane 1/1 Running 0 12mkube-system kube-controller-manager-kind-control-plane 1/1 Running 0 12mkube-system kube-proxy-875cf 1/1 Running 0 11mkube-system kube-scheduler-kind-control-plane 1/1 Running 0 12mlocal-path-storage local-path-provisioner-6bc4bddd6b-4tvd7 1/1 Running 0 11mrekor-system rekor-redis-5d665cddb8-mrsh9 1/1 Running 0 4m45srekor-system rekor-server-75c967c64-p4jc2 1/1 Running 0 4m45srekor-system scaffold-rekor-createtree-vt8wb 0/1 Completed 0 4m45strillian-system scaffold-trillian-createdb-22t9s 0/1 Error 0 4m45strillian-system scaffold-trillian-createdb-9jwgm 0/1 Completed 0 3m55strillian-system trillian-logserver-68bf4cbbc8-jd52q 1/1 Running 0 4m45strillian-system trillian-logsigner-754cd6894-bk6hr 1/1 Running 0 4m45strillian-system trillian-mysql-64dbf8864-cngn2 1/1 Running 0 4m45stuf-system copy-secrets-job-fzv89 0/3 Completed 0 4m45stuf-system scaffold-tuf-tuf-7fd95b87cd-gzrwv 1/1 Running 0 4m45s
On crée les secrets stockant les certificats :
for service_name in rekor fulcio tuf; dokubectl create secret -n ${service_name}-system tls ${service_name}-tls --key=${service_name}.robert.local+3-key.pem --cert=${service_name}.robert.local+3.pemdone
secret/rekor-tls createdsecret/fulcio-tls createdsecret/tuf-tls created
On récupère l’adresse du container :
docker container inspect kind-control-plane \ --format '{{ .NetworkSettings.Networks.kind.IPAddress }}'
172.19.0.2
On édite le fichier /etc/hosts
:
vi /etc/hosts
Ajoutez cette ligne :
172.19.0.2 rekor.robert.local172.19.0.2 fulcio.robert.local172.19.0.2 tuf.robert.local
On teste que le serveur rekor
est accessible et que le certificat est accepté:
curl https://rekor.robert.local<!DOCTYPE html><html lang="en-us">
<head> <meta property="og:title" content="sigstore" /> <meta property="og:description" content="A non-profit, public good software signing & transparency service" /> <meta property="og:type" content="website" /> <meta property="og:url" content="/" /> <meta name="description" content="A non-profit, public good software signing & transparency service" /> <meta charset="utf-8"> <title>sigstore</title>
<link href="https://fonts.googleapis.com/css?family=Catamaran:400,600" rel="stylesheet"></head>
<body> <h1> Rekor Server </h1> <h2> A non-profit, public good software signing & transparency service. <p>To learn more visit <a href="https://sigstore.dev">Sigstore project page</a></p> </h2>
<p>Currently storing <span id="count">some</span> items.</p>
<footer> <p>Copyright © sigstore a Series of LF Projects, LLC For web site terms of use, trademark policy and general project policies please see <a href="https://lfprojects.org">https://lfprojects.org</a>.</p> </footer>
<script type="text/javascript">const url = '/api/v1/log/';function update() { fetch(url, {headers: {'Accept': 'application/json'}}).then((resp) => { resp.json().then((j) => { let count = j.treeSize; document.getElementById('count').innerText = count; }).catch(console.error); }).catch(console.error);}update(); // Update immediately on page load.setInterval(update, 10000); // Update the counter every 10 seconds. </script></body></html>
Il faut maintenant initialisé le serveur tuf :
kubectl -n tuf-system get secrets tuf-root -ojsonpath='{.data.root}' | base64 -d > root.json
Vous devriez obtenir le fichier root.json avec ce contenu :
cat root.json{ "signed": { "_type": "root", "spec_version": "1.0", "version": 1, "expires": "2024-03-02T06:42:45Z", "keys": { "1ddd1e0f11401c5b981bd67edaf3c2779a963cc9739cfb7136a4be48b0ae7a6e": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "507e72d4024fa5f12289bbe9ddb24259939eeece2f43100be3deaab8e7fed859" } }, "1f28940a9d054ddcd3d34603b6b0db2bad0b5c79ce822bb206682fa5f3595f01": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "4a50d6d166fdc9648e7ffc3db6eae7f09fadc6d47c2012a3382d159daab42870" } }, "777ba66bf28f946c2182ec68260230b1aded26ff5b80888a6777354f674a92fb": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "5b1940fe025d8e4cf4ea4b04b8e3260b20b6e460eef3e31e98ff9d5021dfdefe" } }, "acbf0880ad51c944a937b1a5b869bbe423279fa803d04fcc13d7ecb49e50b456": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "6cdfd0edf6f1e99db99a3a3bad5f66f2bf7228c4108d6c1774986235daf1d152" } } }, "roles": { "root": { "keyids": [ "777ba66bf28f946c2182ec68260230b1aded26ff5b80888a6777354f674a92fb" ], "threshold": 1 }, "snapshot": { "keyids": [ "1ddd1e0f11401c5b981bd67edaf3c2779a963cc9739cfb7136a4be48b0ae7a6e" ], "threshold": 1 }, "targets": { "keyids": [ "1f28940a9d054ddcd3d34603b6b0db2bad0b5c79ce822bb206682fa5f3595f01" ], "threshold": 1 }, "timestamp": { "keyids": [ "acbf0880ad51c944a937b1a5b869bbe423279fa803d04fcc13d7ecb49e50b456" ], "threshold": 1 } }, "consistent_snapshot": false }, "signatures": [ { "keyid": "777ba66bf28f946c2182ec68260230b1aded26ff5b80888a6777354f674a92fb", "sig": "188589b269dd79f899718aac806375a0a437c23e7691434fd28b83ca719ee2b309f70f82e7a497245f19dfeacc265ab53e74aa68a8de9d151c38268fb2864c04" } ]}
Initialisons le serveur tuf :
cosign -d initialize --root root.json --mirror https://tuf.robert.localRoot status: { "local": "/home/bob/.sigstore/root", "remote": "https://tuf.robert.local", "metadata": { "root.json": { "version": 1, "len": 2178, "expiration": "02 Mar 24 06:42 UTC", "error": "" }, "snapshot.json": { "version": 1, "len": 618, "expiration": "02 Mar 24 06:42 UTC", "error": "" }, "targets.json": { "version": 1, "len": 1028, "expiration": "02 Mar 24 06:42 UTC", "error": "" }, "timestamp.json": { "version": 1, "len": 619, "expiration": "02 Mar 24 06:42 UTC", "error": "" } }, "targets": [ "ctfe.pub", "fulcio_v1.crt.pem", "rekor.pub" ]}
Cool ! Passons à la signature :)
Installation de la CLI Rekor
Avant de signer notre image de conteneur, installons la cli Rekor
:
wget https://github.com/sigstore/rekor/releases/download/v1.2.2/rekor-cli-linux-amd64 -O rekor-clichmod +x rekor-clisudo install rekor-cli /usr/local/bin
On teste l’accès à notre serveur local :
rekor-cli loginfo --rekor_server https://rekor.robert.local
No previous log state stored, unable to prove consistencyUnable to store previous state: do not persist state for empty logsUnable to store previous state: do not persist state for empty logsVerification Successful!Active Tree Size: 0Total Tree Size: 0Root Hash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Timestamp: 2023-08-31T06:54:22ZTreeID: 2639852854654503233
Super !
Signature de l’image avec Cosign avec notre serveur Rekor
On reprend les commandes du billet d’hier pour signer notre image sauf qu’on
indique l’adresse du serveur rekor
:
docker pull registry.gitlab.com/dockerfiles6/images/demo-cosign:latestexport IMAGE=`docker inspect --format='{{index .RepoDigests 0}}' registry.gitlab.com/dockerfiles6/images/demo-cosign:latest`export REKOR_URL=https://rekor.robert.localexport FULCIO_URL=https://fulcio.robert.local
Generating ephemeral keys...Retrieving signed certificate...
The sigstore service, hosted by sigstore a Series of LF Projects, LLC, is provided pursuant to the Hosted Project Tools Terms of Use, available at https://lfprojects.org/policies/hosted-project-tools-terms-of-use/. Note that if your submission includes personal data associated with this signed artifact, it will be part of an immutable record. This may include the email address associated with the account with which you authenticate your contractual Agreement. This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later, and is subject to the Immutable Record notice at https://lfprojects.org/policies/hosted-project-tools-immutable-records/.
By typing 'y', you attest that (1) you are not submitting the personal data of any other person; and (2) you understand and agree to the statement and the Agreement terms at the URLs listed above.Are you sure you would like to continue? [y/N] yYour browser will now be opened to:https://oauth2.sigstore.dev/auth/auth?access_type=online&client_id=sigstore&code_challenge=C_QL_huOKcxcHhVSnehyy5RhfHmA3TznIZqAdNAPCvg&code_challenge_method=S256&nonce=2UjtssQFjscrEvjyvBxOETXwuF1&redirect_uri=http%3A%2F%2Flocalhost%3A33809%2Fauth%2Fcallback&response_type=code&scope=openid+email&state=2Ujtslba54Tl5MLEmqLSBMBWVpXSuccessfully verified SCT...tlog entry created with index: 0Pushing signature to: registry.gitlab.com/dockerfiles6/images/demo-cosign
Normalement une fenêtre s’ouvre avec une demande d’authentification. Pour le
moment, on utilise la configuration d’OIDC de sigstore mais on peut imaginer
utiliser celui de --
(self-hosté) par exemple. Ça fera l’objet d’un projet
billet.
Vérification de la signature
Et là cela fonctionne-t-il ? :
cosign verify --rekor-url=$REKOR_URL --certificate-identity-regexp=.+ --certificate-oidc-issuer-regexp=.+ $IMAGE | jq -r .**Warning** Missing fallback target fulcio.crt.pem, skipping**Warning** Missing fallback target fulcio_intermediate_v1.crt.pem, skipping
Verification for registry.gitlab.com/dockerfiles6/images/demo-cosign@sha256:c3b002f3a90054d0f0db12f43f608291610dd61af7f5b06f2a05fdeac1096b40 --The following checks were performed on each of these signatures: - The cosign claims were validated - Existence of the claims in the transparency log was verified offline - The code-signing certificate was verified using trusted certificate authority certificates[ { "critical": { "identity": { "docker-reference": "registry.gitlab.com/dockerfiles6/images/demo-cosign" }, "image": { "docker-manifest-digest": "sha256:c3b002f3a90054d0f0db12f43f608291610dd61af7f5b06f2a05fdeac1096b40" }, "type": "cosign container image signature" }, "optional": { "1.3.6.1.4.1.57264.1.1": "https://github.com/login/oauth", "Bundle": { "SignedEntryTimestamp": "MEQCIFA1nuEu4X0/HaGUs/Pi2wURTRTNa/2aLYV+9rSUBny2AiAdsANTHFDFedNu5JMkIM3ItLrqJLIZ9V1PboGZeLuQXA==", "Payload": { "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MjVhNmIyOTcxOWI1YzRhOWMyZDNlZTIzZGU0YmY4OGExNGM3NDE0NjRlN2YwNDdmOTE2NjAyMTg1ZTdmNGE1In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJSGV2aTc3Y3gzcnIrYWNoU053WEpYWHdNL0JFcGVudVM2RThuQzA3M0hQZUFpRUFnYUlOS1FMb3RmSkp5eWtyOHN1WkFlZjhXOU85a3c0OXZTRUppT2JZYU5ZPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVVjNla05EUVhGMVowRjNTVUpCWjBsVlRrcG1lamhyVTNOVmNraEVVVVU0SzFGUldFb3phbVp1Tm5jMGQwUlJXVXBMYjFwSmFIWmpUa0ZSUlV3S1FsRkJkMlpxUlUxTlFXOUhRVEZWUlVKb1RVUldWazVDVFZKTmQwVlJXVVJXVVZGSlJYZHdSRmxYZUhCYWJUbDVZbTFzYUUxU1dYZEdRVmxFVmxGUlNBcEZkekZVV1ZjMFoxSnVTbWhpYlU1d1l6Sk9kazFTV1hkR1FWbEVWbEZSU2tWM01ERk9SR2RuVkZkR2VXRXlWakJKUms0d1RWRTBkMFJCV1VSV1VWRlNDa1YzVlRGT2Vra3pUa1JGV2sxQ1kwZEJNVlZGUTJoTlVWUkhiSFZrV0dkblVtMDVNV0p0VW1oa1IyeDJZbXBCWlVaM01IbE5la0UwVFhwRmQwNXFWVE1LVFZSQ1lVWjNNSGxOZWtFMFRYcEZkMDU2UVROTlZFSmhUVUZCZDFkVVFWUkNaMk54YUd0cVQxQlJTVUpDWjJkeGFHdHFUMUJSVFVKQ2QwNURRVUZUWlFvM2FFcERUelJqUTJaclJXNWhXVkZTU210TFowWlBUR0ZqVGxaNVRXSlFTVzgyZEhORlRIVnBNalE1UTFsVWNIaDNiemh0WkcxdVVuQkpOVlZ4WldGa0NuazJlVWcwV1VSeVRrTjNRV0pNY1hZemVtSllielJKUW1kRVEwTkJXSGQzUkdkWlJGWlNNRkJCVVVndlFrRlJSRUZuWlVGTlFrMUhRVEZWWkVwUlVVMEtUVUZ2UjBORGMwZEJVVlZHUW5kTlJFMUNNRWRCTVZWa1JHZFJWMEpDVW5GdFRUSnNaMWx3Y0RoNlIwUm9XRkJxVVZvcmJXTjFUM0JuZWtGbVFtZE9WZ3BJVTAxRlIwUkJWMmRDVTFablFYZFhhMU0zUmxob01sUmhkV2xOV0d0S1kxaENMMGMzUkVGeFFtZE9Wa2hTUlVKQlpqaEZTVVJCWldkU2VIbGlNa3BzQ21OdVVYVmpNMUpzWTBkb2FHSnRWWFZOYW1oQldqSXhhR0ZYZDNWWk1qbDBUVU4zUjBOcGMwZEJVVkZDWnpjNGQwRlJSVVZJYldnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJJeVpIQmlhVGwyV1ZoV01HRkVRWFZDWjI5eVFtZEZSVUZaVHk5TlFVVkpRa05CVFVodGFEQmtTRUo2VDJrNGRncGFNbXd3WVVoV2FVeHRUblppVXpsellqSmtjR0pwT1haWldGWXdZVVJEUW1sbldVdExkMWxDUWtGSVYyVlJTVVZCWjFJNFFraHZRV1ZCUWpKQlNWbEJDbk5DWm1rMVUyMDFlbWg0U2xGM1RIRkpla2RZWmxkaVpsQmlaa2x4VGtkR2FHTlVSblVyWld0QlFVRkNhV3R3YUhKeVFVRkJRVkZFUVVWamQxSlJTV2dLUVVrek1ISkllRGhVTVhaVmVVaGxRM2Q1V0M4MWJsQjZNbFU0YTBWcE9WRkNaV1l6WTNKWEszTnhNbkZCYVVKWmFrVjZUMk5YTVRjck9WRlRNVU5KVEFwb2MwTkljblJoYlZoV05tNXRNbGhYZFdOU2VuRlVaRzk0ZWtGT1FtZHJjV2hyYVVjNWR6QkNRVkZ6UmtGQlQwTkJaMFZCY0ROS2VGcFNXbTFoWTBaRENuUmtiV2RaWm5SQlFXTkJabXRSVVVsT2NERlJLM3BWYWxVMWVtMWllbmhtVFRVd2NGaEJWWFpTVlVRNFptSlBkRGxOZWxJeGFrcHVTblp1Y0RsVmNXZ0tlbFptWnpSMGRIQkhXVXNyWjB4MmVHZzNXbU5IYVcwNVFYUmtORXBpYTJNMVkyOTFMMWg0UkdkM1NXTjVTbWxhWkc1bGQzbFBNR0YxVm1WMWNGTmxNQXBLYkZsUmJWSkNRMkpFZUVNeVRHWkJLM1k1WW1sR1dsQklUSFJRUm1abWQzVTVhMVF6UVRZM09VTnFaRkpsVURscWNIWndPRFIyYkVWeVVVYzFaRlp0Q25JdllWUkxNMHBJYURKaGEyVXJlazVTTnprNFQyUlFhVkZSUjNsQlMycFJiV3hMTVhkWlNGUkpZbTFCVEhGRlFpOTJjbUlyYm0xSVQzZDJhSE4xTkZnS2JXWkZhMlpOT0daNVJGWk9SMW96T0U5M1EwMTNaRlIwV201Q05GWjNOMHQxV21wNk5YSmxORTEzY1ZsVU5XODVTMng1YjAxUlNub3JkV1V2YVRKbVVBcEhRWGRNYUNzcmRHRnNRa0owWkVaMmVITnphRlJFZEdwdFlsWm1TQ3N6UVVSbWMycE9iMmcwVEhSdWN6WjBiMVV6VlZOTFFqTnFOV0oxVjFGeWIzQjNDa0ZYTW1SRlUxRjRkV1ExYjJSMGFFOWxPVUZPZW5wNGNGVk1jeXRsYTFkdGVraEdNak52TmtoV2VYTmtPRUo1TnpsRk9XSTVabTF2T0ZoR1ZXNTVOWG9LTURaT1MwZ3dhakoyYlVOa2MxcElkblZ1Vm14VlVYWXhSbUpvZGxadVJrMTRNV0o2ZGxwbmNtUnhUV3BxU1RoQ1ExSmpTMDFITTJabE5FVnlkRlJLVmdvMU5GaENlVE5JVlZBdmEwOVJUbTV4T1V4TGFtSTRWVzVCWWtKeFJXZzFUSEp1WVdjMU1YSnRWREZUUVRCaVptMHdaVlkwYkZOeGExVk5Oek5VWVVOU0NucGtaVTEwT1ZCd1JtUkNaWE5aTkhOdmNXWktZVU5KT1RWR1VXTkplRk5pTXpKWWFrWnliMjA1V0M5WU1FSXJNR0o1YmpBeWMwbHZlSHBCWTJsRUszWUtiMFF3Vm5JeVZFbzVRMDVzTmxkV2VqUnlaRkV4Ykd0ck1sVXZlbk51ZHowS0xTMHRMUzFGVGtRZ1EwVlNWRWxHU1VOQlZFVXRMUzB0TFFvPSJ9fX19", "integratedTime": 1693465031, "logIndex": 0, "logID": "a558e7d223efd979dace1b9323ce425f376f9e9c971900e2e1a0a6fdb6af312e" } }, "Issuer": "https://github.com/login/oauth", "Subject": "robert.stephane.28@gmail.com" } }]
Yes !!!!
rekor-cli get --log-index 0 --rekor_server https://rekor.robert.local --format json | jq -r .{ "Attestation": "", "AttestationType": "", "Body": { "HashedRekordObj": { "data": { "hash": { "algorithm": "sha256", "value": "625a6b29719b5c4a9c2d3ee23de4bf88a14c741464e7f047f916602185e7f4a5" } }, "signature": { "content": "MEUCIHevi77cx3rr+achSNwXJXXwM/BEpenuS6E8nC073HPeAiEAgaINKQLotfJJyykr8suZAef8W9O9kw49vSEJiObYaNY=", "publicKey": { "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUV3ekNDQXF1Z0F3SUJBZ0lVTkpmejhrU3NVckhEUUU4K1FRWEozamZuNnc0d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2ZqRU1NQW9HQTFVRUJoTURWVk5CTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saE1SWXdGQVlEVlFRSApFdzFUWVc0Z1JuSmhibU5wYzJOdk1SWXdGQVlEVlFRSkV3MDFORGdnVFdGeWEyVjBJRk4wTVE0d0RBWURWUVFSCkV3VTFOekkzTkRFWk1CY0dBMVVFQ2hNUVRHbHVkWGdnUm05MWJtUmhkR2x2YmpBZUZ3MHlNekE0TXpFd05qVTMKTVRCYUZ3MHlNekE0TXpFd056QTNNVEJhTUFBd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTZQo3aEpDTzRjQ2ZrRW5hWVFSSmtLZ0ZPTGFjTlZ5TWJQSW82dHNFTHVpMjQ5Q1lUcHh3bzhtZG1uUnBJNVVxZWFkCnk2eUg0WURyTkN3QWJMcXYzemJYbzRJQmdEQ0NBWHd3RGdZRFZSMFBBUUgvQkFRREFnZUFNQk1HQTFVZEpRUU0KTUFvR0NDc0dBUVVGQndNRE1CMEdBMVVkRGdRV0JCUnFtTTJsZ1lwcDh6R0RoWFBqUVorbWN1T3BnekFmQmdOVgpIU01FR0RBV2dCU1ZnQXdXa1M3RlhoMlRhdWlNWGtKY1hCL0c3REFxQmdOVkhSRUJBZjhFSURBZWdSeHliMkpsCmNuUXVjM1JsY0doaGJtVXVNamhBWjIxaGFXd3VZMjl0TUN3R0Npc0dBUVFCZzc4d0FRRUVIbWgwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2IyZHBiaTl2WVhWMGFEQXVCZ29yQmdFRUFZTy9NQUVJQkNBTUhtaDBkSEJ6T2k4dgpaMmwwYUhWaUxtTnZiUzlzYjJkcGJpOXZZWFYwYURDQmlnWUtLd1lCQkFIV2VRSUVBZ1I4QkhvQWVBQjJBSVlBCnNCZmk1U201emh4SlF3THFJekdYZldiZlBiZklxTkdGaGNURnUrZWtBQUFCaWtwaHJyQUFBQVFEQUVjd1JRSWgKQUkzMHJIeDhUMXZVeUhlQ3d5WC81blB6MlU4a0VpOVFCZWYzY3JXK3NxMnFBaUJZakV6T2NXMTcrOVFTMUNJTApoc0NIcnRhbVhWNm5tMlhXdWNSenFUZG94ekFOQmdrcWhraUc5dzBCQVFzRkFBT0NBZ0VBcDNKeFpSWm1hY0ZDCnRkbWdZZnRBQWNBZmtRUUlOcDFRK3pValU1em1ienhmTTUwcFhBVXZSVUQ4ZmJPdDlNelIxakpuSnZucDlVcWgKelZmZzR0dHBHWUsrZ0x2eGg3WmNHaW05QXRkNEpia2M1Y291L1h4RGd3SWN5SmlaZG5ld3lPMGF1VmV1cFNlMApKbFlRbVJCQ2JEeEMyTGZBK3Y5YmlGWlBITHRQRmZmd3U5a1QzQTY3OUNqZFJlUDlqcHZwODR2bEVyUUc1ZFZtCnIvYVRLM0pIaDJha2Urek5SNzk4T2RQaVFRR3lBS2pRbWxLMXdZSFRJYm1BTHFFQi92cmIrbm1IT3d2aHN1NFgKbWZFa2ZNOGZ5RFZOR1ozOE93Q013ZFR0Wm5CNFZ3N0t1Wmp6NXJlNE13cVlUNW85S2x5b01RSnordWUvaTJmUApHQXdMaCsrdGFsQkJ0ZEZ2eHNzaFREdGptYlZmSCszQURmc2pOb2g0THRuczZ0b1UzVVNLQjNqNWJ1V1Fyb3B3CkFXMmRFU1F4dWQ1b2R0aE9lOUFOenp4cFVMcytla1dtekhGMjNvNkhWeXNkOEJ5NzlFOWI5Zm1vOFhGVW55NXoKMDZOS0gwajJ2bUNkc1pIdnVuVmxVUXYxRmJodlZuRk14MWJ6dlpncmRxTWpqSThCQ1JjS01HM2ZlNEVydFRKVgo1NFhCeTNIVVAva09RTm5xOUxLamI4VW5BYkJxRWg1THJuYWc1MXJtVDFTQTBiZm0wZVY0bFNxa1VNNzNUYUNSCnpkZU10OVBwRmRCZXNZNHNvcWZKYUNJOTVGUWNJeFNiMzJYakZyb205WC9YMEIrMGJ5bjAyc0lveHpBY2lEK3YKb0QwVnIyVEo5Q05sNldWejRyZFExbGtrMlUvenNudz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=" } } } }, "LogIndex": 0, "IntegratedTime": 1693465031, "UUID": "24a2a42f4cfb8941bfe184574ae20e7444b406693ec70484cd661f92fb079a9996c9a1af6ba384a4", "LogID": "a558e7d223efd979dace1b9323ce425f376f9e9c971900e2e1a0a6fdb6af312e"}
Excellent non ?
Conclusion
Bon maintenant que la signature fonctionne, il faut passer à l’attachement des attestations dont le certificat d’analyse de vulnérabilités et des attestions de validation d’étapes de build avec in-toto ↗