Git, CI/CD & GitOpsFinal · Final AssessmentFinal Review
Incident response and secrets — recap
What you'll learn
- Apply the first-respond rule for each of the three incident classes: secret, runner, supply-chain
- Distinguish revoke-or-rotate from history-rewrite and explain why rotation must precede rewrite
- Plan a secrets-management model that keeps plaintext secrets out of Git while remaining GitOps-compatible
- Define a rotation cadence for the credential classes (cloud keys, registry tokens, deploy keys, personal tokens) and the rotation triggers beyond the schedule
Prerequisites
- The GitOps secret problem — why plaintext credentials cannot live in Git
- External secret systems — Vault, cloud KMS, and the controller that bridges them
- Bitnami Sealed Secrets — cluster-bound encryption and the controller as the trust boundary
- SOPS and Mozilla SOPS — file-level encryption for the GitOps repository
- Git revert versus controller rollback — what Git undoes and what the controller undoes
- Environment secrets and isolation — secrets scoped to a deployment target
- Why rotate credentials — the cost of long-lived secrets
- Token rotation cadence — PAT, OAuth, and OIDC tokens
- Cloud credential rotation — IAM access keys and OIDC federation
- The incident arrives — first alert, first scope, first ten minutes
- Revoke or rotate first — the first action and the rationale that forces it
- The runner incident arrives — detection, initial scope, first ten minutes
- Isolate the runner — remove from pool, drain new jobs, preserve evidence
- Revoke credentials — what credentials did the runner have, and how to revoke them
- The supply-chain incident arrives — detection and initial triage
- Rotate credentials and revoke tokens — what the malicious code touched
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
CI/CD incidents are not all the same shape, and treating them as the same shape is how teams lose hours to the wrong remediation. The three classes — secret leak, runner compromise, supply-chain compromise — each have a distinct first-respond rule, and confusing them turns a recoverable incident into a multi-day forensic operation.
The three incident classes
flowchart TD
A[CI/CD incident] --> B{What leaked?}
B -->|credential| C[Secret leak]
B -->|code execution| D[Runner compromise]
B -->|dependency| E[Supply-chain compromise]
C --> F["First: rotate"]
D --> G["First: isolate runner"]
E --> H["First: stop builds"]
F --> I[Then: rewrite history]
G --> J[Then: revoke credentials]
H --> K[Then: identify impact]
- Secret leak. A credential (cloud key, registry token, personal access token, deploy key) has been exposed — committed to Git, logged in CI output, or shared over an insecure channel. First respond: rotate the credential immediately. The active exposure is the credential, not the Git history. A history rewrite without rotation is a partial fix.
- Runner compromise. A malicious job, a supply-chain attack via a third-party action, or a vulnerability in the runner host has produced unauthorised code execution. First respond: isolate the runner — drain the queue, remove the runner from the pool, freeze the autoscaler. The active exposure is the runner itself, which can mint new credentials, write to registries, and read every secret in scope.
- Supply-chain compromise. A dependency, a base image, or a third-party action has been compromised upstream. First respond: stop affected builds. The active exposure is every artifact produced by the compromised component since the compromise began.
The secrets-management model
The operational question is not “how do I store a secret” but “how do I keep plaintext secrets out of Git while remaining GitOps-compatible”. Three patterns, in order of operational complexity:
- External secret stores. HashiCorp Vault, AWS
Secrets Manager, Azure Key Vault. The manifest in Git
contains a reference (
vault://path/to/secret,aws-secrets-manager://name); a controller in the cluster resolves the reference and mounts the plaintext. The plaintext never appears in Git. - Encrypted-in-Git (SOPS, Sealed Secrets). The manifest in Git contains an encrypted blob; a controller in the cluster holds the decryption key and decrypts at apply time. The plaintext never appears in Git, but the encrypted blob is diff-friendly and review-friendly.
- Plaintext in Git. The manifest in Git contains the plaintext secret. Never acceptable in a production repository — secret scanning will eventually find it, a fork will eventually leak it, and a CI log will eventually expose it.
Rotation cadence and triggers
The two drivers of rotation are time (scheduled) and event (triggered). A rotation policy that has only the time driver is a policy that rotates the credential the day after it leaks. A rotation policy that has only the event driver is a policy that never rotates until something bad happens. The right policy has both:
| Credential class | Scheduled cadence | Event triggers |
|---|---|---|
| Personal access token | 90 days | Departure of the owner; team change; suspected exposure |
| Cloud access key | Replaced by OIDC federation | Any leak indicator; IAM policy change |
| Registry token | 90 days | Departure of the owner; CI runner decommission |
| Deploy key | 180 days | Project change; suspected exposure |
| OIDC trust policy | Reviewed quarterly | OIDC provider change; workflow file rename |
Production discipline
The five rules that recur across every incident response:
- First respond according to the incident class. Rotate for a secret leak; isolate for a runner compromise; stop builds for a supply-chain compromise. The first action is the one that closes the active exposure; everything else is forensic.
- Rotate, do not just revoke. A revoked credential can still be used in caches, in IAM sessions, in role assumptions. Rotation produces a new credential and revokes the old one; revocation alone leaves the active sessions in place.
- History rewrite is forensic, not first-respond. The rewrite can happen hours or days later; the rotation has to happen in minutes.
- Secrets in plaintext in Git are not a fix. Even with rotation. The secret may not be the only thing in the file, and the next secret will have the same fate. Replace the workflow with a secret-management pattern that does not put plaintext in Git.
- A break-glass procedure must be written before the incident. The on-call engineer at 03:00 with a leaked credential does not have time to design a procedure. The break-glass procedure is a runbook entry, not a thought experiment.
Cross-course references
- Linux for Production Sysadmins — Secret rotation
in
/etc/shadow, SSH key rotation, andsudotoken expiry are the operating-system analogues of CI/CD credential rotation. - Kubernetes for Production Sysadmins — The external-secrets operator pattern is the cluster-side resolution of the same problem the CI/CD side faces.
Quiz
Knowledge check · 4 questions
Q1. An engineer accidentally committed a long-lived AWS access key to the main branch six hours ago. The key has `AdministratorAccess`. The team is debating whether to rotate first or rewrite history first. What is the correct order?
Q2. For a runner-compromise incident, the first respond is to isolate the runner (drain the queue, remove from the pool, freeze the autoscaler) before revoking credentials or determining artifact impact.
Q3. Name the three patterns for keeping plaintext secrets out of a GitOps repository and the one that is never acceptable in production.
Q4. A third-party GitHub Action used by the production deploy workflow is discovered to have been compromised upstream. A malicious version was published for 90 minutes before the maintainer reverted it. The deploy workflow ran during the 90-minute window. Walk through the response, in order.
The Action `thirdparty/setup-terraform` was compromised and a malicious version `v3.0.0` was published. The deploy workflow pinned to `@v3` and therefore pulled `v3.0.0` during the window. The malicious version exfiltrated the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables to an external host. The deploy workflow ran 4 times during the window, against staging, pre-production, and production.
Passing score: 75%. Answers are checked in this browser.