mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-25 01:35:18 -06:00
Revert "docs: Update terraform examples" (#7428)
This reverts commit d506db305c.
This was committed to main in error and should be merged via PR instead.
Signed-off-by: Charlie Egan <charlie@styra.com>
This commit is contained in:
+58
-75
@@ -12,7 +12,8 @@ Terraform is about to make before it makes them. Such tests help in different wa
|
||||
* tests can auto-approve run-of-the-mill infrastructure changes and reduce the burden of peer-review
|
||||
* tests can help catch problems that arise when applying Terraform to production after applying it to staging
|
||||
|
||||
Terraform is a popular integration case for OPA and there are already a number of popular tools for
|
||||
|
||||
Terraform is a popular integration case for OPA and there are already a number of popular tools for
|
||||
running policy on HCL and plan JSONs.
|
||||
{{<
|
||||
ecosystem_feature_link
|
||||
@@ -37,9 +38,8 @@ This tutorial requires
|
||||
* [Terraform 0.12.6](https://releases.hashicorp.com/terraform/0.12.6/)
|
||||
* [OPA](https://github.com/open-policy-agent/opa/releases)
|
||||
|
||||
(This tutorial _should_ also work with the
|
||||
[latest version of Terraform](https://www.terraform.io/downloads.html), but
|
||||
it is untested. Contributions welcome!)
|
||||
(This tutorial *should* also work with the [latest version of Terraform](https://www.terraform.io/downloads.html), but
|
||||
it is untested. Contributions welcome!)
|
||||
|
||||
# Getting Started
|
||||
|
||||
@@ -48,8 +48,8 @@ it is untested. Contributions welcome!)
|
||||
### 1. Create and save a Terraform plan
|
||||
|
||||
Create a [Terraform](https://www.terraform.io/docs/index.html) file that includes an
|
||||
auto-scaling group and a server on AWS.
|
||||
(You will need to modify the `shared_credentials_file` to point to your AWS credentials.)
|
||||
auto-scaling group and a server on AWS. (You will need to modify the `shared_credentials_file`
|
||||
to point to your AWS credentials.)
|
||||
|
||||
```shell
|
||||
cat >main.tf <<EOF
|
||||
@@ -97,7 +97,7 @@ terraform show -json tfplan.binary > tfplan.json
|
||||
|
||||
Here is the expected contents of `tfplan.json`.
|
||||
|
||||
```json
|
||||
```live:terraform:input
|
||||
{
|
||||
"format_version": "0.1",
|
||||
"terraform_version": "0.12.6",
|
||||
@@ -467,7 +467,7 @@ practice you would vary the threshold depending on the user.)
|
||||
|
||||
**policy/terraform.rego**:
|
||||
|
||||
```rego
|
||||
```live:terraform:module:openable
|
||||
package terraform.analysis
|
||||
|
||||
import input as tfplan
|
||||
@@ -502,21 +502,21 @@ authz if {
|
||||
|
||||
# Compute the score for a Terraform plan as the weighted sum of deletions, creations, modifications
|
||||
score := s if {
|
||||
all_resources := [x |
|
||||
some resource_type, crud in weights
|
||||
|
||||
del := crud.delete * num_deletes[resource_type]
|
||||
new := crud.create * num_creates[resource_type]
|
||||
mod := crud.modify * num_modifies[resource_type]
|
||||
all := [x |
|
||||
some resource_type
|
||||
crud := weights[resource_type]
|
||||
del := crud["delete"] * num_deletes[resource_type]
|
||||
new := crud["create"] * num_creates[resource_type]
|
||||
mod := crud["modify"] * num_modifies[resource_type]
|
||||
x := (del + new) + mod
|
||||
]
|
||||
s := sum(all_resources)
|
||||
s := sum(all)
|
||||
}
|
||||
|
||||
# Whether there is any change to IAM
|
||||
touches_iam if {
|
||||
all_resources := resources.aws_iam
|
||||
count(all_resources) > 0
|
||||
all := resources.aws_iam
|
||||
count(all) > 0
|
||||
}
|
||||
|
||||
####################
|
||||
@@ -524,50 +524,39 @@ touches_iam if {
|
||||
####################
|
||||
|
||||
# list of all resources of a given type
|
||||
resources[resource_type] := all_resources if {
|
||||
some resource_type, _ in resource_types
|
||||
|
||||
all_resources := [name |
|
||||
some name in tfplan.resource_changes
|
||||
resources[resource_type] := all if {
|
||||
some resource_type
|
||||
resource_types[resource_type]
|
||||
all := [name |
|
||||
name := tfplan.resource_changes[_]
|
||||
name.type == resource_type
|
||||
]
|
||||
}
|
||||
|
||||
# number of creations of resources of a given type
|
||||
num_creates[resource_type] := num if {
|
||||
some resource_type, _ in resource_types
|
||||
|
||||
all_resources := resources[resource_type]
|
||||
creates := [res |
|
||||
some res in all_resources
|
||||
"create" in res.change.actions
|
||||
]
|
||||
some resource_type
|
||||
resource_types[resource_type]
|
||||
all := resources[resource_type]
|
||||
creates := [res | res := all[_]; res.change.actions[_] == "create"]
|
||||
num := count(creates)
|
||||
}
|
||||
|
||||
# number of deletions of resources of a given type
|
||||
num_deletes[resource_type] := num if {
|
||||
some resource_type, _ in resource_types
|
||||
|
||||
all_resources := resources[resource_type]
|
||||
|
||||
deletions := [res |
|
||||
some res in all_resources
|
||||
"delete" in res.change.actions
|
||||
]
|
||||
some resource_type
|
||||
resource_types[resource_type]
|
||||
all := resources[resource_type]
|
||||
deletions := [res | res := all[_]; res.change.actions[_] == "delete"]
|
||||
num := count(deletions)
|
||||
}
|
||||
|
||||
# number of modifications to resources of a given type
|
||||
num_modifies[resource_type] := num if {
|
||||
some resource_type, _ in resource_types
|
||||
|
||||
all_resources := resources[resource_type]
|
||||
|
||||
modifies := [res |
|
||||
some res in all_resources
|
||||
"update" in res.change.actions
|
||||
]
|
||||
some resource_type
|
||||
resource_types[resource_type]
|
||||
all := resources[resource_type]
|
||||
modifies := [res | res := all[_]; res.change.actions[_] == "update"]
|
||||
num := count(modifies)
|
||||
}
|
||||
```
|
||||
@@ -580,17 +569,12 @@ ask it to evaluate `terraform/analysis/authz`.
|
||||
```shell
|
||||
opa exec --decision terraform/analysis/authz --bundle policy/ tfplan.json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"path": "tfplan.json",
|
||||
"result": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```live:terraform/authz:query:hidden
|
||||
data.terraform.analysis.authz
|
||||
```
|
||||
```live:terraform/authz:output
|
||||
```
|
||||
|
||||
|
||||
If you're curious, you can ask for the score that the policy used to make the authorization decision.
|
||||
In our example, it is 11 (10 for the creation of the auto-scaling group and 1 for the creation of the server).
|
||||
@@ -599,21 +583,16 @@ In our example, it is 11 (10 for the creation of the auto-scaling group and 1 fo
|
||||
opa exec --decision terraform/analysis/score --bundle policy/ tfplan.json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"path": "tfplan.json",
|
||||
"result": 11
|
||||
}
|
||||
]
|
||||
}
|
||||
```live:terraform/score:query:hidden
|
||||
data.terraform.analysis.score
|
||||
```
|
||||
```live:terraform/score:output
|
||||
```
|
||||
|
||||
If as suggested in the previous step, you want to modify your policy to make an authorization decision
|
||||
based on both the user and the Terraform plan, the input you would give to OPA would take the form
|
||||
`{"user": <user>, "plan": <plan>}`, and your policy would reference the user with `input.user` and
|
||||
the plan with `input.plan`. You could even go so far as to provide the Terraform state file and the AWS
|
||||
the plan with `input.plan`. You could even go so far as to provide the Terraform state file and the AWS
|
||||
EC2 data to OPA and write policy using all of that context.
|
||||
|
||||
### 5. Create a Large Terraform plan and Evaluate it
|
||||
@@ -718,7 +697,7 @@ You learned a number of things about Terraform Testing with OPA:
|
||||
* OPA gives you fine-grained policy control over Terraform plans.
|
||||
* You can use data other than the plan itself (e.g. the user) when writing authorization policies.
|
||||
|
||||
Keep in mind that it's up to you to decide how to use OPA's Terraform tests and authorization decision. Here are some ideas.
|
||||
Keep in mind that it's up to you to decide how to use OPA's Terraform tests and authorization decision. Here are some ideas.
|
||||
|
||||
* Add it as part of your Terraform wrapper to implement unit tests on Terraform plans
|
||||
* Use it to automatically approve run-of-the-mill Terraform changes to reduce the burden of peer-review
|
||||
@@ -733,9 +712,7 @@ If you'd like to explore an additional example that uses terraform modules pleas
|
||||
### 1. Create and save Terraform module plan
|
||||
|
||||
Create a new Terraform file that includes a
|
||||
security group and security group from a module.
|
||||
(This example uses the module from
|
||||
[terraform-aws-modules](https://github.com/terraform-aws-modules/terraform-aws-security-group))
|
||||
security group and security group from a module. (This example uses the module from https://github.com/terraform-aws-modules/terraform-aws-security-group)
|
||||
|
||||
```shell
|
||||
cat >main.tf <<EOF
|
||||
@@ -816,13 +793,12 @@ The policy uses the walk keyword to explore the json structure, and uses conditi
|
||||
package terraform.module
|
||||
|
||||
deny contains msg if {
|
||||
some r
|
||||
desc := resources[r].values.description
|
||||
contains(desc, "HTTP")
|
||||
msg := sprintf("No security groups should be using HTTP. Resource in violation: %v", [r.address])
|
||||
}
|
||||
|
||||
resources contains r if {
|
||||
resources := {r |
|
||||
some path, value
|
||||
|
||||
# Walk over the JSON tree and check if the node we are
|
||||
@@ -831,11 +807,14 @@ resources contains r if {
|
||||
walk(input.planned_values, [path, value])
|
||||
|
||||
# Look for resources in the current value based on path
|
||||
some r in module_resources(path, value)
|
||||
rs := module_resources(path, value)
|
||||
|
||||
# Aggregate them into `resources`
|
||||
r := rs[_]
|
||||
}
|
||||
|
||||
# Variant to match root_module resources
|
||||
module_resources(path, value) := value if {
|
||||
module_resources(path, value) := rs if {
|
||||
# Expect something like:
|
||||
#
|
||||
# {
|
||||
@@ -850,10 +829,11 @@ module_resources(path, value) := value if {
|
||||
|
||||
reverse_index(path, 1) == "resources"
|
||||
reverse_index(path, 2) == "root_module"
|
||||
rs := value
|
||||
}
|
||||
|
||||
# Variant to match child_modules resources
|
||||
module_resources(path, value) := value if {
|
||||
module_resources(path, value) := rs if {
|
||||
# Expect something like:
|
||||
#
|
||||
# {
|
||||
@@ -875,9 +855,12 @@ module_resources(path, value) := value if {
|
||||
|
||||
reverse_index(path, 1) == "resources"
|
||||
reverse_index(path, 3) == "child_modules"
|
||||
rs := value
|
||||
}
|
||||
|
||||
reverse_index(path, idx) := path[count(path) - idx]
|
||||
reverse_index(path, idx) := value if {
|
||||
value := path[count(path) - idx]
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Evaluate the OPA policy on the Terraform module plan
|
||||
|
||||
Reference in New Issue
Block a user