A medical-device manufacturer — the kind that ships networked infusion pumps and the cloud backend that monitors them — gets a memo from its VP of Quality that lands like a fire alarm. The FDA’s refuse-to-accept policy now requires a Software Bill of Materials with every premarket submission, a hospital customer’s procurement team has started demanding signed-provenance attestations before they will connect a device to their network, and the company’s own AppSec lead just flagged that the build server holds a long-lived cloud admin key that 40 engineers can reach. The board’s read is blunt: a compromised build pipeline that slips a tampered binary onto a Class II device is not a “security incident,” it is a recall, a warning letter, and a headline. The ask is “make our pipeline something an FDA auditor and a hospital CISO will both trust.” This article is the reference architecture for that — a secure CI/CD supply chain built on Jenkins, HashiCorp Vault, and Wiz Code, where secrets are short-lived, every artifact is scanned and signed, and nothing critical ships without passing a gate.
The pressures here are specific to regulated manufacturing but rhyme with every enterprise. Provenance means you must be able to prove, cryptographically, that the binary running on a device is the one that came out of your reviewed source — the SolarWinds and 3CX attacks both subverted the build step, not the source repo. Least privilege means the blast radius of a compromised build agent has to be minutes and one project, not a standing key to the whole cloud estate. Shift-left means a misconfigured S3 bucket or an over-permissive IAM role is caught on the pull request, not in a Wiz alert three weeks after it shipped. And auditability means every one of those controls produces evidence a regulator can read. The supply-chain-security pattern satisfies all four by treating the pipeline itself as the thing to secure: short-lived credentials, scanning as a gate, and signed attestations at every hop.
Why not the obvious shortcuts
Three “we already do security” answers will be proposed in the first meeting, and each fails in a way worth naming.
Storing cloud keys in Jenkins credentials feels solved — the keys are “encrypted at rest.” But they are long-lived, broadly scoped, and a single compromised pipeline script, malicious plugin, or curious engineer with job-configure rights exfiltrates a credential that works for months. Running a nightly security scan catches the misconfiguration eventually, but “eventually” means the vulnerable infrastructure was live in production for the gap, and the finding lands on a triage queue nobody owns. Trusting the artifact because it came from our Jenkins assumes the build environment is trustworthy — but with no signature and no SBOM, you cannot prove after the fact that the image in your registry is the one your pipeline built, or what open-source components are inside it when a Log4Shell-class CVE drops at midnight.
The secure-supply-chain pattern threads the needle. Secrets are minted on demand and expire in minutes, so a leaked credential is worthless by the time anyone finds it. Security scanning is a gate, not a report — a critical IaC finding or an unsigned image fails the build. And every artifact carries a signed SBOM and provenance attestation, so “is this binary trustworthy” becomes a verifiable cryptographic question instead of an act of faith.
Architecture overview
The platform runs two intertwined concerns over the same pipeline: a build-and-release flow that turns a commit into a signed, deployed artifact, and a policy-and-secrets control plane that gates every step and hands out short-lived credentials. Keeping those two planes distinct — the thing that moves code, and the thing that decides whether code is allowed to move — is the mental model that makes this operable.
The defining property of the whole topology is the one the AppSec lead cares about most: no standing long-lived cloud credentials live anywhere in the pipeline, and nothing reaches an environment without passing a gate. Build agents are ephemeral and credential-less at rest; they authenticate to Vault with a verifiable workload identity and receive a credential that dies when the job ends. Every promotion across an environment boundary is a checkpoint where scanning, signing, and policy must all pass.
Build-and-release flow, following the control flow:
- A developer opens a pull request in GitHub. They authenticate through Okta as the workforce IdP, federated to Microsoft Entra ID so the cloud platform sees a first-class token and the same conditional-access policy that governs everything else. The PR is the first gate, not an afterthought.
- The PR triggers a Jenkins multibranch pipeline. The build runs on an ephemeral agent — a Kubernetes pod or short-lived VM spun up per job and destroyed after — so there is no warm machine holding secrets between runs and no agent state for an attacker to camp on.
- Before the agent can touch any cloud or registry, it authenticates to HashiCorp Vault using its workload identity (the Kubernetes service-account JWT, validated by Vault’s Kubernetes auth method). Vault returns short-lived, narrowly-scoped credentials — a dynamic AWS IAM credential leased for the build’s duration, a registry push token, an artifact-signing identity — none of which existed before the job and all of which expire minutes after it.
- Wiz Code scans the change. On the PR it analyzes the Terraform / IaC and application manifests for misconfigurations, exposed secrets, and risky permissions before anything is provisioned, and posts findings inline on the pull request. The same scan engine evaluates the built container image for vulnerable OS and library packages.
- The pipeline generates an SBOM (CycloneDX or SPDX) from the resolved dependency tree, then signs the image and the SBOM with the Vault-issued signing key, producing a provenance attestation bound to the artifact’s digest.
- A policy gate evaluates everything together: Wiz Code findings, SBOM contents against a vulnerability and license policy, and signature validity. Critical findings fail the build — the artifact never reaches the registry, and the developer gets the reason on the PR.
- On pass, the signed image and its attestations are pushed to the artifact registry (ECR / GAR / ACR, or Harbor on a virtual appliance for air-gapped builds). Argo CD then deploys to the target cluster, but only after verifying the signature and provenance at admission — an unsigned or policy-violating image is rejected at the door, even if it somehow reached the registry.
Policy-and-secrets control plane, running alongside every step: Vault is the broker for all dynamic credentials and signing keys, with audit logging on every secret issuance. Wiz runs continuously across the cloud accounts and registries for posture and runtime risk, correlating a finding back to the exact PR and commit that introduced it. Terraform / Ansible provision and configure the pipeline infrastructure itself as reviewed, scanned code — Terraform for cloud resources, Ansible for the Jenkins controller and agent base images — so the build platform is as governed as what it builds.
Component breakdown
| Component | Service / tool | Role in the supply chain | Key configuration choices |
|---|---|---|---|
| Identity / SSO | Okta + Microsoft Entra ID | Workforce SSO (Okta) federated to Entra; governs Jenkins, Vault, Argo CD login | OIDC federation; group claims drive RBAC; conditional access; no local admin accounts |
| CI orchestration | Jenkins | Pipeline build, test, scan, sign, gate; ephemeral agents | Kubernetes plugin for per-job agents; pipeline-as-code in repo; no inbound creds stored |
| Secrets & signing | HashiCorp Vault | Short-lived cloud creds, registry tokens, image-signing keys | Kubernetes auth method; dynamic AWS/DB secrets engine; Transit/PKI for signing; full audit log |
| IaC & image scanning | Wiz Code | Scan Terraform/IaC + images on PR; block on critical | PR integration; secret-detection; IaC policy packs; image vuln scan in the pipeline |
| Cloud posture | Wiz | Continuous CSPM, attack-path, runtime risk across accounts | Agentless account scan; finding-to-PR correlation; drift alerts to ServiceNow |
| SBOM & provenance | Syft / cosign (in pipeline) | Generate CycloneDX/SPDX SBOM; sign image + attestation | SBOM per build; keyless or Vault-keyed signing; attestation bound to digest |
| Artifact registry | ECR / GAR / ACR / Harbor | Stores signed images and attestations | Immutable tags; image scanning on push; Harbor on a virtual appliance for air-gap |
| GitOps deploy | Argo CD | Deploy to clusters with signature verification at admission | Sigstore policy / admission controller; sync only signed, policy-passing images |
| IaC provisioning | Terraform + Ansible | Provision pipeline infra (Terraform); configure controllers/agents (Ansible) | Remote state with locking; OIDC to cloud; agent golden images via Ansible |
| Edge | Akamai | TLS, WAF, anycast for the externally-reachable device backend and webhooks | WAF on the public API; bot protection; rate-limit on webhook endpoints |
| Runtime security | CrowdStrike Falcon | Runtime threat detection on build agents, Jenkins controller, deploy targets | Sensor on node pools and controller host; detections piped to the SOC |
| Observability | Dynatrace / Datadog | Pipeline timing, failure analytics, deploy-to-runtime tracing | DORA metrics; build-stage spans; correlate a deploy with a runtime regression |
| ITSM / approvals | ServiceNow | Change records for production deploys; auto-tickets on gate breaches | Change gate before prod sync; auto-ticket on critical Wiz finding or signature failure |
| LMS / enablement | Moodle | Secure-coding and supply-chain training for engineers, tracked for audit | Course completion as an audit artifact for the regulated SDLC |
A few of these choices deserve the why, because they are the ones teams get wrong.
Why dynamic secrets, not vaulted static keys. Putting a long-lived AWS key into Vault and reading it from the pipeline is better than putting it in Jenkins credentials — but only marginally, because the key is still long-lived and broadly scoped. Vault’s real power is the dynamic secrets engine: when a build needs to push infrastructure, Vault calls AWS, mints a brand-new IAM credential scoped to exactly that role, leases it for, say, 15 minutes, and revokes it automatically when the lease expires or the job ends. The credential never existed before the job and is dead after it. A leaked build log, a compromised agent, an exfiltrated environment variable — all of it is worthless within minutes. The shift from “rotate static secrets quarterly” to “secrets that self-destruct per job” is the single biggest reduction in blast radius this architecture buys.
Why scanning must be a gate, not a dashboard. A scanner that posts findings to a report nobody is forced to read changes nothing. Wiz Code runs as a required check on the pull request and as a required stage in the Jenkins pipeline, and the policy gate fails the build on a critical IaC misconfiguration (a public S3 bucket, a wildcard IAM policy, a hardcoded secret) or a critical image CVE. The developer sees the exact line of Terraform and the fix on their PR, before the resource is ever provisioned. The cultural shift is from “security reviews us after we ship” to “security is a test we run on every change” — and it only works because the gate has teeth.
Why sign the artifact and verify at admission. Generating an SBOM and signing the image at build time proves provenance only if someone checks the signature before running it. Signing without verification is theater. So the pipeline signs the image and SBOM with a Vault-issued key, and Argo CD verifies that signature and the provenance policy at deploy admission — an unsigned image, or one whose attestation does not match policy, is rejected at the cluster door even if an attacker managed to push it to the registry. Provenance becomes an enforced property of what runs, not a label on what was built.
Implementation guidance
Provision the pipeline as code, and treat secrets brokering as the first deliverable. The order matters: stand up Vault and its auth before you wire any pipeline, or engineers will “temporarily” paste a static key and it will outlive everyone’s intentions.
- Vault, deployed HA (Raft or on a virtual appliance for an air-gapped facility), with the Kubernetes auth method bound to the build namespace and the AWS secrets engine configured for the roles builds actually need.
- The Jenkins controller (configured by Ansible from a golden image) with the Kubernetes plugin, so agents are ephemeral pods — no static agent fleet holding state.
- Wiz Code wired to GitHub as a PR check and to the Jenkins pipeline as a stage, with IaC policy packs and image scanning enabled.
- The registry with immutable tags and scan-on-push, plus the Argo CD signature-verification policy at admission.
- All of the above defined in Terraform with remote state and locking, so the security platform is itself reviewed, scanned, and reproducible.
A minimal Vault role and a Jenkins step communicate the intent — credentials that exist only for the job:
# Vault: a dynamic AWS credential, scoped and short-lived
resource "vault_aws_secret_backend_role" "ci_deploy" {
backend = vault_aws_secret_backend.aws.path
name = "ci-terraform-apply"
credential_type = "assumed_role"
role_arns = [aws_iam_role.ci_terraform.arn] # least-privilege role
default_sts_ttl = 900 # 15 minutes — dies with the build
max_sts_ttl = 1800
}
// Jenkins: authenticate with workload identity, lease creds, never store them
withVault(vaultSecrets: [[
path: 'aws/creds/ci-terraform-apply',
secretValues: [
[vaultKey: 'access_key', envVar: 'AWS_ACCESS_KEY_ID'],
[vaultKey: 'secret_key', envVar: 'AWS_SECRET_ACCESS_KEY']
]
]]) {
sh 'wiz-code iac scan ./terraform --policy critical-blocking' // gate
sh 'terraform apply -auto-approve'
sh 'syft packages dir:. -o cyclonedx-json=sbom.json' // SBOM
sh 'cosign sign --key hashivault://image-signing $IMAGE_DIGEST' // sign
}
// creds are revoked the moment this block exits
Identity: kill the static keys, federate the humans. Jenkins, Vault, and Argo CD all authenticate humans through Okta → Entra federation, so an engineer logs in once with the company’s conditional-access-protected credentials and the same group claims drive RBAC everywhere — no local Jenkins admin accounts, no separate Vault user store. Build agents authenticate to Vault with their Kubernetes service-account identity, not a token a human pasted, so the only “credential” an agent holds is one the platform can verify and revoke. The principle is uniform: every actor, human or machine, proves identity to get a short-lived grant, and nothing carries a standing key.
SBOM and signing wiring. Generate the SBOM from the resolved dependency tree at build time (Syft against the build directory or the final image), so it reflects exactly what shipped, not what the manifest declared. Sign the image and attach the SBOM as a signed attestation with cosign, keyed by Vault’s Transit or PKI engine so the signing key itself is never on the agent’s disk. Carry the commit SHA, builder identity, and pipeline run ID into the provenance attestation — that is the chain an FDA auditor or a hospital CISO follows from “this binary on the device” back to “this reviewed commit, built by this pipeline.”
Enterprise considerations
Security & Zero Trust. The architecture is Zero Trust applied to the pipeline: no implicit trust in the build agent, no standing credentials, identity required for every grant. Layer on top: (a) ephemeral, credential-less agents so a compromised build host has nothing to steal and no persistence; (b) Vault dynamic secrets so every credential self-destructs; © Wiz Code as a blocking gate so misconfigured infrastructure is caught on the PR, and Wiz continuously across the accounts as the posture backstop, correlating any drift back to the commit that caused it; (d) CrowdStrike Falcon sensors on the Jenkins controller, the agent node pool, and the deploy targets for runtime threat detection feeding the SOC — because a hardened pipeline still needs eyes on the hosts; (e) signature verification at Argo CD admission so only signed, policy-passing artifacts run. A critical Wiz finding or a signature-verification failure auto-raises a ServiceNow incident, so security has a ticket and an owner, not just a log line. The threat this defends against is concrete: an attacker who compromises a single build job finds short-lived scoped creds, a gate that blocks their tampered artifact, and a verification step that refuses to run anything unsigned.
Cost optimization. The spend here is build compute, tooling licenses, and the engineering time the gates save by catching issues early.
| Lever | Mechanism | Typical effect |
|---|---|---|
| Ephemeral spot agents | Run Jenkins agents on spot/preemptible nodes, scaled to queue depth | Build fleet costs a fraction of a standing pool |
| Shift-left gating | Catch IaC misconfigs on the PR with Wiz Code, not in prod | A fix on the PR is far cheaper than an incident + recall exposure |
| Layer & SBOM caching | Cache base layers and dependency resolution across builds | Cuts build minutes every run |
| Right-sized scanning | Scan changed paths on PR; full scan on merge to main | Keeps PR feedback fast without scanning the world each time |
| Consolidated tooling | Wiz Code + Wiz on one platform for PR-to-runtime correlation | Avoids a sprawl of point scanners and stitched dashboards |
The largest “cost” lever is avoided incident cost: for a regulated device maker, a single tampered-artifact event carries recall and warning-letter exposure that dwarfs the entire pipeline budget — which is the number that funds this build.
Scalability. Each plane scales independently. Jenkins agents scale horizontally as ephemeral pods on build-queue depth — the controller schedules, the cluster autoscaler supplies nodes, and there is no warm fleet to size for peak. Vault scales reads with performance standby nodes and is sized for secret-issuance throughput, not data volume. Wiz Code scanning parallelizes across PRs. The natural ceiling is usually registry and signing throughput at high merge rates, so cache aggressively and scan changed paths on the PR while reserving full scans for the merge to main.
Failure modes, and what each one looks like. Name them before they page you.
- Vault unavailable — no build can mint credentials, so the pipeline halts hard. That is the correct failure (fail closed, never fall back to a static key), but it makes Vault a tier-0 dependency: deploy it HA, monitor it, and rehearse its recovery.
- A leaked credential in a build log — real, but de-fanged: a dynamic credential is already expired or revoked by the time anyone reads the log. Mitigation: keep TTLs short and treat any leak as a same-day rotation regardless.
- Gate fatigue / bypass pressure — a noisy scanner that blocks on low-severity findings trains engineers to demand a bypass, and a bypassed gate is no gate. Mitigation: block only on critical, tune policy packs, and route the bypass itself through a logged ServiceNow approval so exceptions are visible.
- Unsigned image reaches the registry — an attacker or a misconfigured job pushes an artifact. Mitigation: Argo CD admission verification refuses to deploy it; the registry’s immutable-tag policy prevents silent overwrite of a good image.
- Stale SBOM — a CVE drops for a component the SBOM does not reflect because it was generated from the manifest, not the build. Mitigation: generate the SBOM from the resolved tree / final image, and re-scan existing images on new-CVE feeds, not only at build time.
Reliability & DR (RTO/RPO). Decide the numbers per plane. Vault is tier-0: replicate its Raft storage and rehearse unseal/recovery, targeting RTO under 30 minutes because no build ships without it. The Jenkins controller config lives in code (Configuration-as-Code + Ansible), so a controller is rebuildable from version control in minutes; the artifact registry is the durable source of truth and should be geo-replicated, since a signed image you cannot retrieve is a deploy you cannot do. A pragmatic target: RTO 30 minutes for the ability to build and deploy, RPO near zero for artifacts and Vault state (both replicated), with the whole pipeline reconstructable from Terraform/Ansible if a region is lost.
Observability. Instrument the pipeline end to end in Dynatrace or Datadog: a span per stage (checkout → scan → build → SBOM → sign → gate → deploy) with timing and pass/fail on each, plus DORA metrics — deployment frequency, lead time, change-failure rate, MTTR — so engineering leadership sees flow and the gates’ effect on it. Emit the security metrics the auditor cares about: percentage of artifacts signed, gate pass/fail rates by severity, mean credential TTL, time-to-remediate a critical finding. Correlate a deploy with its runtime behavior so a regression traces back to the exact build and commit. Production deploys pass through a ServiceNow change record, giving Quality a documented gate that maps directly to the regulated SDLC.
Governance. Pin scanner policy packs and signing-key identities explicitly so behavior does not drift, and keep all pipeline definitions, Terraform, and Ansible in version control, reviewable and revertable. The SBOM and provenance attestation per release are first-class compliance artifacts — the FDA submission and the hospital procurement attestation draw straight from them. Engineer secure-coding and supply-chain training through Moodle, with course completion recorded as an audit artifact for the regulated SDLC. Log every Vault secret issuance and every gate decision for audit and incident review.
Explicit tradeoffs
Accept these or do not build it. Dynamic secrets make Vault a hard tier-0 dependency — when Vault is down, builds stop, full stop, and that is the design, not a bug; you trade “builds always run” for “builds never run with a leaked standing key.” Gating on scans adds latency and friction to every PR, and a poorly-tuned policy that blocks on noise will breed bypass culture faster than it improves security. Signing and SBOM generation add build steps, key management, and the discipline of verifying at admission — sign without verify and you have spent effort on theater. Ephemeral agents mean you lose the convenience of a warm machine with cached state and “just SSH in to debug,” which some teams will miss. And the Okta-to-Entra federation plus per-actor identity is real setup that a small single-IdP shop with three engineers genuinely does not need.
The alternatives, and when they win. If you are a small team shipping a non-regulated internal tool, GitHub Actions with OIDC-to-cloud gives you keyless, short-lived cloud auth without standing up Jenkins and Vault — and OIDC federation is exactly the same least-privilege idea, just hosted. If your secrets needs are modest, a cloud-native secrets manager (AWS/Azure/GCP) covers static-secret rotation without Vault’s operational weight, though it lacks Vault’s dynamic-secrets and signing breadth. If you only need posture and not a build gate, Wiz alone (without Wiz Code in the pipeline) catches misconfigurations in the cloud after the fact — cheaper to adopt, but it is detection, not prevention. Graduate to this full Jenkins + Vault + Wiz Code supply chain when provenance, least privilege at build time, and auditable gates become non-negotiable — which, for anyone shipping regulated software or selling to security-conscious enterprises, they will.
The shape of the win
For the device maker, the payoff is not “we added a scanner.” It is that when the FDA submission asks for an SBOM, it is generated automatically and signed from the exact build; when a hospital’s CISO asks “prove this binary came from your reviewed source,” there is a verifiable provenance chain from device to commit; and when the next Log4Shell-class CVE drops at midnight, the team queries SBOMs to know in minutes which artifacts are affected instead of guessing for a week. Everything upstream — the ephemeral agents, the Vault dynamic secrets, the Wiz Code PR gate, the cosign signature verified at Argo CD admission, the Dynatrace pipeline spans, the ServiceNow change record — exists so that a regulator, a hospital CISO, and the company’s own board each say yes. The architecture here is the destination; a smaller team can start with OIDC and a single gate, but for regulated software shipping to customers who audit you, this is where a trustworthy supply chain has to land.