Tạo Task Tekton để Build Docker Image
Ta sẽ tạo một tài nguyên Task trong Tekton để đóng gói quy trình build Docker image từ source code. Task này sử dụng image gcr.io/cloud-builders/docker để chạy lệnh docker build và đẩy image lên registry.
Mục đích là chuẩn hóa bước build, đảm bảo đầu vào là source code từ Git và đầu ra là image đã được tag với version cụ thể (SHA256 của commit).
Tạo file build-task.yaml tại đường dẫn /home/user/tekton-tasks/build-task.yaml:
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: build-docker-image
spec:
params:
- name: image
description: Tên của image Docker sẽ được build (bao gồm registry và tag)
type: string
- name: gitUrl
description: URL của repository Git
type: string
- name: gitRevision
description: Branch hoặc commit SHA cần build
type: string
default: main
- name: dockerfile
description: Đường dẫn đến file Dockerfile
type: string
default: Dockerfile
- name: buildContext
description: Context cho lệnh docker build
type: string
default: .
workspaces:
- name: source
description: Workspace chứa source code
steps:
- name: build-and-push
image: gcr.io/cloud-builders/docker
env:
- name: IMAGE
value: $(params.image)
workingDir: /workspace/source
command:
- /bin/bash
- -c
args:
- |
set -e
echo "Building image $(IMAGE) from context $(params.buildContext)"
docker build -f $(params.dockerfile) -t $(IMAGE) $(params.buildContext)
echo "Pushing image $(IMAGE) to registry"
docker push $(IMAGE)
echo "Image built and pushed successfully."
Sau khi tạo file, áp dụng Task vào cluster Kubernetes bằng lệnh kubectl apply.
kubectl apply -f /home/user/tekton-tasks/build-task.yaml
Kết quả mong đợi: Tekton Task được tạo thành công với thông báo task.tekton.dev/build-docker-image created.
Verify Task đã tồn tại:
kubectl get task build-docker-image
Kết quả hiển thị trạng thái READY hoặc không có lỗi.
Tích hợp Task Cosign để Ký Image Tự động
Bây giờ ta tạo Task riêng biệt để thực thi lệnh ký (sign) sử dụng Cosign. Task này sẽ nhận đầu vào là image đã build và thực hiện ký bằng chứng chỉ từ Fulcio (vía OIDC) hoặc key từ Secret.
Ta sử dụng flow OIDC (OpenID Connect) để lấy chứng chỉ tự động từ Kubernetes Service Account, tránh việc lưu key bí mật trong cluster.
Tạo file cosign-sign-task.yaml tại đường dẫn /home/user/tekton-tasks/cosign-sign-task.yaml:
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: cosign-sign-image
spec:
params:
- name: image
description: Image cần ký (bao gồm tag)
type: string
- name: cosign-key
description: Path to cosign key (nếu dùng key file, để trống nếu dùng OIDC)
type: string
default: ""
steps:
- name: sign
image: quay.io/sigstore/cosign:v2.2.0
env:
- name: COSIGN_EXPERIMENTAL
value: "true"
- name: IMAGE
value: $(params.image)
- name: KUBERNETES_SERVICE_HOST
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: KUBERNETES_SERVICE_PORT
value: "443"
command:
- /bin/bash
- -c
args:
- |
set -e
echo "Signing image $(IMAGE)"
# Kiểm tra nếu có key thì dùng key, nếu không dùng OIDC (kubernetes-identity)
if [ -n "$(params.cosign-key)" ]; then
cosign sign --key $(params.cosign-key) $(IMAGE)
else
# Sử dụng OIDC với Kubernetes Service Account
cosign sign --yes $(IMAGE)
fi
echo "Image $(IMAGE) signed successfully."
echo "Verifying signature..."
cosign verify $(IMAGE) --certificate-oidc-issuer https://token.actions.githubusercontent.com || true
Áp dụng Task Cosign vào cluster:
kubectl apply -f /home/user/tekton-tasks/cosign-sign-task.yaml
Kết quả mong đợi: Task cosign-sign-image được tạo thành công.
Verify Task Cosign:
kubectl get task cosign-sign-image
Kết quả hiển thị Task trong namespace mặc định (hoặc namespace bạn đang làm việc).
Cấu hình Tekton Pipeline để Chạy Build và Ký
Tiếp theo, ta tạo Pipeline để nối hai Task trên lại thành một quy trình tuần tự: Build trước, sau đó mới Sign. Pipeline này sẽ quản lý việc truyền biến (passing parameters) giữa các bước.
Pipeline sẽ nhận input là Git URL và Revision, sau đó tạo tên image động dựa trên commit SHA để đảm bảo tính immutability.
Tạo file secure-build-pipeline.yaml tại đường dẫn /home/user/tekton-pipelines/secure-build-pipeline.yaml:
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: secure-supply-chain-pipeline
spec:
params:
- name: gitUrl
type: string
- name: gitRevision
type: string
- name: registryUrl
type: string
default: myregistry.example.com
- name: imageRepo
type: string
default: my-app
workspaces:
- name: source
tasks:
- name: build-image
taskRef:
name: build-docker-image
workspaces:
- name: source
workspace: source
params:
- name: image
value: $(params.registryUrl)/$(params.imageRepo):$(params.gitRevision)
- name: gitUrl
value: $(params.gitUrl)
- name: gitRevision
value: $(params.gitRevision)
- name: dockerfile
value: Dockerfile
- name: buildContext
value: .
- name: sign-image
taskRef:
name: cosign-sign-image
runAfter:
- build-image
params:
- name: image
value: $(params.registryUrl)/$(params.imageRepo):$(params.gitRevision)
- name: cosign-key
value: ""
Áp dụng Pipeline vào cluster:
kubectl apply -f /home/user/tekton-pipelines/secure-build-pipeline.yaml
Kết quả mong đợi: Pipeline secure-supply-chain-pipeline được tạo.
Verify Pipeline:
kubectl get pipeline secure-supply-chain-pipeline
Triển khai Pipeline và Thực thi Quy trình
Để chạy pipeline, ta cần tạo PipelineRun. Đây là một instance cụ thể của Pipeline với các giá trị tham số thực tế. PipelineRun này sẽ kích hoạt Task build, sau đó Task sign.
Ta giả sử source code nằm trong repo https://github.com/myorg/myapp và branch là main. Image sẽ được đẩy lên registry myregistry.example.com.
Tạo file pipeline-run.yaml tại đường dẫn /home/user/tekton-runs/pipeline-run.yaml:
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: secure-build-run-$(date +%s)
spec:
serviceAccountName: tekton-pipeline-runner
pipelineRef:
name: secure-supply-chain-pipeline
params:
- name: gitUrl
value: https://github.com/myorg/myapp
- name: gitRevision
value: main
- name: registryUrl
value: myregistry.example.com
- name: imageRepo
value: my-app
workspaces:
- name: source
persistentVolumeClaim:
claimName: source-pvc
Lưu ý: Bạn cần đảm bảo tồn tại PVC source-pvc hoặc sử dụng emptyDir cho môi trường test. Ở đây ta dùng PVC để lưu source code.
Áp dụng PipelineRun để bắt đầu quy trình:
kubectl apply -f /home/user/tekton-runs/pipeline-run.yaml
Kết quả mong đợi: PipelineRun được tạo và trạng thái chuyển sang Running rồi Succeeded.
Theo dõi tiến trình thực thi theo thời gian thực:
kubectl logs -l tekton.dev/pipelineRun=secure-build-run-$(date +%s) -f
Kết quả hiển thị log của cả 2 bước: Build image và Sign image.
Verify Kết quả và Ghi log vào Rekor
Sau khi Pipeline chạy thành công, ta cần xác minh rằng image đã được ký và signature đã được ghi vào Rekor (public transparency log). Đây là bước quan trọng nhất để đảm bảo tính toàn vẹn của chuỗi cung ứng.
Đầu tiên, kiểm tra trạng thái của PipelineRun:
kubectl get pipelinerun | grep secure-build-run
Kết quả phải hiển thị trạng thái SUCCEEDED và COMPLETED.
Truy cập vào log chi tiết của bước ký (sign) để xem thông báo thành công:
kubectl logs pipelinerun/secure-build-run-$(date +%s) -c sign-image
Kết quả mong đợi: Thấy dòng Image ... signed successfully và Verifying signature... không có lỗi.
Bây giờ, xác minh signature trên registry bằng lệnh cosign verify từ terminal bên ngoài (hoặc từ một Pod khác có quyền truy cập registry). Lệnh này sẽ tự động fetch signature từ registry và kiểm tra với Rekor.
cosign verify --certificate-oidc-issuer https://token.actions.githubusercontent.com myregistry.example.com/my-app:main
Kết quả mong đợi:
- Hiển thị Certificate chain hợp lệ.
- Các Verified claims (như
repository`, source`).
- Không có lỗi
failed to verify signature.
Cuối cùng, kiểm tra xem bản ghi (entry) của signature đã được ghi vào Rekor chưa. Sử dụng lệnh cosign verify-attestation hoặc tra cứu trực tiếp trên Rekor API nếu cần, nhưng cách đơn giản nhất là lệnh verify ở trên đã ngầm thực hiện bước này.
Để xem chi tiết bản ghi trong Rekor (nếu bạn có quyền truy cập Rekor public hoặc private instance của mình), dùng lệnh:
cosign verify --signature-opts rekor.myregistry.example.com myregistry.example.com/my-app:main 2>&1 | grep "Rekor entry"
Nếu không có lỗi, điều này chứng tỏ signature đã được ghi vào log minh bạch (transparency log) của Rekor, hoàn tất quy trình Secure Software Supply Chain.
Đ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 3: Triển khai Cosign để ký và xác minh container image
Phần 5: Triển khai OPA Gatekeeper để thực thi chính sách bảo mật »