نظرة عامة
يجب توقيع كل صورة حاوية ينتجها خط أنابيب CI/CD الخاص بك بشكل تشفيري قبل أن تصل إلى أي بيئة. الصور غير الموقعة تمثل نقطة عمياء — ليس لديك دليل على أنها جاءت من خط الأنابيب الخاص بك، ولا ضمان بأنها لم يتم التلاعب بها أثناء النقل، ولا آلية سياسة لمنع عمليات النشر غير المصرح بها.
في هذا المعمل العملي ستقوم بـ:
- توقيع صورة حاوية محلياً باستخدام زوج مفاتيح Cosign.
- إعداد التوقيع بدون مفاتيح في GitHub Actions باستخدام بنية Sigstore التحتية (Fulcio و Rekor).
- التحقق من التوقيعات محلياً مع فحوصات الشهادات المبنية على الهوية.
- فرض التحقق من التوقيع عند القبول في Kubernetes باستخدام Kyverno.
- إرفاق والتحقق من شهادة SBOM باستخدام Cosign و Syft.
بنهاية هذا المعمل سيكون لديك سير عمل GitHub Actions كامل يبني ويدفع ويوقع ويشهد كل صورة — وسياسة Kubernetes ترفض أي شيء غير موقع.
المتطلبات الأساسية
قبل البدء، تأكد من توفر ما يلي:
- حساب GitHub مع صلاحية إنشاء مستودعات وتفعيل GitHub Actions.
- حساب سجل حاويات — يستخدم هذا المعمل GitHub Container Registry (GHCR)، لكن Docker Hub يعمل أيضاً.
- Docker مثبت وقيد التشغيل محلياً.
- Cosign CLI مثبت محلياً:
# macOS (Homebrew)
brew install cosign
# Or install from source with Go
go install github.com/sigstore/cosign/v2/cmd/cosign@latest
# Verify installation
cosign version
- kubectl و Helm مثبتان (لتمرين Kyverno).
- Syft مثبت (لتمرين SBOM):
brew install syft
ستحتاج أيضاً إلى تطبيق بسيط لوضعه في حاوية. إليك تطبيق Go بسيط وملف Dockerfile الخاص به الذي سنستخدمه طوال المعمل.
main.go
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from a signed container!")
})
http.ListenAndServe(":8080", nil)
}
Dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY main.go .
RUN go build -o server main.go
FROM alpine:3.19
COPY --from=builder /app/server /server
EXPOSE 8080
ENTRYPOINT ["/server"]
إعداد البيئة
ابدأ بإنشاء مستودع اختبار ودفع كود التطبيق.
الخطوة 1 — إنشاء المستودع
# Create a new directory and initialize a Git repo
mkdir cosign-lab && cd cosign-lab
git init
# Create the Go application and Dockerfile from the prerequisites above
# Then push to GitHub
git add .
git commit -m "Initial commit: simple Go app"
gh repo create cosign-lab --public --source=. --push
الخطوة 2 — إنشاء سير العمل بدون توقيع
قبل إضافة التوقيع، أنشئ سير عمل أساسي يقوم فقط ببناء ودفع الصورة. هذا يعطيك شيئاً للمقارنة لاحقاً.
أنشئ .github/workflows/build.yml:
name: Build and Push (Unsigned)
on:
push:
tags:
- 'v*'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
قم بعمل commit ودفع سير العمل هذا. أنشئ وسم إصدار لتشغيله:
git add .
git commit -m "Add unsigned build workflow"
git push origin main
git tag v0.1.0
git push origin v0.1.0
بمجرد اكتمال سير العمل، ستكون صورتك في GHCR — لكنها لا تحمل أي توقيع تشفيري. يمكن لأي شخص لديه صلاحية الكتابة على السجل استبدالها، ولن يلاحظ أي شيء في المراحل اللاحقة.
التمرين 1: التوقيع المحلي بزوج مفاتيح
قبل الانتقال إلى التوقيع بدون مفاتيح في CI، من المفيد فهم الأساسيات من خلال توقيع صورة محلياً بزوج مفاتيح صريح.
الخطوة 1 — إنشاء زوج مفاتيح Cosign
cosign generate-key-pair
ينشئ هذا ملفين في دليلك الحالي:
cosign.key— المفتاح الخاص (مشفر بعبارة مرور تختارها).cosign.pub— المفتاح العام الذي توزعه على المتحققين.
الخطوة 2 — بناء ودفع وتوقيع الصورة
# Build the image
docker build -t ghcr.io/<your-username>/cosign-lab:v1 .
# Push to GHCR
docker push ghcr.io/<your-username>/cosign-lab:v1
# Sign the image with your private key
cosign sign --key cosign.key ghcr.io/<your-username>/cosign-lab:v1
استبدل <your-username> باسم مستخدم GitHub الخاص بك. سيطلب Cosign عبارة المرور التي حددتها أثناء إنشاء المفتاح.
الخطوة 3 — التحقق من التوقيع
cosign verify --key cosign.pub ghcr.io/<your-username>/cosign-lab:v1
يجب أن ترى مخرجات مشابهة لـ:
Verification for ghcr.io/<your-username>/cosign-lab:v1 --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
[{"critical":{"identity":{"docker-reference":"ghcr.io/<your-username>/cosign-lab"},"image":{"docker-manifest-digest":"sha256:abc123..."},"type":"cosign container image signature"},"optional":null}]
أين يتم تخزين التوقيع؟
يخزن Cosign التوقيعات كقطع OCI في نفس السجل، بجانب الصورة. لصورة موسومة بـ sha256:abc123، يدفع Cosign التوقيع إلى وسم مشتق من ذلك الملخص — sha256-abc123.sig. هذا يعني:
- لا حاجة لبنية تحتية منفصلة لتخزين التوقيعات.
- تنتقل التوقيعات مع الصورة عند نسخ أو تكرار السجلات.
- تنطبق ضوابط الوصول إلى السجل على التوقيعات بنفس الطريقة التي تنطبق بها على الصور.
التوقيع بزوج مفاتيح يعمل، لكنه يفرض عبء إدارة المفاتيح: يجب حماية المفتاح الخاص وتدويره دورياً وتوزيع المفتاح العام على كل متحقق. في التمرين التالي، سنزيل هذا العبء تماماً مع التوقيع بدون مفاتيح.
التمرين 2: التوقيع بدون مفاتيح في GitHub Actions
يزيل التوقيع بدون مفاتيح الحاجة إلى إنشاء أو تخزين أو تدوير مفاتيح التوقيع. بدلاً من ذلك، يعتمد على شهادات قصيرة العمر صادرة عن Fulcio ومسجلة في سجل الشفافية Rekor.
كيف يعمل التوقيع بدون مفاتيح
- رمز OIDC — يصدر GitHub Actions رمز هوية OIDC يثبت هوية سير العمل (المستودع، ملف سير العمل، المرجع، والمزيد).
- شهادة Fulcio — يرسل Cosign رمز OIDC هذا إلى Fulcio، الذي يصدر شهادة توقيع X.509 قصيرة العمر مرتبطة بهوية سير العمل.
- التوقيع — يوقع Cosign ملخص الصورة بالمفتاح الخاص المؤقت المقابل لشهادة Fulcio.
- سجل شفافية Rekor — يتم تسجيل التوقيع والشهادة في Rekor حتى يتمكن أي شخص من مراجعة متى ومن قام بتوقيع الصورة.
- التخلص من المفتاح — يتم التخلص من المفتاح الخاص المؤقت فوراً. يستخدم التحقق الشهادة وإدخال Rekor، وليس مفتاحاً عاماً طويل العمر.
الخطوة 1 — إنشاء سير عمل التوقيع
أنشئ .github/workflows/sign.yml:
name: Build, Push, and Sign
on:
push:
tags:
- 'v*'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-sign:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write # Required for keyless signing via OIDC
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Cosign
uses: sigstore/cosign-installer@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push
id: build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Sign the image
run: |
cosign sign --yes \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
التفاصيل الرئيسية في سير العمل هذا
id-token: write— هذا الإذن يسمح للمشغل بطلب رمز OIDC من GitHub، الذي يستخدمه Fulcio لإصدار شهادة التوقيع.packages: write— مطلوب لدفع الصورة وتوقيعها إلى GHCR.cosign sign --yes— علم--yesيؤكد الوضع غير التفاعلي (بدون طلب موافقة التوقيع بدون مفاتيح). عدم وجود علم--keyيعني أن Cosign يستخدم تلقائياً التوقيع بدون مفاتيح.- نوقع بالملخص (
@sha256:...) بدلاً من الوسم لضمان توقيع الصورة نفسها التي بنيناها للتو.
الخطوة 2 — الدفع وتشغيل سير العمل
git add .github/workflows/sign.yml
git commit -m "Add keyless signing workflow"
git push origin main
git tag v1.0.0
git push origin v1.0.0
الخطوة 3 — مراجعة سجلات Actions
في خطوة “Sign the image” سترى مخرجات مشابهة لـ:
Generating ephemeral keys...
Retrieving signed certificate...
The sigstore community wants to hear from you! Connect with us at
https://links.sigstore.dev/slack-invite
Successfully verified SCT...
tlog entry created with index: 45678901
Pushing signature to: ghcr.io/<your-username>/cosign-lab:sha256-a1b2c3d4.sig
الصورة الآن موقعة بشهادة تربطها تشفيرياً بهوية سير عمل GitHub Actions الخاص بك. التوقيع والشهادة مسجلان بشكل دائم في سجل شفافية Rekor.
التمرين 3: التحقق من التوقيعات محلياً
يتطلب التحقق من صورة موقعة بدون مفاتيح معلومتين: هوية الشهادة (من وقع) و مُصدر OIDC (من ضمن تلك الهوية).
الخطوة 1 — التحقق من الصورة الموقعة
cosign verify \
--certificate-identity "https://github.com/<your-username>/cosign-lab/.github/workflows/sign.yml@refs/tags/v1.0.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/<your-username>/cosign-lab:v1.0.0
المخرجات الناجحة:
Verification for ghcr.io/<your-username>/cosign-lab:v1.0.0 --
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
- The signatures were verified against the specified public key
- The signature was verified against a valid Fulcio certificate
[{"critical":{"identity":{"docker-reference":"ghcr.io/<your-username>/cosign-lab"},"image":{"docker-manifest-digest":"sha256:a1b2c3d4..."},"type":"cosign container image signature"},"optional":{...}}]
الخطوة 2 — التحقق بهوية غير صحيحة (توقع الفشل)
cosign verify \
--certificate-identity "https://github.com/attacker/malicious-repo/.github/workflows/build.yml@refs/tags/v1.0.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/<your-username>/cosign-lab:v1.0.0
المخرجات:
Error: no matching signatures:
none of the expected identities matched what was in the certificate
هذا يؤكد أن التوقيعات مرتبطة بالهوية. حتى لو تمكن شخص ما من دفع توقيع، فلن يجتاز التحقق ما لم يكن موقعاً من سير العمل المحدد الذي تحدده.
الخطوة 3 — التحقق من صورة غير موقعة (توقع الفشل)
cosign verify \
--certificate-identity "https://github.com/<your-username>/cosign-lab/.github/workflows/sign.yml@refs/tags/v0.1.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/<your-username>/cosign-lab:v0.1.0
المخرجات:
Error: no matching signatures
no signatures found for image
صورة v0.1.0 تم بناؤها بسير العمل غير الموقع من قسم إعداد البيئة، لذلك لا يوجد توقيع.
فهم حقول الشهادة
عند التحقق من توقيع بدون مفاتيح، يفحص Cosign عدة حقول مضمنة في شهادة Fulcio:
- المُصدر (
certificate-oidc-issuer) — مزود OIDC الذي صادق على الموقِّع. بالنسبة لـ GitHub Actions هذا دائماًhttps://token.actions.githubusercontent.com. - الموضوع / الهوية (
certificate-identity) — مرجع سير العمل الكامل بما في ذلك المستودع ومسار ملف سير العمل ومرجع Git. هذا يربط التوقيع بسير عمل محدد عند commit أو وسم محدد. - امتدادات GitHub Workflow — تحتوي الشهادة أيضاً على امتدادات OID مخصصة للمستودع و SHA لسير العمل وحدث التشغيل وبيئة المشغل. تسمح هذه بسياسات تحقق دقيقة.
يمكنك أيضاً استخدام مطابقة regex لسياسات أكثر مرونة:
cosign verify \
--certificate-identity-regexp "https://github.com/<your-username>/cosign-lab/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/<your-username>/cosign-lab:v1.0.0
هذا مفيد عندما تريد قبول التوقيعات من أي سير عمل في مستودع، أو من أي وسم.
التمرين 4: التحقق في Kubernetes باستخدام Kyverno
التحقق المحلي مفيد لتصحيح الأخطاء، لكن مجموعات الإنتاج تحتاج إلى فرض آلي. Kyverno هو وحدة تحكم قبول في Kubernetes يمكنها التحقق من توقيعات Cosign على كل طلب قبول pod.
الخطوة 1 — تثبيت Kyverno
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno -n kyverno --create-namespace
انتظر حتى تصبح pods الخاصة بـ Kyverno جاهزة:
kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance=kyverno -n kyverno --timeout=120s
الخطوة 2 — إنشاء سياسة التحقق من الصور
احفظ ما يلي باسم require-signed-images.yml:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-cosign-signature
spec:
validationFailureAction: Enforce
background: false
rules:
- name: verify-cosign-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "ghcr.io/<your-username>/cosign-lab:*"
attestors:
- entries:
- keyless:
subject: "https://github.com/<your-username>/cosign-lab/.github/workflows/sign.yml@refs/tags/*"
issuer: "https://token.actions.githubusercontent.com"
rekor:
url: "https://rekor.sigstore.dev"
طبق السياسة:
kubectl apply -f require-signed-images.yml
الخطوة 3 — اختبار بصورة موقعة (يجب أن ينجح)
kubectl run signed-app \
--image=ghcr.io/<your-username>/cosign-lab:v1.0.0 \
--restart=Never
المخرجات المتوقعة:
pod/signed-app created
الخطوة 4 — اختبار بصورة غير موقعة (يجب أن يفشل)
kubectl run unsigned-app \
--image=ghcr.io/<your-username>/cosign-lab:v0.1.0 \
--restart=Never
المخرجات المتوقعة:
Error from server: admission webhook "mutate.kyverno.svc-fail" denied the request:
resource Pod/default/unsigned-app was blocked due to the following policies:
require-cosign-signature:
verify-cosign-signature: |
image verification failed for ghcr.io/<your-username>/cosign-lab:v0.1.0:
no matching signatures found
هذا هو بالضبط حلقة الفرض التي تريدها: فقط الصور الموقعة من سير عمل GitHub Actions الموثوق الخاص بك يُسمح لها بالدخول إلى المجموعة.
التمرين 5: إرفاق SBOM
التوقيع يثبت من بنى الصورة. شهادة SBOM تثبت ما بداخلها. الجمع بينهما يمنحك سلسلة ثقة كاملة: الهوية والنزاهة وشفافية المحتوى.
الخطوة 1 — إنشاء SBOM باستخدام Syft
syft ghcr.io/<your-username>/cosign-lab:v1.0.0 -o spdx-json > sbom.spdx.json
يقوم هذا بمسح طبقات الصورة وإنتاج مستند JSON بتنسيق SPDX يسرد كل حزمة ومكتبة وتبعية داخل الصورة.
الخطوة 2 — إرفاق SBOM كشهادة
cosign attest \
--predicate sbom.spdx.json \
--type spdxjson \
--yes \
ghcr.io/<your-username>/cosign-lab:v1.0.0
مثل التوقيع بدون مفاتيح، يستخدم هذا الهوية المبنية على OIDC عند التشغيل في GitHub Actions أو يطلب المصادقة التفاعلية عند التشغيل محلياً. يتم تخزين الشهادة كقطعة OCI بجانب الصورة.
الخطوة 3 — التحقق من الشهادة
cosign verify-attestation \
--type spdxjson \
--certificate-identity "https://github.com/<your-username>/cosign-lab/.github/workflows/sign.yml@refs/tags/v1.0.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/<your-username>/cosign-lab:v1.0.0
التحقق الناجح يؤكد أن SBOM تم إنشاؤه وإرفاقه بواسطة سير العمل الموثوق الخاص بك، وأنه لم يتم التلاعب به منذ ذلك الحين.
خط أنابيب التوقيع الكامل
إليك سير العمل النهائي الذي يجمع كل شيء: البناء والدفع والتوقيع وإنشاء SBOM وتوثيقه. احفظ هذا باسم .github/workflows/sign-and-attest.yml:
name: Build, Sign, and Attest
on:
push:
tags:
- 'v*'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-sign-attest:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Cosign
uses: sigstore/cosign-installer@v3
- name: Install Syft
uses: anchore/sbom-action/download-syft@v0
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push
id: build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Sign the image
run: |
cosign sign --yes \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
- name: Generate SBOM
run: |
syft ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} \
-o spdx-json > sbom.spdx.json
- name: Attest SBOM
run: |
cosign attest --yes \
--predicate sbom.spdx.json \
--type spdxjson \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
- name: Verify signature
run: |
cosign verify \
--certificate-identity-regexp "https://github.com/${{ github.repository }}/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
- name: Verify SBOM attestation
run: |
cosign verify-attestation \
--type spdxjson \
--certificate-identity-regexp "https://github.com/${{ github.repository }}/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
يمنحك سير العمل هذا سلسلة ثقة كاملة لكل إصدار موسوم: الصورة موقعة، ومحتوياتها موثقة في SBOM، و SBOM مشهود عليه تشفيرياً — كل ذلك بدون إدارة مفتاح واحد طويل العمر.
التنظيف
عند الانتهاء من المعمل، نظف الموارد التي أنشأتها.
حذف صور الاختبار من GHCR
انتقل إلى https://github.com/<your-username>?tab=packages واحذف حزمة cosign-lab، أو استخدم GitHub CLI:
# List package versions
gh api user/packages/container/cosign-lab/versions | jq '.[].id'
# Delete each version
gh api --method DELETE user/packages/container/cosign-lab/versions/<version-id>
إزالة Kyverno
kubectl delete clusterpolicy require-cosign-signature
helm uninstall kyverno -n kyverno
kubectl delete namespace kyverno
حذف مستودع الاختبار
gh repo delete <your-username>/cosign-lab --yes
إزالة الملفات المحلية
cd .. && rm -rf cosign-lab
rm -f cosign.key cosign.pub
النقاط الرئيسية
- التوقيع بدون مفاتيح يزيل إدارة المفاتيح. باستخدام رموز هوية OIDC من GitHub Actions وشهادات Fulcio قصيرة العمر، تتجنب العبء التشغيلي لإنشاء وتخزين وتدوير وتوزيع مفاتيح التوقيع.
- التوقيعات مرتبطة بالهوية، وليس بالمفتاح. يتحقق التحقق من الذي وقع الصورة (أي سير عمل، في أي مستودع، عند أي مرجع) بدلاً من أي مفتاح تم استخدامه. هذا يجعل السياسات أكثر سهولة وقابلية للمراجعة.
- سجل شفافية Rekor يوفر مسار مراجعة مقاوم للتلاعب. كل توقيع مسجل علنياً، حتى تتمكن من إثبات متى تم توقيع الصورة واكتشاف أي محاولة لتأخير التاريخ أو إزالة التوقيعات.
- وحدات تحكم القبول تفرض سياسات التوقيع عند وقت النشر. Kyverno (أو بدائل مثل Connaisseur أو Sigstore Policy Controller) يضمن أن الصور غير الموقعة أو الموقعة بشكل غير صحيح لا تعمل أبداً في مجموعتك.
- شهادات SBOM توسع سلسلة الثقة. التوقيع يثبت من بنى الصورة؛ إرفاق SBOM موقع يثبت ما بداخلها. معاً، يوفران مصدراً كاملاً من المصدر إلى وقت التشغيل.
- وقّع بالملخص، وليس بالوسم. الوسوم قابلة للتغيير — يمكن لشخص ما نقل وسم إلى صورة مختلفة. الملخصات هي عناوين محتوى ثابتة، لذا التوقيع بالملخص يضمن أنك وقعت بالضبط الصورة التي بنيتها.
الخطوات التالية
واصل بناء معرفتك بأمان سلسلة التوريد مع هذه الأدلة ذات الصلة:
- توقيع والتحقق من صور الحاويات باستخدام Sigstore و Cosign — دليل شامل يغطي بنية Cosign وأنماط التحقق المتقدمة والتكامل مع سجلات وأنظمة CI مختلفة.
- مصدر القطع الأثرية والشهادات: من SLSA إلى in-toto — فهم نظام المصدر الأوسع بما في ذلك مستويات SLSA وتخطيطات in-toto وكيف تتناسب الشهادات مع استراتيجية أمان سلسلة التوريد الكاملة.