Shift Left – CI/CD Scanning & Signing Pipeline
Duration: ~25 minutes
Overview
Integrate security scanning and policy checks into pipelines.
Build a Tekton pipeline that builds, scans, gates, and signs an image, then deploy by digest from the signed result.
Why it matters
Unsigned, unscanned images reach production when security sits after deploy. Pipelines that build, scan, gate, and sign shrink the window where attackers swap in a poisoned tag.
What does it solve
-
Silent promotion of unscanned images
-
Deployments that float on mutable tags instead of digests
-
Missing signature evidence for admission and audit
Your Mission
Build a Tekton path that refuses unscanned or unsigned images—then deploy only by digest so a supply-chain swap cannot silently replace what you ran.
Prerequisites
-
OpenShift Pipelines (Tekton) Operator installed
-
Cosign installed locally, or simulate signing in the pipeline tasks
Click each step only if you need a hint.
Namespace & Service Account
Tekton CRDs require YAML; only typos fixed and kept minimal.
oc new-project 201-05-s-pipeline
och create sa pipeline -n 201-05-s-pipeline
oc adm policy add-scc-to-user anyuid -z pipeline -n 201-05-s-pipeline # only if build strategy requires
Build Task (S2I or Buildah Simplified)
oc apply -n 201-05-s-pipeline -f - <<'EOF'
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: build-image
spec:
results:
- name: image-digest
params:
- name: IMAGE
steps:
- name: build
image: registry.access.redhat.com/ubi9/buildah
script: |
#!/usr/bin/env bash
set -e
touch index.html; echo Hello > index.html
buildah bud -t $(params.IMAGE) .
buildah push $(params.IMAGE)
DIGEST=$(skopeo inspect docker://$(params.IMAGE) | jq -r .Digest)
echo -n "$DIGEST" > $(results.image-digest.path)
EOF
Scan Task (Simulated)
oc apply -n 201-05-s-pipeline -f - <<'EOF'
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: scan-image
spec:
params:
- name: IMAGE
results:
- name: scan-status
steps:
- name: scan
image: registry.access.redhat.com/ubi9/ubi
script: |
#!/usr/bin/env bash
echo "Simulating vulnerability scan"
# set FAIL=1 to simulate failure
if [ "$FAIL" = "1" ]; then echo -n FAIL > $(results.scan-status.path); exit 1; fi
echo -n PASS > $(results.scan-status.path)
EOF
Sign Task (Cosign Simulated)
oc apply -n 201-05-s-pipeline -f - <<'EOF'
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: sign-image
spec:
params:
- name: IMAGE
- name: DIGEST
steps:
- name: sign
image: registry.access.redhat.com/ubi9/ubi
script: |
#!/usr/bin/env bash
echo "Simulating cosign sign $(params.IMAGE)@$(params.DIGEST)"
echo "signature-ok" > /tekton/home/signature.txt
EOF
Pipeline Definition
oc apply -n 201-05-s-pipeline -f - <<'EOF'
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: secure-build
spec:
params:
- name: IMAGE
tasks:
- name: build
taskRef:
name: build-image
params:
- name: IMAGE
value: $(params.IMAGE)
- name: scan
runAfter: [build]
taskRef:
name: scan-image
params:
- name: IMAGE
value: $(params.IMAGE)
- name: sign
runAfter: [scan]
when:
- input: "$(tasks.scan.results.scan-status)"
operator: In
values: ["PASS"]
taskRef:
name: sign-image
params:
- name: IMAGE
value: $(params.IMAGE)
- name: DIGEST
value: $(tasks.build.results.image-digest)
EOF
Run Pipeline
oc apply -n 201-05-s-pipeline -f - <<'EOF'
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: secure-build-run
spec:
serviceAccountName: pipeline
pipelineRef:
name: secure-build
params:
- name: IMAGE
value: image-registry.openshift-image-registry.svc:5000/201-05-s-pipeline/demo:latest
EOF
Monitor:
oc get pipelineruns -n 201-05-s-pipeline
och describe pipelinerun secure-build-run -n 201-05-s-pipeline | grep -i status
Get digest:
oc get pipelinerun secure-build-run -n 201-05-s-pipeline -o jsonpath='{.status.pipelineResults}'
Deployment Using Digest (Gate Simulation)
Replace <DIGEST> with extracted digest:
oc apply -n 201-05-s-pipeline -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 1
selector:
matchLabels: {app: demo}
template:
metadata:
labels: {app: demo}
spec:
containers:
- name: web
image: image-registry.openshift-image-registry.svc:5000/201-05-s-pipeline/demo@sha256:<DIGEST>
EOF
Debrief
Your pipeline enforced scan-before-sign, skipped signing on failure, and deployed by digest so mutable tags cannot sneak into production.
What breaks without this:
-
Unscanned or unsigned images → known-bad artifacts reach the cluster
-
Tag-based deploys → non-reproducible, retaggable runtime
Controls that matter: Tekton (or equivalent) gates, conditional sign tasks, digest pins, and admission that extends trust (signatures/SBOM) at deploy time—see 201-11 for Gatekeeper / cosign enforcement on tag-based images.
Quick facts: the when-clause is the gate; admission and SBOM checks are the natural next layers.
