Infra Stack Review

Managing Secrets Injection Across Multiple Deployment Environments

Columnist · · 10 min read
Cover illustration for “Managing Secrets Injection Across Multiple Deployment Environments”
CI/CD Workflows · August 6, 2026 · 10 min read · 2,340 words

A secret is any credential that grants access: API keys, database passwords, OAuth tokens, TLS certificates, cloud service account keys. Injection is the act of making a secret available to a process at the precise moment it needs it, not before, and never persistently afterward. That timing distinction is where most teams get into trouble.

There are three points in a deployment pipeline where injection can happen, and they are not equivalent.

Build time is the highest-risk injection point. Secrets baked into a container image travel with that artifact everywhere it goes: into registries, into caches, into any system that pulls the image. The exposure is often invisible because the secret is not surfaced as a credential; it is just embedded data sitting in a layer nobody is auditing. Teams discover this during incident retrospectives, well after the damage is done.

Deploy time is the most common approach: secrets injected as environment variables when a container starts. Workable, but it requires genuine attention to what persists in process memory, what surfaces in logs, and what appears in platform dashboards decrypted to plaintext on read. Most teams using this pattern have not thought through all three of those failure modes.

Runtime injection carries the smallest blast radius. The running process fetches secrets on demand from a vault, and nothing is pre-loaded into the environment. It requires application-level integration, which is why most teams do not start here. It is still the pattern worth building toward.

Your effective secrets perimeter is the union of every system that can read a production credential in cleartext: hosting provider dashboards, CI secret stores,.env files on developer machines. All of them count. Injection strategy cannot be designed around a single tool because the exposure surface is never a single tool.

Table: Secrets Injection Timing: Risk Profiles Compared. Compares Blast Radius, Primary Risk, Visibility, Typical Adoption, and 1 more by Build Time, Deploy Time and Runtime.

Why Dev, Staging, and Production Must Be Treated as Fully Isolated Secrets Domains

The intuitive failure mode here is sharing credentials between staging and production because staging mirrors prod. It is a reasonable shortcut at small scale. It becomes a structural liability quietly, before anyone notices, and usually before anyone is looking.

Staging environments rarely receive the same access controls, audit logging, or rotation discipline as production, and developers know it. Tokens get reused across environments because it is faster. Test.env files end up in version control because they feel lower-stakes. Access controls get temporarily disabled to unblock a debugging session and then never re-enabled. Each of those shortcuts is individually defensible. Collectively, they are a side door into production.

According to Verizon's 2025 Data Breach Investigations Report, 39% of secrets exposed in public Git repositories were tied to web application infrastructure. Staging credentials end up there disproportionately because they feel less consequential. They are not less consequential if they share scope with production systems.

The fix is environment-based segmentation: separate secrets namespaces for dev, staging, and production, with separate access policies governing each. Staging should have its own database, its own API keys for third-party services, its own model provider credentials. Pointing a less-controlled environment at production services is not a staging environment; it is a misconfigured production environment with reduced oversight.

Credentials for deployment operations should never be fetchable during a test stage. Secrets intended for production should be inaccessible to development pipelines. Those are the minimum conditions for environment isolation to mean anything at all.

Centralized Secret Storage and the Access Control Model That Makes It Work

You cannot rotate, audit, or scope credentials you cannot locate. Centralization into a dedicated vault is the prerequisite for everything else in this architecture. HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, and Azure Key Vault all provide that foundation, with different integration surfaces and tradeoff profiles worth evaluating against your stack.

Once credentials live in one place, granular access control becomes tractable. Role-based access control grants access based on role, full stop. Attribute-based access control is more expressive: access can be conditioned on environment, time window, originating IP, or workload identity. For complex multi-environment deployments, the additional configuration burden of ABAC is worth carrying.

The governing model is least privilege. Every service, pipeline, and engineer gets access to exactly the secrets they need, nothing beyond that. Standing permissions are a liability. Just-in-time access models ensure credentials are only accessible during a pre-approved window rather than permanently available to anyone holding the right role.

Applications should authenticate to the vault without carrying a static key. OIDC-based authentication lets workloads authenticate using their cloud or on-premises identity provider. AWS IAM roles, GCP Workload Identity, and Azure Managed Identity accomplish the same goal natively. The whole point is eliminating the static key, because the static key is the thing that gets committed to a repository, shared in a Slack message, or left in a.env file that outlives the sprint. I have seen all three of those happen at companies that thought they had their secrets story figured out.

Audit logging is a byproduct of centralization, not a separate project. Every secret read, every access grant, every rotation becomes a logged event. B2B SaaS teams preparing for SOC 2 routinely discover credentials scattered across their infrastructure, most of them undocumented, and reconstructing the audit trail requires a substantial consulting engagement just to inventory what existed. Centralization before that point collapses that cost entirely.

Dynamic Secrets and Injection Patterns That Eliminate the Static Credential Window

Static credentials have a lifecycle problem that teams manage through avoidance. The credential is created once, distributed across however many systems need it, and then either forgotten or rotated on a schedule that keeps slipping because the rotation process is manual and the risk of breaking something in production feels more immediate than the risk of a stale credential sitting somewhere exposed. So the credential just sits. Sometimes for years.

Dynamic secrets invert this entirely. Credentials are generated on demand, scoped to a specific workload and time window, and expire automatically. There is no rotation schedule to maintain because the credential never persists long enough to require one.

In a CI/CD pipeline, the sequence looks like this: the runner authenticates to the vault using OIDC or workload identity, so no stored credential is required to initiate the process. The vault issues short-lived credentials scoped to that specific pipeline run. Those credentials are injected as environment variables valid only for the duration of that execution, then discarded automatically. Nothing persists in logs or build artifacts.

For container workloads, sidecar injection is a common pattern. A short-lived sidecar container fetches secrets from the vault and writes them to a shared in-memory volume. The application container reads from that mounted volume. Secrets never touch the container image or the environment variable layer. HashiCorp's Vault Agent Sidecar Injector is one widely deployed implementation of this pattern, worth understanding even if you end up using something else, because the conceptual model transfers.

Scoping discipline matters throughout. Test stages should not fetch deployment credentials. Build stages should have no access to production database passwords. Each pipeline stage should access only what that stage requires. Native CI/CD integrations with GitHub Actions, GitLab CI, CircleCI, and Jenkins can pull from vaults directly without storing secrets in the platform's own secret store, which reduces the number of systems holding plaintext credentials at any given moment. That number is the thing you are always trying to minimize.

What PaaS Migrations Reveal About Secrets Architecture: The Heroku Transition as a Case Study

Heroku's shift toward a maintenance-focused support posture drove a significant wave of platform migrations, and those migrations are worth examining not just as an operational event. They function as a diagnostic tool. They force teams to make explicit what the platform was handling implicitly, and secrets architecture is almost always the first implicit dependency that surfaces.

Heroku has two secrets categories that behave differently in ways most teams never had reason to examine. Runtime config vars are set via CLI and injected at container startup. Build-time variables are injected during the build process itself. Different mechanisms, different access points, different risk profiles. Heroku abstracted that distinction for years. The migration removes the abstraction, and teams that never understood it find out the hard way.

The most common migration failure is predictable: teams complete the move and find builds breaking because the target platform does not inject build-time credentials the way Heroku did silently. Mapping every config var to its equivalent on the target platform, and explicitly identifying which are runtime versus build-time, needs to happen before the migration begins.

Platform-specific secrets handling varies in ways that matter operationally. Vercel scopes environment variables to three environments (Development, Preview, and Production), supports branch-specific variables, and deploys changes without downtime. Railway and similar platforms support CLI-based secret management, which allows secrets to be set programmatically rather than through a dashboard UI. For teams that want to treat secrets configuration as code, that distinction is meaningful and worth prioritizing.

The trap that recurs across these migrations is copying a single secrets configuration across all environments and discovering mid-migration that staging is now pointing at production databases. It happens because the migration creates time pressure and the environment isolation work gets deferred. The migration moment is also, for exactly this reason, the right moment to move secrets out of platform-native storage and into a centralized vault. If credentials live in the vault and the platform simply references them, the next migration requires no archaeology.

Secrets Management for AI/ML Workloads Introduces a Distinct Set of Credential Types

Standard secrets management tooling was not designed for the credential surface that AI/ML workloads introduce. The types are different, the access patterns are different, and the risks concentrate in places that general-purpose tooling does not address.

Model provider API keys from services like OpenAI, Anthropic, and Google are high-value, frequently shared carelessly across environments, and rarely rotated because rotation breaks active experiments. That last part is the real problem. The cultural norm around experimentation creates a practical argument against rotation that teams accept without examining, and it persists because nobody is directly accountable for it until something goes wrong. Model registry credentials from platforms like Weights & Biases and MLflow tie to experiment tracking and versioned artifacts, creating a lineage dependency that complicates rotation further. Dataset storage credentials for S3 or GCS buckets holding training data are frequently granted overly broad access because data pipelines are complex and debugging access failures during a training run is expensive. Inference endpoint tokens are scoped differently from training credentials and tend to be exposed to more systems because inference is externally accessible.

Training and inference are architecturally distinct workloads with different secrets profiles. Training runs are long-lived, multi-node jobs; credentials need to persist across a run but should not survive after it. Inference endpoints are latency-sensitive and frequently scaled; secrets must be available at startup without adding latency, and rotation must avoid interrupting serving. Conflating these two contexts when designing access policy is a mistake that surfaces at the worst possible time.

GPU infrastructure frequently spans multiple providers simultaneously, typically a hyperscaler for managed services and a specialized GPU cloud for compute cost efficiency. Secrets must be scoped and managed across that hybrid surface. This is not an edge case; it is the normal operating environment for any team doing serious training work.

The same environment isolation principle applies here as everywhere else, with one additional wrinkle: the culture around notebooks is historically permissive about credential hygiene. Model provider API keys are particularly easy to commit to a notebook or script, and the notebook-to-repository pipeline has burned teams repeatedly. Development experiments should use sandboxed API credentials with rate limits or mock endpoints. Production inference should use separately scoped, separately rotated credentials that never touch a developer laptop. The cultural gap between those two norms is where most AI/ML credential incidents actually originate.

Building a Rotation and Audit Practice That Holds Up Under a Compliance Review

Rotation is where most secrets strategies quietly collapse. Credentials are centralized, access-controlled, properly scoped, and then never actually rotated because the process is manual and the perceived risk of breaking something in production feels more immediate than the risk of a stale credential being exploited. Teams know this logic is flawed. They do it anyway because the downside of a broken deployment is immediate and visible, and the downside of a stale credential is diffuse and deniable until it is neither.

Automated rotation removes that choice. Vault-native rotation for database credentials, cloud service keys, and API tokens happens on a defined schedule without human intervention. The application fetches the current version from the vault at runtime; nothing breaks because nothing is hardcoded to a specific credential value. Dynamic secrets sidestep the rotation problem entirely for workloads that support them. A credential that expires after one pipeline run has no rotation schedule to maintain because it never existed long enough to go stale.

SOC 2 and HIPAA audit requirements map directly onto what a centralized vault produces automatically. The relevant events are who or what accessed a secret and when, when a secret was rotated and by what mechanism, when access was granted or revoked, and whether any access occurred outside approved windows. A centralized vault generates all of this as a byproduct of normal operation. Without centralization, reconstructing the same audit trail means combing through platform logs, CI logs, and engineer access records across multiple systems, and that archaeology is expensive every time it is required.

Teams that centralize secrets management before a compliance review consistently find the process substantially less painful than teams that do not. The audit trail that would otherwise require weeks of reconstruction is already in the vault's log. The manual credential rotation work that consumed engineering time weekly is gone. The evidence that access controls were enforced is already there, rather than something that needs to be assembled after the fact.

The investment in coherent secrets architecture is a recurring operational saving. The compliance benefit is a byproduct of the same discipline that makes the system reliable day to day. Every audit, migration, and scaling event that comes afterward costs less than it would have otherwise.

Sources

  1. infisical.com
  2. akeyless.io
  3. cheatsheetseries.owasp.org
  4. doppler.com
Filed underCI/CD Workflows

More in CI/CD Workflows