Aller au contenu
Sécurité medium

Rekor : le log de transparence de Sigstore

26 min de lecture

Rekor est le log de transparence de l’écosystème Sigstore. Il enregistre chaque signature dans un registre public et immuable, permettant de prouver qu’une signature existait à un moment précis, d’auditer les signatures d’une identité, et de détecter les signatures frauduleuses.

Pour comprendre comment Rekor s’intègre dans l’écosystème Sigstore (avec Fulcio et Cosign), consultez le guide Sigstore.

Avec la signature keyless de Sigstore, vous signez avec un certificat Fulcio qui expire après 10 minutes. Sans Rekor, impossible de prouver que la signature était valide au moment de sa création.

Le problème des certificats éphémères

Rekor résout ce problème en enregistrant la signature au moment de sa création avec un horodatage cryptographique :

La solution Rekor

PropriétéDescriptionPourquoi c’est important
ImmuableUne entrée ne peut pas être modifiéeGarantit l’intégrité historique
Append-onlyOn ne peut qu’ajouter, jamais réécrireEmpêche la réécriture de l’historique
VérifiableStructure en arbre de MerklePreuves cryptographiques d’inclusion
PublicTout le monde peut lire et auditerTransparence totale
HorodatéTimestamp RFC3161 sur chaque entréePreuve temporelle incontestable

Rekor utilise un arbre de Merkle : une structure où chaque nœud est le hash de ses enfants. Si vous modifiez une seule entrée, le hash racine change.

Structure d'un arbre de Merkle

Pour prouver qu’une entrée existe, il suffit de fournir les hashs intermédiaires qui permettent de recalculer le root hash :

Preuve d'inclusion pour l'entrée B

Votre entreprise veut auditer toutes les signatures effectuées par ses développeurs sur les 6 derniers mois :

Fenêtre de terminal
# Rechercher toutes les signatures de l'équipe
rekor-cli search --email "@votre-entreprise.com"

Vous configurez une alerte qui vous notifie dès qu’une signature est créée avec votre identité. Si vous recevez une alerte pour une signature que vous n’avez pas faite, vous savez que votre compte est compromis.

Le Cyber Resilience Act (CRA) européen exige la traçabilité des artefacts logiciels. Rekor fournit une preuve cryptographique de qui a signé quoi et quand.

Après un incident de sécurité, vous pouvez retracer l’historique complet des signatures pour identifier le point de compromission.

ScénarioQuestionRéponse de Rekor
AuditQui a signé nos artefacts ce mois-ci ?Liste des signatures par email/hash
CompromissionQuelqu’un a-t-il signé à ma place ?Oui, entrée #12345 le 15/12
ConformitéPreuve de traçabilité ?Inclusion proof + timestamp
IncidentQuand l’image malveillante a-t-elle été signée ?Timestamp précis

Avant de commencer :

  • Connexion Internet : pour accéder à l’instance publique Rekor
  • jq (optionnel) : pour parser les réponses JSON dans vos scripts
Fenêtre de terminal
# Installer jq si nécessaire
# Debian/Ubuntu
sudo apt install jq
# macOS
brew install jq
Fenêtre de terminal
# Télécharger la dernière version
REKOR_VERSION=$(curl -s https://api.github.com/repos/sigstore/rekor/releases/latest | grep tag_name | cut -d '"' -f 4)
curl -LO "https://github.com/sigstore/rekor/releases/download/${REKOR_VERSION}/rekor-cli-linux-amd64"
# Installer
chmod +x rekor-cli-linux-amd64
sudo mv rekor-cli-linux-amd64 /usr/local/bin/rekor-cli
# Vérifier
rekor-cli version

Sortie attendue :

rekor-cli: vX.Y.Z

L’instance publique de Rekor est accessible à rekor.sigstore.dev. C’est l’instance utilisée par défaut par Cosign et gitsign. Elle offre un SLA de 99.5% et est utilisée par npm, PyPI, Kubernetes et des milliers de projets open source.

Chaque entrée dans Rekor peut être identifiée de plusieurs façons :

IdentifiantFormatExempleUsage
IndexEntier séquentiel7403797Position dans le log
UUIDChaîne hexadécimale24296fb24b8ad77a8...Identifiant unique
HashSHA256 de l’artefact97fc222cee7991b5...Recherche par artefact
EmailIdentité OIDCdev@example.comRecherche par signataire

Commençons par vérifier que nous pouvons accéder au log et voir son état actuel :

Fenêtre de terminal
rekor-cli loginfo

Sortie :

Verification Successful!
Active Tree Size: 98765432
Total Tree Size: 98765432
Root Hash: abc123def456...
Timestamp: 2025-12-29T10:30:00Z
ChampSignification
Active Tree SizeNombre d’entrées dans le log
Root HashHash racine de l’arbre de Merkle
TimestampDate de la dernière mise à jour

Le Root Hash est la donnée la plus importante : c’est le hash qui “résume” tout le contenu du log. Si une seule entrée était modifiée, ce hash changerait.

C’est la recherche la plus courante. Elle permet de retrouver toutes les signatures associées à une identité OIDC (votre compte GitHub, Google, etc.) :

Fenêtre de terminal
rekor-cli search --email votre@email.com

Sortie :

Found matching entries (showing first 10):
24296fb24b8ad77a8...
24296fb24b8ad77a9...

Si vous avez une image conteneur ou un fichier et que vous voulez savoir s’il a été signé, utilisez son hash SHA256 :

Fenêtre de terminal
# Calculer le hash d'un fichier local
sha256sum mon-fichier.txt
# Sortie : 97fc222cee7991b5b061d4d4afdb5f3428fcb0c9 mon-fichier.txt
# Rechercher dans Rekor
rekor-cli search --sha 97fc222cee7991b5b061d4d4afdb5f3428fcb0c9

Cette recherche est utile pour vérifier la provenance d’un artefact : a-t-il été signé ? Par qui ? Quand ?

Chaque entrée a un index unique (numéro séquentiel). L’index 0 est la première entrée du log, l’index 1 la deuxième, etc.

Fenêtre de terminal
# Récupérer l'entrée numéro 7403797
rekor-cli get --log-index 7403797

Cette commande retourne toutes les informations de l’entrée : le type d’artefact, le hash, la signature, le certificat utilisé, etc.

L’UUID est l’identifiant unique global d’une entrée. Contrairement à l’index qui dépend de l’instance Rekor, l’UUID est calculé à partir du contenu de l’entrée :

Fenêtre de terminal
rekor-cli get --uuid 24296fb24b8ad77a8d5b76c36...

Une fois que vous avez trouvé une entrée (par email, hash, index ou UUID), vous pouvez afficher tous ses détails :

Fenêtre de terminal
rekor-cli get --log-index 7403797

Sortie typique :

LogID: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
Index: 7403797
IntegratedTime: 2025-06-15T14:30:00Z
UUID: 24296fb24b8ad77a8d5b76c36...
Body: {
"kind": "hashedrekord",
"apiVersion": "0.0.1",
"spec": {
"data": {
"hash": {
"algorithm": "sha256",
"value": "97fc222cee7991b5..."
}
},
"signature": {
"content": "MEUCIQDx...",
"publicKey": {
"content": "LS0tLS1CRUdJTi..."
}
}
}
}

Pour intégrer Rekor dans vos scripts ou pipelines CI/CD, utilisez le format JSON :

Fenêtre de terminal
# Récupérer une entrée en JSON
rekor-cli get --log-index 7403797 --format json
# Extraire le hash de l'artefact avec jq
rekor-cli get --log-index 7403797 --format json | jq -r '.Body.HashedRekordObj.data.hash.value'
# Extraire l'email du signataire
rekor-cli get --log-index 7403797 --format json | jq -r '.Body.HashedRekordObj.signature.publicKey.content' | base64 -d | openssl x509 -noout -email

La vérification est l’opération la plus importante de Rekor. Elle permet de prouver cryptographiquement qu’une signature existe dans le log et qu’elle est valide.

Quand vous vérifiez une entrée, Rekor retourne une inclusion proof (preuve d’inclusion). Cette preuve est un ensemble de hashs qui permettent de recalculer le Root Hash à partir de l’entrée.

Fonctionnement de la preuve d'inclusion

Étapes de vérification pour une entrée B :

  1. Calculer Hash(B)
  2. Calculer Hash(A+B) avec le Hash(A) fourni dans la preuve
  3. Calculer Root = Hash(Hash(A+B) + Hash(C+D))
  4. Comparer avec le Root Hash public
  5. Si égal → l’entrée B existe vraiment dans le log

Pour vérifier qu’une signature est bien dans le log :

Fenêtre de terminal
rekor-cli verify --artifact mon-fichier.txt \
--signature signature.sig \
--public-key cle-publique.pem

Sortie si valide :

Inclusion Proof:
Index: 7403797
Root Hash: abc123...
Tree Size: 98765432
Hashes: [def456..., ghi789...]
Entry was verified in Rekor!
Élément vérifiéSignification
Inclusion proofL’entrée existe bien dans le log
Signature validityLa signature correspond à l’artefact
TimestampLa signature a été créée à un moment précis

En pratique, vous n’avez pas besoin d’appeler rekor-cli verify directement. Cosign vérifie automatiquement les preuves Rekor lors de la vérification d’une signature :

Fenêtre de terminal
# Cosign vérifie automatiquement l'inclusion dans Rekor
cosign verify mon-registry/mon-image:v1.0.0
# Pour désactiver la vérification Rekor (non recommandé)
cosign verify --insecure-ignore-tlog mon-registry/mon-image:v1.0.0

Pour une exploration visuelle, Rekor dispose d’une interface web :

search.sigstore.dev

Rekor Search Interface

Fonctionnalités :

  • Recherche par email, hash, UUID, index
  • Visualisation des détails complets d’une entrée
  • Affichage du certificat décodé
  • Export des données en JSON

L’intégration de Rekor dans vos pipelines CI/CD permet d’automatiser la vérification et la surveillance des signatures.

Intégration Rekor dans un pipeline CI/CD

GitHub Actions avec bonnes pratiques de sécurité :

name: Verify Signatures
on:
push:
branches: [main]
schedule:
- cron: '0 2 * * *' # Vérification quotidienne à 2h
permissions:
contents: read
jobs:
verify:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Install rekor-cli
run: |
REKOR_VERSION=$(curl -s https://api.github.com/repos/sigstore/rekor/releases/latest | grep tag_name | cut -d '"' -f 4)
curl -LO "https://github.com/sigstore/rekor/releases/download/${REKOR_VERSION}/rekor-cli-linux-amd64"
chmod +x rekor-cli-linux-amd64
sudo mv rekor-cli-linux-amd64 /usr/local/bin/rekor-cli
- name: Search for signatures
run: |
# Rechercher les signatures de l'image
rekor-cli search --sha $(sha256sum mon-artefact | cut -d ' ' -f 1)
- name: Verify inclusion proof
run: |
rekor-cli verify --artifact mon-artefact \
--signature signature.sig \
--public-key public-key.pem

Vérifiez automatiquement les attestations SLSA de vos images :

name: SLSA Audit
on:
schedule:
- cron: '0 */6 * * *' # Toutes les 6 heures
workflow_dispatch:
permissions:
contents: read
jobs:
audit:
runs-on: ubuntu-24.04
steps:
- name: Get latest release
id: release
run: |
LATEST_TAG=$(gh api repos/${{ github.repository }}/tags --jq '.[0].name')
echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get image digest
id: digest
run: |
IMAGE="ghcr.io/${{ github.repository }}:${{ steps.release.outputs.tag }}"
DIGEST=$(docker pull "${IMAGE}" 2>&1 | grep "Digest:" | cut -d' ' -f2)
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
- name: Verify SLSA attestation
run: |
gh attestation verify \
oci://ghcr.io/${{ github.repository }}@${{ steps.digest.outputs.digest }} \
--owner ${{ github.repository_owner }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check Rekor entries
run: |
# Installer rekor-cli
REKOR_VERSION=$(curl -s https://api.github.com/repos/sigstore/rekor/releases/latest | grep tag_name | cut -d '"' -f 4)
curl -LO "https://github.com/sigstore/rekor/releases/download/${REKOR_VERSION}/rekor-cli-linux-amd64"
chmod +x rekor-cli-linux-amd64
sudo mv rekor-cli-linux-amd64 /usr/local/bin/rekor-cli
# Rechercher les signatures de cette image
IMAGE_SHA=$(echo "${{ steps.digest.outputs.digest }}" | cut -d':' -f2)
echo "Searching Rekor for image SHA: ${IMAGE_SHA}"
rekor-cli search --sha "${IMAGE_SHA}"
- name: Report audit results
if: always()
run: |
if [ "${{ job.status }}" == "success" ]; then
echo "✅ Audit passed for ${{ steps.release.outputs.tag }}"
echo "- SLSA attestation: verified"
echo "- Rekor entries: found"
else
echo "❌ Audit failed for ${{ steps.release.outputs.tag }}"
exit 1
fi

Créez un job qui surveille les signatures pour votre domaine :

monitor-signatures.sh
#!/bin/bash
EMAIL_DOMAIN="@votre-entreprise.com"
LAST_CHECK_FILE="/tmp/rekor-last-check"
# Récupérer le dernier index vérifié
if [ -f "$LAST_CHECK_FILE" ]; then
LAST_INDEX=$(cat "$LAST_CHECK_FILE")
else
LAST_INDEX=0
fi
# Récupérer la taille actuelle du log
CURRENT_SIZE=$(rekor-cli loginfo --format json | jq -r '.ActiveTreeSize')
# Vérifier les nouvelles entrées
for i in $(seq $((LAST_INDEX + 1)) $CURRENT_SIZE); do
ENTRY=$(rekor-cli get --log-index $i --format json 2>/dev/null)
if echo "$ENTRY" | grep -q "$EMAIL_DOMAIN"; then
echo "Nouvelle signature détectée à l'index $i"
# Envoyer une alerte (Slack, email, etc.)
fi
done
echo "$CURRENT_SIZE" > "$LAST_CHECK_FILE"

L’instance publique de Rekor convient à la plupart des cas d’usage open source. Cependant, certaines situations nécessitent une instance privée.

SituationPourquoi une instance privée
Air-gappedPas d’accès à Internet depuis l’environnement de build
ConfidentialitéLes emails/signatures ne doivent pas être publics
ConformitéLes données doivent rester dans une région géographique
PerformanceContrôle total sur la latence et la disponibilité
SouverainetéIndépendance vis-à-vis de l’infrastructure Sigstore

Une instance Rekor nécessite plusieurs composants :

Architecture Rekor privé

Voici un exemple de déploiement simplifié pour tests et développement :

docker-compose.yml
version: '3.8'
services:
mysql:
image: mariadb:10.11
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: trillian
MYSQL_USER: trillian
MYSQL_PASSWORD: trillian
volumes:
- mysql-data:/var/lib/mysql
redis:
image: redis:7-alpine
trillian-log-server:
image: gcr.io/trillian-opensource-ci/log_server:latest
command:
- --storage_system=mysql
- --mysql_uri=trillian:trillian@tcp(mysql:3306)/trillian
- --rpc_endpoint=0.0.0.0:8090
- --http_endpoint=0.0.0.0:8091
depends_on:
- mysql
trillian-log-signer:
image: gcr.io/trillian-opensource-ci/log_signer:latest
command:
- --storage_system=mysql
- --mysql_uri=trillian:trillian@tcp(mysql:3306)/trillian
- --rpc_endpoint=0.0.0.0:8090
- --force_master=true
depends_on:
- mysql
rekor-server:
image: gcr.io/projectsigstore/rekor-server:latest
command:
- serve
- --trillian_log_server.address=trillian-log-server
- --trillian_log_server.port=8090
- --redis_server.address=redis
- --redis_server.port=6379
- --rekor_server.address=0.0.0.0
- --rekor_server.port=3000
ports:
- "3000:3000"
depends_on:
- trillian-log-server
- redis
volumes:
mysql-data:
Fenêtre de terminal
# Configurer rekor-cli pour utiliser votre serveur
export REKOR_SERVER=https://rekor.votre-entreprise.com
# Ou par commande
rekor-cli --rekor_server https://rekor.votre-entreprise.com loginfo
SymptômeCause probableSolution
connection refusedServeur Rekor inaccessibleVérifier la connexion Internet
entry not foundUUID/index invalideVérifier le format de l’identifiant
verification failedArtefact modifiéL’artefact ne correspond pas à la signature
timeoutRéseau lentRéessayer ou augmenter le timeout
Fenêtre de terminal
# Tester l'accès au serveur public
curl -s https://rekor.sigstore.dev/api/v1/log | jq .
# Sortie attendue :
# {
# "rootHash": "abc123...",
# "signedTreeHead": "...",
# "treeSize": 98765432
# }

Comprendre ce que Rekor protège (et ne protège pas) est essentiel pour une utilisation éclairée.

Garanties de sécurité de Rekor

AttaqueProtection RekorLimite
Usurpation d’identitéSignature visible publiquementSi compte OIDC compromis, attaquant peut signer
Modification d’artefactHash enregistré dans le logDétection a posteriori uniquement
Falsification du logArbre de Merkle + signaturesRequiert compromission de l’infrastructure
Suppression d’entréeStructure append-onlyOpérateur malveillant pourrait “fork” le log
PratiquePourquoi
Vérifier les signatures en CIDétecte les artefacts non signés ou falsifiés
Monitorer les nouvelles signaturesAlerte immédiate si usurpation d’identité
Activer 2FA sur les comptes OIDCRéduit le risque de compromission
Archiver les preuves d’inclusionAudit trail pour conformité
Utiliser Rekor privé si confidentialité requiseEmails sont publics sinon

Voici les 5 points essentiels à retenir sur Rekor :

  1. Rekor = registre notarial numérique : chaque signature est horodatée et enregistrée dans un log public et immuable

  2. Arbre de Merkle : structure cryptographique qui garantit que le log ne peut pas être modifié sans que cela soit détectable

  3. Preuve temporelle : résout le problème des certificats éphémères en prouvant qu’une signature existait à un moment précis

  4. Auditabilité totale : n’importe qui peut rechercher et vérifier les signatures (attention : les emails sont publics)

  5. Instance privée possible : pour les environnements air-gapped ou nécessitant la confidentialité

Résumé Rekor