Skip to main content
Cloud DevOps Solutions
Get a quote Talk to an engineer

CI/CD Pipelines

Secrets Management in CI/CD: Vault, AWS Secrets Manager and Azure Key Vault

CI/CD secrets management means pipelines obtain credentials at run time from a central store such as HashiCorp Vault, AWS Secrets Manager or Azure Key Vault, using short-lived identity federation (OIDC) rather than stored keys. This removes long-lived credentials from repositories and CI settings and gives each job only the access it needs.

Key takeaways

  • The best pipeline secret is the one that does not exist: OIDC federation replaces stored cloud keys with short-lived tokens.
  • Application secrets belong in a dedicated store, fetched at deploy or run time, not copied into CI variables.
  • Access is scoped by repository, branch and environment, so a feature branch cannot reach production credentials.
  • Masking helps but is not a control. Preventing secrets from reaching logs and artefacts is.
  • Rotation and revocation must be rehearsed, because that is when you discover where a secret was copied.

Why pipelines are a favourite target

A CI system holds some of the most powerful credentials in your company. It can read your source, push to your registry and deploy to production. If an attacker, a compromised dependency or a careless script gets hold of those credentials, the damage is large and quiet. Yet in many startups the pipeline’s secrets are a handful of long-lived cloud access keys pasted into settings pages two years ago, shared across projects and known to a former contractor.

Good secrets management makes the pipeline less valuable to attack and a leak less costly. It is a core part of our CI/CD pipeline service, and this page describes the approach.

What good looks like

  • No long-lived cloud credentials in CI. Jobs authenticate through federated identity and receive short-lived tokens.
  • Least privilege per job. A test job cannot deploy. A staging job cannot touch production.
  • A single source of truth for application secrets with audit logs, versioning and rotation.
  • Secrets stay out of images, repositories and logs.
  • Fast revocation. You can find where a secret is used and replace it quickly.

Step one: remove cloud keys with OIDC

The largest single improvement is eliminating stored access keys. GitHub Actions, GitLab CI and Azure DevOps can each issue a signed OpenID Connect token that identifies the repository, branch and environment of a running job. AWS, Azure and Google Cloud can trust those tokens and issue temporary credentials in exchange.

In GitHub Actions with AWS, a job looks like this:

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/ci-deploy-production
          aws-region: eu-west-1
      - run: aws sts get-caller-identity

The account ID above is a documentation-style example. The important part is the role’s trust policy, which restricts who may assume it, for example only the main branch or the production environment of one repository:

{
  "Effect": "Allow",
  "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" },
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringEquals": {
      "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
      "token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:environment:production"
    }
  }
}

A missing or loose sub condition is the most common mistake we see: it lets any repository in the organisation, or even any GitHub repository, assume the role. We review these policies carefully. Azure uses federated credentials on an app registration, and the principle is identical.

Step two: pick a store for everything else

OIDC handles cloud access. Applications still need database passwords, API keys and signing certificates. These belong in a dedicated store.

OptionStrengthsCosts and limits
AWS Secrets ManagerNative IAM, rotation for supported databases, little to operatePer-secret pricing; AWS only
Azure Key VaultNative Entra ID access control, certificates and keysAzure only
HashiCorp VaultMulti-cloud, dynamic short-lived database credentials, rich policiesYou run, upgrade and secure it, or pay for a managed edition

Our default advice: if you live mostly in one cloud, use that cloud’s service and avoid operating a secrets platform. Choose Vault when you need dynamic credentials generated per job, a consistent model across clouds or on-premises, or finer policy control. It is powerful, but a mis-run Vault becomes a single point of failure.

Getting secrets to workloads

For Kubernetes, avoid putting plaintext in manifests. Options include the External Secrets Operator, which syncs from a cloud store into native Kubernetes secrets, the Secrets Store CSI driver, which mounts secrets as files, or Sealed Secrets for encrypting values committed to Git. Each has trade-offs: External Secrets keeps one source of truth, whereas Sealed Secrets suits small teams wanting everything in Git. Understanding how ConfigMaps and Secrets behave matters too, because Kubernetes Secrets are base64-encoded, not encrypted, unless you enable encryption at rest.

Step three: stop leaks

Prevention is cheaper than rotation.

  • Push protection and scanning. Block commits containing known credential patterns, and scan history with a tool such as Gitleaks.
  • Scoped, environment-level secrets. Variables for production are only available to jobs on a protected branch targeting the production environment, as part of promotion gates.
  • Safe handling in scripts. Avoid set -x around sensitive commands, do not pass secrets as command-line arguments (they show in process lists), and prefer files or environment variables.
  • Fork protections. Pull requests from forks should not receive secrets. Be careful with pull_request_target style triggers, which can expose secrets to untrusted code.
  • Pin third-party actions. A compromised action runs with your job’s permissions. Pinning to a commit SHA and reviewing updates reduces that risk.

Masking in CI logs is a convenience, not a security control. It only recognises exact known values, so a base64-encoded or split secret slips through.

Decisions and trade-offs

Dynamic versus static secrets. Vault can create a database user per job that expires in minutes. This greatly limits blast radius but needs the database integration to be reliable. Static secrets with rotation are simpler and good enough for many teams.

Central store versus CI variables. A central store adds a dependency: if it is down, deploys may stall. We design fallbacks and caching sensibly, and keep the secret store highly available proportional to its importance.

Self-hosted runners. They can use instance roles, which avoids secrets entirely, but shared runners that serve many projects risk cross-job leakage. We prefer ephemeral runners.

When not to over-engineer. A small team with two services and one cloud does not need Vault. OIDC plus the cloud secret manager covers most of the value.

Common failure modes

  • Overly broad trust policies on OIDC roles.
  • One shared “ci-user” with administrator rights.
  • Secrets copied into several projects, then only rotated in some.
  • Secrets baked into Docker images, visible to anyone who can pull them. Our image build and scan stage checks for this.
  • No rotation because nobody knows where a secret is used.
  • Credentials in Terraform state or logs. State needs encryption and tight access.

Delivery and handover

We start with an inventory and a risk-ranked plan, then replace cloud keys first because that gives the biggest reduction in risk. Secrets are migrated to the chosen store service by service, with the old values revoked once confirmed unused. You receive a register of secrets with owners, rotation schedules and a revocation runbook that we test with your team.

How to tell it is working

Count long-lived credentials in CI (the target is zero for cloud access), measure the age of your oldest secret, check that secret scanning findings trend down, and test that a revoked credential genuinely stops working. Also confirm that a job on a feature branch cannot assume your production role. If you want a review of your current setup, talk to us.

References

How we deliver it

  1. 01

    Inventory every secret

    We find credentials in CI variables, repositories, scripts and developer machines, and record owner, scope and age.

  2. 02

    Replace cloud keys with OIDC

    Pipelines assume cloud roles through federated identity, with trust policies limited to specific repositories, branches and environments.

  3. 03

    Choose the right store

    Vault, AWS Secrets Manager or Azure Key Vault is selected to fit your cloud footprint, and secrets are moved there with clear ownership.

  4. 04

    Integrate with pipelines and workloads

    Jobs fetch only what they need at run time. Kubernetes workloads receive secrets through an operator or CSI driver, not baked into images.

  5. 05

    Add detection

    Secret scanning on commits and in history, push protection, and log checks catch leaks early.

  6. 06

    Rotate and rehearse

    Rotation schedules and a tested revocation procedure turn a leak from a crisis into a routine task.

Tools and technologies

HashiCorp VaultAWS Secrets ManagerAzure Key VaultOIDCAWS IAMExternal Secrets OperatorSealed SecretsGitleaksGitHub secret scanningTerraformKubernetes CSI Secrets Store

Frequently asked questions

What is the safest way to give CI access to AWS or Azure?
Use OpenID Connect federation instead of stored access keys. The CI platform issues a signed identity token per job, and the cloud provider exchanges it for short-lived credentials if the token matches a trust policy. There is no long-lived key to leak, and the policy can restrict access to a repository and branch.
Should secrets live in CI variables or a secrets manager?
CI variables are fine for a few low-risk values scoped to an environment. Anything shared, sensitive or needed at run time by applications belongs in a dedicated manager, with audit logs, rotation and fine-grained access. Copying secrets into several CI projects creates drift and makes rotation painful.
HashiCorp Vault, AWS Secrets Manager or Azure Key Vault?
Pick the cloud-native service if you are mostly on one cloud, because it integrates with IAM and has little to operate. Choose Vault when you need multi-cloud, dynamic database credentials or advanced policies, accepting that you must run and secure it, or pay for a managed offering.
How do you stop secrets appearing in CI logs?
Masking only hides known values and fails on transformed ones, such as base64 or partial output. The stronger approach is avoiding the exposure: never echo variables, disable shell tracing around sensitive steps, pass secrets by file or environment rather than arguments, and scan logs and artefacts for patterns.
What should we do if a secret has leaked?
Revoke it first, then rotate and investigate. Assume the value is compromised the moment it appears in a public or shared place. Remove it from history only after revocation, since the old value stays valid until revoked. Review access logs for use between exposure and revocation.

Talk to an engineer about ci/cd secrets management

Book a free 30-minute call. We review your current setup and tell you honestly whether and how we can help.

Written by Saddique Khan, DevOps / SRE / Cloud Consultant Engineer. Last updated 2026-10-08.