Domain 8 β€Ί Domain 8 Β· Lesson 3 of 5

DevSecOps & CI/CD Security

DevSecOps & BαΊ£o mαΊ­t Pipeline CI/CD

DevSecOps: Security as Code

DevSecOps integrates security into every stage of the DevOps pipeline β€” making security checks automatic, fast, and developer-friendly. The goal: make the secure path the easy path. If developers have to think about security, they will sometimes forget it. If security is automated in the pipeline, it is always enforced.

Dev

Write code, create PRs, run unit tests β€” security checks happen automatically via IDE plugins and pre-commit hooks

Sec

Define security policies as code β€” SAST rules, SCA policies, container scanning thresholds, secret detection patterns

Ops

Enforce gates in CI/CD pipeline β€” ArgoCD only deploys approved Git SHAs; Trivy blocks Critical CVEs in production

CI/CD Security Pipeline β€” Platform C (Go 1.23 + GitHub Actions)

Stage Tool What it Catches Gate?
Pre-commit TruffleHog / Gitleaks Secrets in code β€” API keys, passwords, private keys committed to Git Block commit
Build (SAST) gosec + Semgrep (OWASP rules) Insecure Go patterns β€” SQL injection, weak crypto, hardcoded secrets, OWASP Top 10 patterns Block PR merge
Test (SCA) govulncheck + Dependabot CVEs in Go module dependencies β€” known vulnerabilities in third-party packages Block PR (Critical)
Container (SCA) Trivy CVEs in Docker base image packages, OS-level vulnerabilities, misconfigurations Block deploy (Critical)
Container Signing cosign Unsigned images β€” ensures image was built by trusted CI, not modified after build Block deploy
Staging (DAST) OWASP ZAP Runtime vulnerabilities β€” auth bypass, injection, insecure headers, SSL/TLS issues Alert (review)
Deploy ArgoCD Ensures ONLY Git-approved SHA is deployed β€” no manual Docker push to production Enforced (GitOps)

Security Gate Philosophy

A gate that warns but doesn't block is not a security control β€” it's a notification. Every Critical/High finding must exit with code 1 to prevent PR merge or deployment. If developers can bypass the warning and ship anyway, the gate provides no security guarantee.

Platform C GitHub Actions Security Pipeline (Actual YAML)

name: Security Gates
on: [push, pull_request]

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: {fetch-depth: 0}  # Full history for TruffleHog
      - run: go install github.com/securego/gosec/v2/cmd/gosec@latest && gosec ./...
      - uses: returntocorp/semgrep-action@v1
        with: {config: 'p/owasp-top-ten p/golang'}

  sca:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: go install golang.org/x/vuln/cmd/govulncheck@latest && govulncheck ./...

  secrets:
    runs-on: ubuntu-latest
    steps:
      - uses: trufflesecurity/trufflehog@main
        with: {path: ./, base: main, head: HEAD}

  container:
    runs-on: ubuntu-latest
    steps:
      - uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'aula:${{github.sha}}'
          severity: 'CRITICAL,HIGH'
          exit-code: '1'  # ← BLOCK if Critical/High found

If any job exits with code 1, the PR cannot be merged. Branch protection rules enforce required status checks.

Container Image Security Best Practices

AVOID β€” Mutable tag

FROM golang:1.23-alpine

Tag 1.23-alpine can be changed by the registry owner β€” supply chain risk

USE β€” Immutable digest

FROM golang:1.23@sha256:abc123...

SHA-256 digest is cryptographically bound to exact image content β€” cannot be changed

Run as non-root

USER nonroot:nonroot

Container compromise β†’ attacker only has nonroot privileges, not host root

Container Security Checklist

  • βœ“ Use distroless or alpine base image (minimal attack surface)
  • βœ“ Pin base image by digest (SHA-256), not tag
  • βœ“ Run as non-root user (USER nonroot)
  • βœ“ No secrets baked into image layers (use Vault Agent)
  • βœ“ Sign image with cosign after build
  • βœ“ Scan with Trivy before push to registry
  • βœ“ Set read-only root filesystem in K8s manifest

Secret Scanning & IaC Security

Why TruffleHog Scans History

A secret committed and then deleted is still in Git history β€” every commit hash is permanent. TruffleHog scans the entire commit history, not just the current HEAD. If a secret is found in history, it must be considered compromised and rotated immediately, then removed using git-filter-repo.

Secret found in history = ROTATE IMMEDIATELY

Even if the commit was made 2 years ago and deleted next commit, the secret is in the Git object store and visible to anyone with repo access (including historical clones).

IaC Security Scanning

Infrastructure as Code (Terraform, Kubernetes manifests, Helm charts) can contain security misconfigurations. Scan with Checkov or kube-bench before apply.

  • β–ΈPrivileged containers (privileged: true)
  • β–ΈPermissive RBAC (ClusterAdmin role for app pods)
  • β–ΈNo resource limits (enables DoS via resource exhaustion)
  • β–ΈExposed ports in service definitions
  • β–ΈSecrets in environment variables (use Vault + K8s secrets)

Key Terms

DevSecOps

Integration of security into DevOps practices β€” security automated in every CI/CD stage

SAST Gate

Static Application Security Testing that blocks PR merge on Critical/High findings (exit code 1)

SCA Gate

Software Composition Analysis β€” scans third-party dependencies for known CVEs; blocks on Critical

cosign

Signs container images with cryptographic signatures β€” ensures image integrity and provenance from trusted CI

Image Digest Pinning

Using SHA-256 hash instead of tag β€” digest is immutable, tag can be overwritten by registry owner

IaC Security

Scanning Terraform, K8s manifests, Helm charts for misconfigurations before infrastructure is provisioned

Exam Tips β€” Lesson 03
  1. 1. Security gates should BLOCK (exit code 1) β€” a gate that warns but doesn't prevent deployment is a notification, not a control. CISSP may phrase this as "which is a preventive control?" β€” only blocking gates qualify.
  2. 2. TruffleHog scans Git HISTORY β€” even deleted secrets can be found and must be rotated. Never think "it's safe because I deleted the commit."
  3. 3. Container images: pin by digest (immutable, cryptographically bound) not tag (mutable β€” can be changed by registry). This is a supply chain security principle.
  4. 4. IaC security: scan Terraform/K8s manifests for misconfigurations before apply β€” the configuration is infrastructure; misconfigurations are vulnerabilities.
  5. 5. DevSecOps goal: make the secure path the easy path β€” automate so developers get fast feedback and don't have to manually think about each security check.
Platform C/FinTech Company X DevSecOps Pipeline

Current state assessment: Platform C has GitHub Actions + ArgoCD. Verify which security jobs have exit-code: '1' configured β€” advisory-only jobs are not security controls.

Priority 1 β€” Secret scanning: Enable TruffleHog with fetch-depth: 0 (full history). Run once manually first β€” any findings in historical commits require immediate secret rotation, even if the committer thought they deleted it.

Priority 2 β€” govulncheck vs Dependabot: govulncheck is Go-native and checks for vulnerabilities in the Go module graph that are actually reachable β€” fewer false positives than Dependabot alone. Both should run.

Priority 3 β€” Trivy with exit-code 1: Confirm that Critical CVEs in base images block deployment, not just generate reports. Check current Trivy action configuration in all Platform C service repos.

Action this week: audit all GitHub Actions workflows β€” confirm every security job has exit-code: '1' or equivalent blocking behavior.

Practice Questions

Q1: A security scanning job in GitHub Actions outputs a warning about a Critical CVE but the PR can still be merged. Is this a security control?

A: No β€” a gate that warns but does not block is a notification, not a preventive security control. Setting exit-code: '1' on Critical findings converts it from advisory to a true blocking gate.
CISSP distinguishes between detective controls (find and report) and preventive controls (prevent the bad action). A warning-only CI job is detective at best. A blocking gate (exit code 1 + required status check in branch protection) is preventive.

Q2: A developer committed an API key to Git by mistake, realized it, and deleted it in the next commit. TruffleHog finds it. Does the secret need to be rotated?

A: Yes β€” immediately. Git history is permanent. The secret exists in the repository's object store and is visible to anyone with read access to the repo, including historical clones. The only secure response is to rotate the secret, then optionally rewrite history with git-filter-repo.
This is a critical security principle. "Deleted" in Git means only the pointer is removed β€” the object (blob) still exists in the packfile. TruffleHog specifically targets this pattern. All secrets found in history must be assumed compromised regardless of when they were committed or deleted.

Q3: A Dockerfile uses FROM golang:1.23-alpine. What security risk does this tag present compared to a digest pin?

A: Tags are mutable β€” the registry owner (or attacker who compromises the registry) can push a different image to the same tag. Pinning by digest (FROM golang:1.23@sha256:abc...) uses a cryptographic hash that is immutable β€” if the image content changes, the hash changes, causing the build to fail with a mismatch error.
This is a software supply chain attack vector. The XZ Utils backdoor (2024) demonstrated that trusted package maintainers can be compromised. Pinning by digest means your build is deterministic and immune to upstream tag mutation. This is a SLSA (Supply chain Levels for Software Artifacts) requirement at higher maturity levels.

Q4: What does IaC security scanning check in Kubernetes deployment manifests?

A: Privileged containers, permissive RBAC (ClusterAdmin for app pods), missing resource limits, exposed ports, secrets in environment variables, missing security contexts (runAsNonRoot, readOnlyRootFilesystem, drop capabilities).
IaC security is a DevSecOps domain 8 topic. Kubernetes manifests are infrastructure definitions β€” a misconfigured K8s manifest (e.g., privileged: true) is as dangerous as vulnerable application code. Tools like Checkov, kube-bench, and Polaris scan these automatically in CI.

Q5: What is the primary goal of DevSecOps shift-left in a CI/CD pipeline?

A: To provide developers with fast, automated security feedback as early as possible in the development process β€” ideally in the IDE (real-time) and pre-commit (before push) β€” so vulnerabilities are fixed at minimal cost before reaching production.
DevSecOps applies the 1-10-100 rule (from Lesson 01) to CI/CD. Catching a vulnerability in a pre-commit hook costs almost nothing. The same vulnerability in a production incident costs orders of magnitude more β€” remediation, incident response, regulatory notification, reputational damage.