โšก
Zero to Platform Architect2026
War-Room Triage & 43 Traps
War-Room Triage & 43 Trapsโฑ๏ธ 6 min readโšก Staff SRE Standard
๐ŸŽฏ Operations Test Bank →

๐Ÿ›ก๏ธ DevSecOps, Supply Chain & Fleet Patching Triage Guide

This guide details the most common, tricky, and critical production failure modes encountered across container security scanning (Trivy), cryptographic signing (Cosign / Sigstore), Kubernetes secret synchronization (External Secrets Operator), Golden AMI baking (Packer), and fleet patching (ASG Instance Refresh).


๐Ÿงญ Beginner-Friendly First-5-Minutes DevSecOps & Supply Chain Playbook (Step-by-Step SOP)

Mental Model (The Airport Passport Control): Supply chain security works like airport border control: 1. CI OIDC mints a short-lived passport โ†’ 2. Cosign stamps the container image digest โ†’ 3. Kyverno checks the stamp at the Kubernetes gate โ†’ 4. External Secrets Operator (ESO) delivers the room key.

Step 1: Check Admission Controller Rejection Reason (Minute 0โ€“1)

kubectl get events -n <namespace> --field-selector reason=PolicyViolation
kubectl logs -n kyverno -l app.kubernetes.io/component=admission-controller --tail=50

Step 2: Verify Container Image Digest & Cosign Signature (Minute 1โ€“2)

cosign verify <registry>/<image>@sha256:<digest> \
  --certificate-identity-regexp="https://github.com/org/.*" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com"

Step 3: Inspect External Secrets Operator (ESO) Synchronization Status (Minute 2โ€“3)

kubectl get secretstores,externalsecrets -A
kubectl describe externalsecret <name> -n <namespace>

Step 4: Check ASG Instance Refresh & PDB Drain Blockers (Minute 3โ€“5)

aws autoscaling describe-instance-refreshes --auto-scaling-group-name <asg-name>
kubectl get pdb -A

๐ŸŽฏ High-Impact Real-World Scenarios

Scenario 1: Air-Gapped EKS Cosign Keyless Verification Failure

The Symptom

Pods scheduled in a PCI-DSS compliant or air-gapped private EKS cluster fail admission with:

Error from server (InternalError): admission webhook "validate.kyverno.io" denied the request: 
failed to verify image signature: failed to fetch rekor public keys: 
dial tcp 34.120.12.55:443: connect: connection timed out

Under-the-Hood Root Cause

The CI/CD pipeline used standard keyless Sigstore signing (cosign sign --yes), which publishes cryptographic transparency entries to the public Sigstore Rekor ledger (rekor.sigstore.dev).

However, the production Kubernetes cluster resides inside an isolated, air-gapped private VPC with zero public internet access. When Kyverno or the admission controller attempts to verify the signature against Rekor, the outbound TCP connection times out, blocking all pod creation!

sequenceDiagram
    autonumber
    participant K8s as EKS API Server
    participant Kyverno as Kyverno Admission Webhook
    participant Rekor as ๐ŸŒ Public Rekor (rekor.sigstore.dev)
    participant Pod as Microservice Pod

    K8s->>Kyverno: Admission Request (New Pod)
    Kyverno->>Rekor: โŒ Verifies against public Rekor over Internet
    Note over Kyverno,Rekor: Private Subnet: No Internet Gateway or NAT Gateway!<br/>Connection times out after 15s! ๐Ÿšจ
    Kyverno-->>K8s: Admission Denied: Rekor Connection Timed Out!
    Note over K8s,Pod: Pod fails to schedule! Production halted!

Remediation & Architectural Standard

  • The Solution (Private AWS KMS Asymmetric Signing): For air-gapped enterprise environments, do NOT rely on public Sigstore infrastructure. Use AWS KMS Asymmetric Keys (ECC NIST P-256 or RSA-4096) with AWS PrivateLink endpoints:
# 1. Sign image via private AWS KMS VPC Endpoint
cosign sign --yes \
  --key awskms://arn:aws:kms:us-east-1:123456789012:key/b6d1911e-450a-4a52-b810-platform-signing \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/payment-service:v2.1.0

# 2. Configure Kyverno to verify using KMS key ARN over AWS VPC Endpoint

Scenario 2: External Secrets Operator (ESO) AWS API Throttling Storm

The Symptom

External Secrets Operator fails to synchronize secrets. The controller logs report:

ThrottlingException: Rate exceeded: 
AWS Secrets Manager API request limit exceeded (TPS limit reached).

Kubernetes pods requiring fresh credentials fail to launch or read outdated values.

Under-the-Hood Root Cause

Developers configured 500 ExternalSecret manifests across 30 namespaces with an aggressive refreshInterval: 10s. AWS Secrets Manager enforces a regional API call limit of 5,000 TPS for GetSecretValue. With 500 secrets being queried every 10 seconds, background polling consumed a massive percentage of the accountโ€™s quota. When an automated deployment triggered 100 new pods simultaneously, the combined API volume exceeded the quota, triggering hard rate-limiting.

CLI Triage Commands

# 1. Inspect failed ExternalSecret statuses across all namespaces
kubectl get externalsecrets -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,STORE:.spec.secretStoreRef.name,READY:.status.conditions[?(@.type=="Ready")].status,MESSAGE:.status.conditions[?(@.type=="Ready")].message | grep -i "rate"

# 2. Check ESO controller logs
kubectl logs -n external-secrets -l app.kubernetes.io/name=external-secrets --tail=100

Remediation & Architectural Fix

  • The Standard: Change the default refreshInterval across all ExternalSecret manifests from seconds to hours:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: payment-db-credentials
spec:
  refreshInterval: "12h" # Poll once every 12 hours instead of every 10s!
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: payment-db-secret
  • Event-Driven Refresh: Instead of aggressive polling, trigger on-demand syncs via AWS EventBridge webhooks whenever AWS Secrets Manager executes a scheduled rotation.

Scenario 3: Golden AMI /etc/machine-id Duplication Disaster

The Symptom

When 200 EC2 worker nodes boot from a newly baked Golden AMI, half of the instances cannot connect to the network, and the corporate DHCP/IPAM server logs report:

DHCPACK: duplicate IP assignment detected for client-id: 7f8a92b1...

Multiple EC2 instances receive identical IP addresses or overwrite each otherโ€™s registration records in internal DNS.

Under-the-Hood Root Cause

During the Packer build process, systemd generated a unique /etc/machine-id file when the temporary builder VM booted. The Packer provisioning script failed to truncate or delete /etc/machine-id before taking the EBS snapshot. As a result, all 200 instances booted with the exact same machine-id, which Linux DHCP clients use as the unique hardware client identifier!

Remediation & Sysprep Best Practice

Always include a cleanup script at the end of the Packer provisioning pipeline:

# Sysprep script: /opt/platform/scripts/sysprep-cleanup.sh
# 1. Truncate machine-id (leaves file empty so systemd re-generates on first boot)
sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id

# 2. Remove persistent SSH host keys
sudo rm -f /etc/ssh/ssh_host_*

# 3. Clean cloud-init caches
sudo cloud-init clean --all --logs

Scenario 4: ASG Instance Refresh Deadlock on Lifecycle Hook Timeout

The Symptom

An automated fleet patching pipeline triggers StartInstanceRefresh on an AWS Auto Scaling Group. The refresh immediately halts at 0% progress:

InstanceRefreshStatus: Failed (Failed to replace instances: 
Instance i-0123456789abcdef0 failed to enter InService state before heartbeat timeout expired).

Under-the-Hood Root Cause

The ASG uses an autoscaling:EC2_INSTANCE_LAUNCHING lifecycle hook to run configuration scripts (e.g. downloading certificates, joining Kubernetes cluster). The script failed or hung waiting for an internal repository, and did NOT issue the completion signal:

aws autoscaling complete-lifecycle-action --lifecycle-action-result CONTINUE ...

When the 1-hour heartbeat timeout expired, AWS terminated the instance and aborted the entire fleet refresh!

CLI Triage Commands

# 1. Check active lifecycle actions on the failing instance
aws autoscaling describe-lifecycle-actions \
  --auto-scaling-group-name prod-worker-asg

# 2. Inspect instance system console logs to see where user-data hung
aws ec2 get-console-output --instance-id i-0123456789abcdef0

Remediation & Architectural Standard

  • Fail-Safe Shell Scripts: Always wrap user-data lifecycle scripts with error trapping and timeouts:
#!/usr/bin/env bash
set -e

cleanup_on_failure() {
    # Send ABANDON so ASG fails fast rather than hanging for 1 hour
    aws autoscaling complete-lifecycle-action \
      --lifecycle-action-result ABANDON \
      --lifecycle-hook-name node-init-hook \
      --auto-scaling-group-name "$ASG_NAME" \
      --instance-id "$INSTANCE_ID"
}
trap cleanup_on_failure ERR