Catching Up: Labs 2.5 - 4.3, and Passing the CGE-AUD Auditor Exam

Summary

My last post left off at Lab 2.4. Since then, I've completed: Labs 2.5, 3.3, 3.4, and 4.3, plus the GRC Auditor exam. This is a quick summary with the main takeaway per lab.

Code for these labs is in my CGE-P Capstone repo.

The GRC Auditor exam was also launched in the meantime, recommended as a prerequisite to the CGE-P exam. My engineering background helped me knock it out in two days. Grateful for quick wins!

Lab 2.5: IaC as Compliance Evidence (AWS)

This lab turns a Terraform plan into signed, retained evidence rather than just a deployment artifact. The module, evidence-vault, is an S3 bucket with Object Lock in GOVERNANCE mode. A capture script (scripts/capture-evidence.sh) runs against a target workspace (in my case, Lab 2.3's compliant-s3) and writes a receipt into the vault.

StepWhat it proves
Capture evidence against compliant-s3The plan output itself becomes the evidence artifact
Verify RetainUntilDate under GOVERNANCE modeRetention is enforced, not just configured
Attempt delete-object on the locked objectConfirms the lock actually blocks deletion with AccessDenied as expected

Labs 3.3 & 3.4: Writing Compliance Policies in Rego, GCP to AWS

Lab 3.3 writes the policy library. Lab 3.4 proves it doesn't have to be tied to one cloud provider.

Lab 3.3: Writing Compliance Policies in Rego (GCP)

Three Rego policies, three NIST controls, checked against a GCP Terraform plan:

ControlFileEnforces
SC-28sc28_encryption.regoEvery google_storage_bucket has a populated encryption { default_kms_key_name } block
AC-3ac3_no_public.regoBuckets have uniform_bucket_level_access = true and public_access_prevention = "enforced"; firewalls don't expose 22 or 3389 to 0.0.0.0/0
CM-6cm6_required_tags.regoEvery taggable resource carries the four required labels: project, environment, managed_by, compliance_scope

Lab 3.4: Integrating PaC with Terraform via Conftest (AWS)

This was my first exposure to Conftest, Rego, and Open Policy Agent.

This lab does two things: runs the Lab 3.3 GCP policies against an AWS plan (they pass with zero coverage since there were no GCP resource types to check), and adds AWS-typed variants of the same three controls into the library. The point is that a control ID is portable across cloud providers while a Rego rule hardcoded to google_storage_bucket is not.

ControlGCP file (3.3)AWS file (3.4)
SC-28sc28_encryption.regosc28_encryption_aws.rego
AC-3ac3_no_public.regoac3_no_public_aws.rego
CM-6cm6_required_tags.regocm6_required_tags_aws.rego

Lab 4.3: Building a GRC Evidence Pipeline (AWS + GitHub Actions)

Lab 4.3 wires the Lab 3.4 Conftest gate into GitHub Actions. Every PR now runs terraform plan, Conftest, and tfsec, and uploads a named evidence artifact regardless of pass or fail. The workflow file itself is the CM-3/CM-6/CA-2/RA-5/AU-9 audit evidence.

Setting up IAM Identity Center

This was my first time setting up IAM Identity Center (SSO) on my personal AWS account. Up to this point, I've been working on the lab in CloudShell to avoid saving keys on my laptop. This has caused some headaches because AWS CloudShell only allows for 1 GB of persistent storage per AWS Region. I kept getting "No space left on device" errors on the AWS labs because every terraform init re-downloads its own full copy. Claude helped me find the Terraform plugin-cache and delete old files to make room for each new AWS lab, but it felt like I was just putting off the inevitable of setting up IAM Identity Center.

With OIDC, my sessions are short-lived and expire, which means occasionally re-authenticating, but nothing durable to leak and no forgetting about keys on my computer.

The guide's reference oidc/main.tf trusts the role to repo:OWNER/REPO:*, so basically any branch, any event. In my repo, I tightened up both the subject claim and the permissions granted.

Since my repo has no remote backend configured, my state stays local. There's no diff for testing drift against real infrastructure. The plan always shows a full "create," not a diff against what's actually live.

With identity and OIDC sorted, here's the gate itself in action:

The two-PR demonstration

  • Green: PR #6, merged. All checks passing.

  • Red: branch lab-4-3-red, opened, not merged. Conftest failed with:

    [SC-28] aws_s3_bucket.primary: aws_s3_bucket has no matching aws_s3_bucket_server_side_encryption_configuration. Remediation: add one referencing this bucket.

That message contains the control ID, resource, and remediation all in one line. The whole point of the gate is that this failure surfaces on the PR, before merge, instead of turning up as a finding in a later audit.

Takeaway

Every gotcha I came across in these labs traced back to two things: my AWS CloudShell setup and that the guides are written for a flat, single-purpose repo. My repo has real structure, which means every path, working directory, and relative reference in the lab guides needed debugging (e.g. TF_WORKING_DIR pointed three levels deep so every ../ in the guide's Conftest/tfsec steps needed to become ../../../).