diff --git a/README.md b/README.md index da366ce..cb8eb20 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,9 @@ - [AWS Policy as code OPA](https://github.com/ik-infrastructure-testing/aws-infra-policy-as-code-with-terraform-fork) - [Teraform rego](https://developer.hashicorp.com/terraform/cloud-docs/policy-enforcement/define-policies/opa) + +- [Blog with terraform](https://www.scalr.com/blog/opa-series-part-1-open-policy-agent-and-terraform) + --- ![](https://img.shields.io/github/commit-activity/m/ik-learning/opa-learn) diff --git a/playground/ex28/input.json b/playground/ex28/input.json new file mode 100644 index 0000000..033067f --- /dev/null +++ b/playground/ex28/input.json @@ -0,0 +1,13 @@ +{ + "attributes": { + "request": { + "http": { + "method": "GET", + "path": "/people/", + "headers": { + "authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiZ3Vlc3QiLCJzdWIiOiJZV3hwWTJVPSIsIm5iZiI6MTUxNDg1MTEzOSwiZXhwIjoxNjQxMDgxNTM5fQ.K5DnnbbIOspRbpCr2IKXE9cPVatGOCBrBQobQmBmaeU" + } + } + } + } +} diff --git a/playground/ex28/policy.rego b/playground/ex28/policy.rego new file mode 100644 index 0000000..ef539fc --- /dev/null +++ b/playground/ex28/policy.rego @@ -0,0 +1,43 @@ +package envoy.authz + +# https://www.openpolicyagent.org/docs/latest/envoy-primer/ + +import input.attributes.request.http + +default allow := false + +allow if { + is_token_valid + action_allowed +} + +is_token_valid if { + token.valid + now := time.now_ns() / 1000000000 + token.payload.nbf <= now + now < token.payload.exp +} + +action_allowed if { + http.method == "GET" + token.payload.role == "guest" + glob.match("/people/*", ["/"], http.path) +} + +action_allowed if { + http.method == "GET" + token.payload.role == "admin" + glob.match("/people/*", ["/"], http.path) +} + +action_allowed if { + http.method == "POST" + token.payload.role == "admin" + glob.match("/people", ["/"], http.path) + lower(input.parsed_body.firstname) != base64url.decode(token.payload.sub) +} + +token := {"valid": valid, "payload": payload} if { + [_, encoded] := split(http.headers.authorization, " ") + [valid, _, payload] := io.jwt.decode_verify(encoded, {"secret": "secret"}) +} diff --git a/playground/ex29/policy.rego b/playground/ex29/policy.rego new file mode 100644 index 0000000..907324c --- /dev/null +++ b/playground/ex29/policy.rego @@ -0,0 +1,71 @@ +package terraform.module + +deny contains msg if { + desc := resources[r].values.description + contains(desc, "HTTP") + msg := sprintf("No security groups should be using HTTP. Resource in violation: %v", [r.address]) +} + +resources := {r | + some path, value + + # Walk over the JSON tree and check if the node we are + # currently on is a module (either root or child) resources + # value. + walk(input.planned_values, [path, value]) + + # Look for resources in the current value based on path + rs := module_resources(path, value) + + # Aggregate them into `resources` + r := rs[_] +} + +# Variant to match root_module resources +module_resources(path, value) := rs if { + # Expect something like: + # + # { + # "root_module": { + # "resources": [...], + # ... + # } + # ... + # } + # + # Where the path is [..., "root_module", "resources"] + + reverse_index(path, 1) == "resources" + reverse_index(path, 2) == "root_module" + rs := value +} + +# Variant to match child_modules resources +module_resources(path, value) := rs if { + # Expect something like: + # + # { + # ... + # "child_modules": [ + # { + # "resources": [...], + # ... + # }, + # ... + # ] + # ... + # } + # + # Where the path is [..., "child_modules", 0, "resources"] + # Note that there will always be an index int between `child_modules` + # and `resources`. We know that walk will only visit each one once, + # so we shouldn't need to keep track of what the index is. + + reverse_index(path, 1) == "resources" + reverse_index(path, 3) == "child_modules" + rs := value +} + +reverse_index(path, idx) := value if { + value := path[count(path) - idx] +}