CI/CD Pipeline Security: A Practical Guide

CI/CD Pipeline Security: A Practical Guide

Published January 30, 2026
security ci-cd devops iam best-practices

CI/CD Pipeline Security: A Practical Guide

CI/CD pipelines are one of the highest-value targets in modern infrastructure. They hold production credentials, modify running services, and typically run with elevated permissions. Securing your pipeline means understanding the attack surface — secrets leakage, supply chain compromise, privilege escalation, and pipeline poisoning — and building defenses into every layer.

The CI/CD Attack Surface

Before locking things down, it helps to know what you’re defending against. Most CI/CD security incidents fall into four categories:

  • Secrets leakage: Credentials exposed in logs, environment variables, or committed to source control. One leaked AWS key can compromise an entire account.
  • Supply chain attacks: Compromised dependencies or base images that inject malicious code into your build. The 2024 xz backdoor showed how deep these can go.
  • Privilege escalation: Deployment roles with overly broad permissions. If a pipeline role has *:*, a compromised build step can do anything in your account.
  • Pipeline poisoning: Unauthorized changes to pipeline definitions that alter what gets deployed and where. A modified pipeline can bypass every other control.

The rest of this guide addresses each of these vectors with practical mitigations.

Secrets Management

The goal isn’t just “don’t commit secrets” — it’s ensuring secrets are never visible outside the moment they’re needed.

Scope access tightly. Not every pipeline stage needs the same credentials. Use environment-scoped secrets so your staging database password isn’t available during production deployments, and vice versa:

variables:
  # Available everywhere
  stripe_key: ${{ secret("STRIPE_PUBLIC_KEY") }}
  # Only available in this stage
  db_password: ${{ stage_secret("DB_PASSWORD") }}

Defer resolution. Secrets shouldn’t exist in your deployment plan at all. DevRamps uses a deferred resolution model — secret references are replaced with markers during pipeline synthesis, and actual values are only retrieved at the moment a step executes. They’re never stored in the database, the dashboard, or the deployment plan.

Mask in logs. Even with deferred resolution, a step might accidentally echo a secret value. DevRamps automatically masks secret values in all log output, replacing them with ***. This catches the cases where application code or scripts inadvertently print sensitive values.

Control the encryption keys. For sensitive workloads, you can choose between letting DevRamps manage encryption (Service Managed) or using your own KMS key in your AWS account (User Managed). User-managed keys mean you retain full control over who can decrypt your secrets.

For a broader look at secrets hygiene including secret scanning and rotation, see Securing Your Deployments.

IAM Least-Privilege for Deployment Roles

Long-lived AWS credentials are the single biggest risk in CI/CD pipelines. If they leak, an attacker has persistent access until someone notices and rotates them.

Use OIDC federation instead of access keys. DevRamps creates an OpenID Connect identity provider in each target account during bootstrap. When a deployment runs, it requests temporary STS credentials via OIDC — no access keys are stored anywhere, and credentials expire automatically.

Scope trust policies. The IAM role created by bootstrap only allows your specific organization and pipeline to assume it. A compromised pipeline in a different org can’t use your deployment role:

{
  "Effect": "Allow",
  "Principal": { "Federated": "arn:aws:iam::oidc-provider/devramps.com" },
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringEquals": {
      "devramps.com:org": "your-org",
      "devramps.com:pipeline": "your-pipeline"
    }
  }
}

Grant only what each step needs. The bootstrap CLI analyzes your pipeline definition and generates IAM policies scoped to the specific step types you use — ECS, Terraform, Docker build, etc. If your pipeline only deploys ECS services, the role doesn’t get EKS, Lambda, or S3 permissions.

Audit additional permissions. When you need custom permissions beyond the built-in step types, add them in aws_additional_iam_policies.yaml with specific actions and resource ARNs — not wildcards:

- Version: "2012-10-17"
  Statement:
    - Effect: Allow
      Action:
        - s3:GetObject
        - s3:PutObject
      Resource: "arn:aws:s3:::my-deploy-bucket/*"

Pipeline Artifact Integrity

Your pipeline is only as secure as the artifacts it builds and deploys.

Pin dependency versions. Use lock files (package-lock.json, poetry.lock) and commit them. Floating version ranges mean a compromised package update can silently enter your build.

Scan container images. If you’re deploying containers, scan images for known vulnerabilities before they reach production. Tools like Trivy or Docker Scout catch CVEs in base images and dependencies that your application-level scanning might miss.

Require approval for pipeline changes. Pipeline definitions themselves are a deployment vector. DevRamps lets you require approval before pipeline configuration changes take effect:

pipeline:
  pipeline_updates_require_approval: ALWAYS

With DESTRUCTIVE_CHANGES_ONLY, additions go through automatically but removing stages or steps requires a human sign-off. This prevents a compromised commit from silently altering your deployment pipeline.

Approval Gates and Manual Checkpoints

Automated pipelines shouldn’t mean zero human oversight. Strategic approval gates create checkpoints where a person reviews what’s about to happen.

Terraform plan review. For infrastructure changes, require approval before applying. The DESTRUCTIVE_CHANGES_ONLY mode is a good middle ground — new resources deploy automatically, but modifications and deletions get human review:

- name: Synthesize Infrastructure
  type: DEVRAMPS:TERRAFORM:SYNTHESIZE
  params:
    requires_approval: DESTRUCTIVE_CHANGES_ONLY
    source: /infrastructure

Bake time periods. After deploying to a stage, pause and observe before promoting. A 5-minute bake period catches issues that only surface under real traffic:

- name: Bake Period
  type: DEVRAMPS:APPROVAL:BAKE
  params:
    duration_minutes: 5

Automated test gates. Run integration tests as a deployment gate. If tests fail, the deployment stops — no manual intervention needed, no bad code reaching the next stage:

- name: Integration Tests
  type: DEVRAMPS:APPROVAL:TEST
  params:
    testCommand: npm test
    testType: jest

These gates complement each other. A typical production pipeline might run tests, deploy, bake, then require manual approval before the next region.

Audit Logging and Compliance

When something goes wrong — or when an auditor asks — you need a clear record of what happened, when, and who approved it.

Deployment history. DevRamps logs every deployment with the commit that triggered it, the stages it passed through, and the outcome. This is your first-line audit trail.

Log retention. Step logs are stored in CloudWatch with 90-day retention. Secret values are automatically masked, so logs are safe to retain and review without risk of credential exposure.

Event forwarding. For teams that need to integrate deployment events into their own systems, DevRamps forwards pipeline events to Amazon EventBridge. Route stage failures to PagerDuty, approval requests to a custom Slack bot, or all events to a SIEM for compliance archival:

{
  "source": ["devramps"],
  "detail-type": ["Stage Failed", "Stage Auto Rolled Back"]
}

Every event includes the pipeline, stage, commit, and timestamp — enough context to reconstruct what happened without digging through logs.

Security by Default

The hardest part of CI/CD security isn’t knowing what to do — it’s making sure it actually happens on every pipeline, every time. DevRamps builds these practices in by default:

  • No long-lived credentials — OIDC federation with temporary STS tokens, set up during bootstrap
  • Least-privilege IAM — roles scoped to your specific pipeline and step types
  • Secrets never at rest in the pipeline — deferred resolution with automatic log masking
  • Approval workflows — Terraform plan review, bake periods, and test gates built into the pipeline definition
  • Audit trail — deployment history, CloudWatch logs, and EventBridge event forwarding

Security that requires extra effort gets skipped. Security that’s built into the platform happens every time.


For more on deployment security basics, see Securing Your Deployments. For multi-account isolation patterns, see Multi-Account AWS Deployment Best Practices.