Practical Case - Containerised Pipeline with Secure Execution
This example illustrates the practical application of the prescriptions of Chapter 09 - from the secure building of the base image to its controlled execution in a CI/CD pipeline and in Kubernetes.
The pipeline in question is responsible for compiling, testing, signing and publishing a Node.js microservice, with 100% containerised execution aligned with the practices of SbD-ToE.
📦 Pipeline structure
.
├── /.github/workflows/build.yml
├── /Dockerfile
├── /.sbom/
├── /k8s/deployment.yaml
└── /policies/
🔐 Main steps implemented
| Step | Actual implementation | Associated documentation |
|---|---|---|
| Secure base image | FROM node:18.17.0-alpine + USER node | 01-imagens-base.md |
| Image signing | cosign sign with GitHub OIDC | 03-assinatura-cadeia-trust.md |
| SBOM generation | syft . -o cyclonedx-json > .sbom/container.json | 06-inventario-sbom.md |
| Vulnerability scanner | trivy image with blocking on CVSS > 7 | 07-vulnerabilidades-imagens.md |
| Isolated runners | runs-on: [self-hosted, ephemeral] | 02-runners-isolamento.md |
| Execution with enforcement | Kyverno validate for labels, UID, origin | 05-policies-runtime-opa.md |
| Controlled deploy on K8s | Pod with securityContext and PSA: restricted | 08-kubernetes-execucao.md |
📜 Summarised example of the pipeline (GitHub Actions)
jobs:
build-and-push:
runs-on: [self-hosted, hardened]
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t registry/project/app:1.0.0 .
- name: Generate SBOM
run: syft docker:registry/project/app:1.0.0 -o cyclonedx-json > sbom.json
- name: Scan for CVEs
run: trivy image --exit-code 1 --severity HIGH registry/project/app:1.0.0
- name: Sign image
run: cosign sign --key env://COSIGN_KEY registry/project/app:1.0.0
- name: Push image
run: docker push registry/project/app:1.0.0
☸️ Controlled execution in Kubernetes
apiVersion: v1
kind: Pod
metadata:
labels:
app: microservico
sbom: "true"
spec:
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
containers:
- name: app
image: registry/project/app:1.0.0
ports: [ { containerPort: 3000 } ]
🔐 This pod will only be accepted in clusters with Pod Security Admission (
restricted) + Kyverno policies validating origin and UID.
✅ Results obtained
- Pipeline execution that is 100% traceable and aligned with policies;
- Final image with SBOM, CVE scan and verifiable signature;
- Deploy to Kubernetes with security enforcement at admission;
- Auditable, versioned process that can be reapplied to other projects.
🧹 Lessons learned
- The use of containers requires discipline and continuous automation;
- Enforcement at runtime is as important as the secure build;
- The validation of the image's origin and content must be done before execution - not after;
- A clear separation between build, validation and execution significantly reduces the attack surface.
📎 Cross-references
- Chapter 07 -
addon/10-sbd-no-proprio-pipeline.md - Chapter 05 -
06-validacao-dependencias.md - Chapter 10 -
intro.md(tests of containerised execution)
✅ This example shows how to apply the practices of SbD-ToE to the complete lifecycle of containerised execution, in an integrated and realistic way.