Shift Left: Integrating OPA Policies into GitLab CI Pipelines

Ishmael Chibvuri, CISM
Cybersecurity Strategist
Compliance teams hate the phrase "shift left" because it usually means "make engineers do my job." But there's a specific, narrow definition of shift-left that everybody wins on: codify the security policy once, run it in CI, run it again at runtime, and stop arguing about it in PR reviews.
That's what Open Policy Agent (OPA) is for.
The OPA contract
OPA evaluates a policy (written in Rego) against an input (JSON) and returns a decision (JSON). That's it. The genius is that the same policy file can be used in three different places:
- Pre-commit —
conftestruns OPA against your Terraform plan locally. - In CI — your GitLab pipeline blocks merges that violate policy.
- At runtime — OPA running as a sidecar gates API Gateway / Kubernetes admission.
One policy, three enforcement points, zero drift.
A real GitLab job
opa_terraform_check:
stage: validate
image: openpolicyagent/conftest:latest
script:
- terraform plan -out=plan.tfplan
- terraform show -json plan.tfplan > plan.json
- conftest test --policy policy/ plan.json
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"And the policy that blocks a public S3 bucket:
package terraform.s3
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket_public_access_block"
resource.change.after.block_public_acls == false
msg := sprintf("S3 bucket '%s' must block public ACLs", [resource.address])
}That's it. Merge requests that try to disable block_public_acls fail the pipeline with a human-readable error. No security review needed. No exception process. The policy is the review.
What this doesn't solve
OPA is not a SIEM. It doesn't detect anomalies, it doesn't correlate events, it doesn't tell you about ongoing attacks. It only tells you whether a configuration matches a rule. The trick is knowing what to make a rule and what to leave to detection.
Most teams over-rotate on prevention and under-invest in detection. Start with the rules where the cost of a violation is high and the rate of false positives is low — public S3 buckets, exposed RDS instances, unencrypted volumes. Save your detection budget for the things that can't be expressed as a rule.
Discussion
Continue the conversation
Share your take, ask a follow-up question, or push back on the analysis — head over to LinkedIn where the discussion lives.