DEV Community

Ayobami Adejumo
Ayobami Adejumo

Posted on

I turned 23 Vanta RED tests GREEN in 14 days. Here is the exact command for each one.

The problem Vanta does not solve

Vanta is excellent at telling you what is wrong. The dashboard is beautiful. The RED tests are clear. The remediation instructions are detailed.

But Vanta does not fix anything. Every RED test represents a gap between the compliance requirement and your current infrastructure. Closing that gap requires someone to write a Kubernetes network policy, modify an IAM role, configure a KMS key, or run an AWS CLI command. Vanta generates the ticket. The engineer has to do the work.

Compliance work is not product work. It does not ship features. It does not close customers. In a small engineering team — 10 to 30 people — compliance always loses to the sprint. The Vanta dashboard sits open. The RED tests sit there. The audit date approaches. The engineering team enters crunch mode trying to close 23 controls in a month when they should have been closing 2 controls per month for the past year.

I have been the engineer in that crunch mode four times. The last time, I turned 23 Vanta RED tests GREEN in 14 days. Here is the exact command for each one.


Control group 1 — IAM and access management (7 controls)

Control 1.1 — IAM Access Keys Rotated

Requirement: No IAM access key older than 90 days.

# Find violating keys
aws iam list-users --query 'Users[].UserName' --output text | tr '\t' '\n' | while read user; do
  aws iam list-access-keys --user-name $user --query 'AccessKeyMetadata[?CreateDate<=`2025-01-04T00:00:00Z`].{User:UserName,KeyId:AccessKeyId}' --output table
done

# Rotate a key
aws iam create-access-key --user-name username
aws iam delete-access-key --user-name username --access-key-id AKIAOLDKEY123
Enter fullscreen mode Exit fullscreen mode

Control 1.2 — MFA Enforcement for All IAM Users

# Find users without MFA
aws iam list-users --query 'Users[].UserName' --output text | tr '\t' '\n' | while read user; do
  MFA=$(aws iam list-mfa-devices --user-name $user --query 'MFADevices[].SerialNumber' --output text)
  [ -z "$MFA" ] && echo "$user has NO MFA"
done
Enter fullscreen mode Exit fullscreen mode

Control 1.3 — IRSA for EKS Workloads (most complex IAM control)

IRSA binds an IAM role directly to a Kubernetes service account. A compromise of one pod does not expose another pod's permissions.

# Check if OIDC provider exists
aws eks describe-cluster --name your-cluster --query 'cluster.identity.oidc.issuer' --output text

# Enable OIDC
eksctl utils associate-iam-oidc-provider --cluster your-cluster --approve

# Create IAM role for a service account
eksctl create iamserviceaccount \
  --name my-service-account \
  --namespace default \
  --cluster your-cluster \
  --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
  --approve
Enter fullscreen mode Exit fullscreen mode

Control group 2 — Network security and Kubernetes (6 controls)

Control 2.1 — Kubernetes Network Policy Enforced (Cilium)

Replace the default CNI with Cilium to enforce network policies:

# Remove aws-node
kubectl -n kube-system delete daemonset aws-node

# Install Cilium with EKS-specific values
helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium --namespace kube-system \
  --set policyEnforcementMode=default \
  --set encryption.enabled=true --set encryption.type=wireguard
Enter fullscreen mode Exit fullscreen mode

Control 2.2 — Default-Deny Network Policy

# default-deny.yaml
apiVersion: "cilium.io/v2"
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: "default-deny-all-traffic"
spec:
  ingress:
  - {}
  egress:
  - {}
Enter fullscreen mode Exit fullscreen mode
kubectl apply -f default-deny.yaml
Enter fullscreen mode Exit fullscreen mode

Control 2.3 — HTTP Security Headers Present

The nginx configuration (5 lines, 10 minutes):

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Enter fullscreen mode Exit fullscreen mode
# Verify
curl -I https://yourapp.com | grep -E "(Strict-Transport-Security|X-Content-Type-Options)"
Enter fullscreen mode Exit fullscreen mode

Control group 3 — Encryption at rest (4 controls)

Control 3.1 — EKS Secrets Encrypted with CMK

# Create customer-managed KMS key
aws kms create-key --description "EKS secrets encryption"
aws kms create-alias --alias-name alias/eks-secrets-prod --target-key-id [KEY_ID]

# Enable envelope encryption on existing cluster (non-disruptive)
eksctl utils enable-secrets-encryption \
  --cluster your-cluster \
  --key-arn arn:aws:kms:us-east-1:123456789012:alias/eks-secrets-prod
Enter fullscreen mode Exit fullscreen mode

Control 3.2 — RDS Instance Encrypted with CMK

For existing unencrypted RDS instances (snapshot → restore → rename):

# Create snapshot
aws rds create-db-snapshot --db-instance-identifier your-db --db-snapshot-identifier pre-encryption-snapshot

# Copy with encryption
aws rds copy-db-snapshot --source-db-snapshot-identifier pre-encryption-snapshot \
  --target-db-snapshot-identifier encrypted-snapshot --kms-key-id alias/rds-encryption

# Restore encrypted instance
aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier your-db-encrypted --db-snapshot-identifier encrypted-snapshot
Enter fullscreen mode Exit fullscreen mode

Control 3.3 — S3 Bucket Encryption with CMK

aws s3api put-bucket-encryption \
  --bucket your-bucket \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "arn:aws:kms:us-east-1:123456789012:alias/s3-encryption"
      }
    }]
  }'
Enter fullscreen mode Exit fullscreen mode

Control group 4 — Monitoring and logging (5 controls)

Control 4.1 — GuardDuty Enabled

aws guardduty create-detector --region us-east-1 --enable --finding-publishing-frequency FIFTEEN_MINUTES
Enter fullscreen mode Exit fullscreen mode

Control 4.2 — GuardDuty EKS Runtime Monitoring

# Enable protection plan
DETECTOR_ID=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text)
aws guardduty update-detector --detector-id $DETECTOR_ID --features '[{"Name": "EKS_RUNTIME_MONITORING", "Status": "ENABLED"}]'

# Install agent as DaemonSet
helm repo add aws-guardduty https://aws.github.io/aws-guardduty-agent-chart
helm install guardduty-agent aws-guardduty/guardduty-agent \
  --namespace guardduty-agent --create-namespace \
  --set accountID=123456789012 --set region=us-east-1
Enter fullscreen mode Exit fullscreen mode

Control 4.3 — VPC Flow Logs Enabled

aws ec2 create-flow-logs \
  --resource-type VPC \
  --resource-ids vpc-xxxxx \
  --traffic-type ALL \
  --log-destination-type s3 \
  --log-destination arn:aws:s3:::your-flow-logs-bucket
Enter fullscreen mode Exit fullscreen mode

The 14-day execution sequence

The order matters. You cannot close network policies before IAM roles are configured. You cannot verify monitoring against a cluster that is still RED on network policies.

Week 1 — Foundational controls

  • Day 1: IAM (7 controls) — MFA, key rotation, IRSA, root account lockdown
  • Day 2: CloudTrail + GuardDuty (4 controls)
  • Day 3: VPC Flow Logs + Hubble observability

Week 2 — Infrastructure hardening

  • Day 4: Cilium installation (prerequisite for network policies)
  • Day 5: Network policies — default-deny + allow policies
  • Day 6: Security headers + TLS 1.2+ enforcement
  • Day 7: Encryption at rest — EKS secrets, RDS, S3, EBS
  • Days 8-14: Verification, documentation, Vanta re-scan

The verification command for each control:

# Generate final evidence package
aws iam get-credential-report --query 'Content' --output text | base64 -d > iam_credential_report.csv
aws guardduty list-detectors > guardduty.json
kubectl get ciliumclusterwidenetworkpolicies -A > network_policies.txt
curl -I https://yourapplication.com > security_headers.txt
Enter fullscreen mode Exit fullscreen mode

The honest statement about what you cannot do

Turning 23 Vanta tests GREEN is the technical implementation side of SOC 2. It is not the whole SOC 2.

These 14 days do not replace the SOC 2 audit. You still need a licensed auditor. They do not produce the policies and procedures that Type II requires — Information Security Policy, Access Control Policy, Incident Response Plan. They do not engage the auditor. Budget $15,000–$30,000 for a SOC 2 Type I audit.

What these 14 days do: they close the engineering gap. Before this sprint, the answer to "show me your network policy enforcement" was "we will implement it before the audit." After this sprint, the answer is a working Cilium configuration with Hubble observability and default-deny policies. They turn Vanta from a dashboard of shame into a dashboard of verification.


The one-liner for your board: "We closed 23 Vanta RED tests in 14 days. The technical infrastructure for SOC 2 is now complete. The remaining work is policies and auditor engagement. Budget $25,000 for the audit. Timeline 60 days to Type I."

If your Vanta dashboard has RED tests that have been open for more than 90 days, book a 20-minute call to audit your platform. Link in bio.

Top comments (0)