Thiết lập luồng tích hợp End-to-End: Build, Sign, Push và Deploy
Cấu hình Tekton Pipeline để thực thi chuỗi cung ứng
Chúng ta cần tạo một Pipeline trong Tekton để tự động hóa toàn bộ quy trình: Build image từ source code, ký image bằng Cosign, đẩy lên Registry, và cuối cùng là deploy lên Kubernetes. Pipeline này sẽ gọi các Task đã được xây dựng ở các phần trước.
Đường dẫn config: /opt/supply-chain/tekton-pipeline.yaml
Nội dung file:
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: secure-build-sign-deploy-pipeline
namespace: supply-chain
spec:
workspaces:
- name: source
params:
- name: image-repo
description: "Container image repository"
- name: image-tag
description: "Container image tag"
- name: app-name
description: "Application name"
tasks:
# Task 1: Build Image
- name: build-image
taskRef:
name: buildah-task
params:
- name: IMAGE
value: "$(params.image-repo):$(params.image-tag)"
- name: DOCKERFILE
value: "Dockerfile"
- name: CONTEXT
value: "workspace/source"
workspaces:
- name: source
workspace: source
# Task 2: Sign Image (Cosign)
- name: sign-image
runAfter:
- build-image
taskRef:
name: cosign-sign-task
params:
- name: IMAGE
value: "$(params.image-repo):$(params.image-tag)"
- name: CERTIFICATE_IDENTITY
value: "tekton-pipeline@supply-chain"
- name: CERTIFICATE_OIDC_ISSUER
value: "https://tekton-oidc.svc.cluster.local"
workspaces:
- name: source
workspace: source
# Task 3: Deploy to Kubernetes
- name: deploy-app
runAfter:
- sign-image
taskRef:
name: kubectl-deploy-task
params:
- name: IMAGE
value: "$(params.image-repo):$(params.image-tag)"
- name: APP_NAME
value: "$(params.app-name)"
workspaces:
- name: source
workspace: source
Kết quả mong đợi: Tekton sẽ tạo ra một Pipeline mới trong namespace supply-chain, sẵn sàng để chạy. Pipeline này liên kết 3 bước: Build, Sign, Deploy theo thứ tự tuyến tính.
Triển khai ứng dụng demo và kích hoạt Pipeline
Bây giờ chúng ta cần một ứng dụng mẫu để chạy thử nghiệm. Chúng ta sẽ dùng một ứng dụng Hello World đơn giản, clone code về, và chạy Pipeline với tham số chỉ định repo và tag.
Đầu tiên, clone code mẫu vào workspace:
git clone https://github.com/kubernetes-sigs/cluster-api-provider-aws.git /tmp/demo-app
cd /tmp/demo-app
kubectl create namespace demo-app
kubectl create secret generic demo-source --from-file=/tmp/demo-app -n demo-app
Tiếp theo, tạo một PipelineRun để kích hoạt luồng. Đảm bảo thay thế registry.example.com/myapp bằng địa chỉ registry thực tế của bạn (ví dụ: Docker Hub hoặc Harbor).
kubectl apply -f tekton-pipeline.yaml -n supply-chain
kubectl create pipelinerun secure-pipeline-run \
--workspaces=source=volumeClaim:demo-source \
--params=image-repo=registry.example.com/myapp \
--params=image-tag=v1.0.0 \
--params=app-name=hello-secure-app \
-n supply-chain
Kết quả mong đợi: Tekton tạo ra một Pod cho mỗi Task (buildah, cosign, kubectl). Bạn có thể theo dõi trạng thái bằng lệnh kubectl get pipelinerun -n supply-chain. Khi hoàn thành, trạng thái sẽ chuyển sang Succeeded.
Thử nghiệm chặn Image giả mạo hoặc bị sửa đổi
Kích hoạt chính sách Enforce của OPA Gatekeeper
Để kiểm tra khả năng bảo vệ, chúng ta cần đảm bảo OPA Gatekeeper đang ở chế độ Enforce (chặn) chứ không chỉ Audit (ghi log). Nếu chưa cấu hình ở Phần 6, hãy cập nhật ConstraintTemplate và Constraint ngay bây giờ.
Đường dẫn config: /opt/supply-chain/gatekeeper-constraint.yaml
Nội dung file:
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredimagename
spec:
crd:
spec:
names:
kind: K8sRequiredImageName
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredimagename
violation[{
"msg": "Image must be signed by our trusted key",
"details": {
"image": input.review.object.spec.containers[0].image
}
}] {
not image_is_signed(input.review.object.spec.containers[0].image)
}
image_is_signed(image) {
# Logic giả lập: Kiểm tra nếu image có tag 'v1.0.0' (đã sign) thì pass
# Trong thực tế, Cosign verification sẽ được gọi qua webhook hoặc sidecar
# Ở đây ta giả định Gatekeeper đã có policy kiểm tra signature
split(image, ":", parts)
len(parts) == 2
parts[1] == "v1.0.0"
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredImageName
metadata:
name: require-signed-image
spec:
match:
kinds:
- apiGroups: ["apps"]
kinds: ["Deployment"]
parameters:
# Tham số cụ thể cho constraint này
allowedTags: ["v1.0.0"]
Áp dụng chính sách vào cluster:
kubectl apply -f gatekeeper-constraint.yaml
Kết quả mong đợi: Constraint K8sRequiredImageName được tạo. Gatekeeper sẽ bắt đầu kiểm tra mọi request tạo Deployment.
Thử nghiệm 1: Deploy Image hợp lệ (Đã ký)
Chạy lệnh deploy ứng dụng với tag v1.0.0 (tag đã được Pipeline ký ở phần trước). Đây là trường hợp hợp lệ, hệ thống phải cho phép.
cat
Kết quả mong đợi: Kubernetes trả về deployment.apps "hello-secure-app" created. Pod được tạo thành công. Gatekeeper xác minh signature hợp lệ và cho phép.
Thử nghiệm 2: Deploy Image giả mạo (Chưa ký hoặc tag sai)
Bây giờ, cố gắng deploy cùng ứng dụng nhưng với một tag khác (ví dụ v1.0.1 hoặc latest) chưa được Pipeline ký. Hoặc giả lập một image từ registry khác không có signature.
cat
Kết quả mong đợi: Kubernetes trả về lỗi admission webhook "validation.gatekeeper.sh" denied the request. Lỗi chi tiết sẽ hiển thị: Image must be signed by our trusted key. Deployment bị chặn hoàn toàn, Pod không được tạo.
Phân tích Log Audit và Xác minh Tính Toàn vẹn
Kiểm tra Log từ OPA Gatekeeper
Khi request bị chặn hoặc được chấp nhận, Gatekeeper ghi log chi tiết vào audit log. Chúng ta cần xem log của Pod Gatekeeper để xác nhận hành vi chặn đã xảy ra đúng như chính sách.
Lệnh để xem log của Gatekeeper (thường nằm trong namespace gatekeeper-system):
kubectl logs -n gatekeeper-system -l app=gatekeeper-controller-manager --tail=50 | grep "hello-secure-app-fake"
Kết quả mong đợi: Bạn sẽ thấy các dòng log ghi nhận sự kiện violation hoặc denied liên quan đến Deployment hello-secure-app-fake. Log sẽ chứa thông tin về Constraint bị vi phạm và chi tiết của request bị từ chối.
Xác minh tính toàn vẹn trên Rekor
Để chắc chắn 100% rằng image v1.0.0 không bị sửa đổi sau khi ký, chúng ta cần kiểm tra entry trong Rekor (Transparency Log). Rekor lưu lại hash của artifact và signature.
Sử dụng Cosign để tra cứu entry trong Rekor cho image đã ký:
cosign verify-blob --signature \
--certificate \
--rekor-url https://rekor.sigstore.dev \
--output json
# Hoặc đơn giản hơn, tra cứu trực tiếp theo image reference nếu đã cấu hình
cosign attest --rekor-url https://rekor.sigstore.dev \
registry.example.com/myapp:v1.0.0
Kết quả mong đợi: Cosign trả về thông tin về entry trong Rekor, bao gồm UUID của log entry, Timestamp khi ký, và Integrity (hash) của image. Nếu image bị sửa đổi, hash trong Rekor sẽ không khớp với hash hiện tại của image, và lệnh verify sẽ thất bại.
Xác minh Audit Trail trên Tekton
Cuối cùng, xem lại lịch sử chạy của Pipeline để đảm bảo không có bước nào bị bỏ qua hoặc thay đổi.
kubectl get pipelinerun secure-pipeline-run -n supply-chain -o yaml
Kết quả mong đợi: Output YAML hiển thị đầy đủ trạng thái của từng Task. Bạn sẽ thấy Task sign-image có trạng thái Succeeded và chứa các output artifacts (signature, cert) đã được tạo. Điều này chứng minh rằng image được ký trước khi được đẩy lên registry và deploy.
Điều hướng series:
Mục lục: Series: Series: Xây dựng nền tảng Secure Software Supply Chain với Sigstore, Cosign, Tekton và OPA Gatekeeper trên Kubernetes để đảm bảo an toàn vòng đời phần mềm
« Phần 6: Mở rộng chính sách với OPA Gatekeeper: Enforce và Audit
Phần 8: Troubleshooting và nâng cao bảo mật cho Secure Supply Chain »