Skip to content

Commit 49f4698

Browse files
authored
Merge pull request #8 from pingidentity/PDI-2053-example-opa-policies
Add policy example
2 parents ecd2710 + 6f4de79 commit 49f4698

File tree

8 files changed

+187
-8
lines changed

8 files changed

+187
-8
lines changed

.gitignore

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# Miscellaneous local files
12
terraform.tfvars
23
*.bak
34
*.local
@@ -8,6 +9,7 @@ generated
89
imports.tf
910
generated-platform.tf
1011
global.js
12+
**/.DS_Store
1113

1214
# Local .terraform directories
1315
**/.terraform/*
@@ -22,13 +24,18 @@ global.js
2224
crash.log
2325
crash.*.log
2426

25-
# Exclude all .tfvars files, which are likely to contain sentitive data, such as
27+
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
2628
# password, private keys, and other secrets. These should not be part of version
2729
# control as they are data points which are potentially sensitive and subject
2830
# to change depending on the environment.
2931
#
3032
*.tfvars
3133

34+
# Ignore plan files and the json plan output
35+
# Used by OPA policies
36+
**/plan.tfplan
37+
**/plan.json
38+
3239
# Ignore override files as they are usually used to override resources locally and so
3340
# are not checked in
3441
override.tf

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ To be successful in recreating the use cases supported by this pipeline, there a
2929

3030
- Completion of all pre-requisites and configuration steps leading to [Feature Development](https://github.com/pingidentity/pipeline-example-platform?tab=readme-ov-file#feature-development) from the example-pipeline-platform repository
3131
- [Docker](https://docs.docker.com/engine/install/) - used to deploy the UI for a sample interface
32-
- [tflint](https://github.com/terraform-linters/tflint) - for Terraform linting
33-
- [dvlint](https://github.com/pingidentity/dvlint) - for Davinci flow linting
34-
- [trivy](https://github.com/aquasecurity/trivy) - for security scanning
32+
- [terraform](https://developer.hashicorp.com/terraform/install) - HashiCorp Terraform (version 1.9.8 was used in this guide)
33+
- [opa](https://www.openpolicyagent.org/docs/latest/#running-opa) - Open Policy Agent (version 0.70.0 was used in this guide)
34+
- [tflint](https://github.com/terraform-linters/tflint) - for Terraform linting (version 0.53.0 was used in this guide)
35+
- [dvlint](https://github.com/pingidentity/dvlint) - for Davinci flow linting (version 1.0.3 was used in this guide)
36+
- [trivy](https://github.com/aquasecurity/trivy) - for security scanning (version 0.56.2 was used in this guide)
3537

3638
> [!TIP]
3739
> The last three tools are used by the pipeline in Github, and the pipeline will fail if these tests and configuration checks do not pass. Installing these tools locally and running `make devcheck` before committing changes should ensure that the pipeline will pass when changes are pushed.
@@ -237,7 +239,7 @@ Terraform will perform the following actions:
237239
~ flow_export_json = (sensitive value)
238240
~ flow_json = (sensitive value)
239241
id = "a6d551f1d7aa2612f2bf6c371b0026e1"
240-
name = "PingOne DaVinci Registration Example"
242+
name = "AppTeam PingOne DaVinci Registration Example"
241243
# (4 unchanged attributes hidden)
242244
243245
# (3 unchanged blocks hidden)

opa/policies/davinci_flow.rego

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package terraform.davinci
2+
3+
import data.terraform.flow_checks as flow_checks
4+
import rego.v1
5+
6+
# Retrieve all relevant flows with the "create" action
7+
relevant_flows := flow_checks.get_relevant_flows("create")
8+
9+
# Check if `deploy` is true for all relevant flows
10+
deploy_true if {
11+
print("Checking if deploy is true for all relevant flows:", relevant_flows)
12+
flow_checks.deploy_is_true_for_all(relevant_flows)
13+
}
14+
15+
# Check if all flow names start with "AppTeam"
16+
name_starts_with_AppTeam if {
17+
print("Checking if all relevant flows start with 'AppTeam':", relevant_flows)
18+
flow_checks.name_starts_with_prefix(relevant_flows, "AppTeam")
19+
}
20+
21+
# Deny if `deploy` is not true for all flows
22+
deny[msg] if {
23+
not deploy_true
24+
msg := "All 'davinci_flow' resources must have 'deploy' set to true."
25+
print("Deny triggered for deploy:", msg) # Debugging output
26+
}
27+
28+
# Deny if any flow name does not start with "AppTeam"
29+
deny[msg] if {
30+
not name_starts_with_AppTeam
31+
msg := "All 'davinci_flow' resources must have names starting with 'AppTeam'."
32+
print("Deny triggered for name prefix:", msg) # Debugging output
33+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package terraform.davinci
2+
3+
import data.terraform.davinci
4+
import rego.v1
5+
6+
# Mock data for testing the `deny` rules
7+
input_all_pass := {
8+
"resource_changes": [
9+
{
10+
"type": "davinci_flow",
11+
"change": {
12+
"actions": ["create"],
13+
"after": {
14+
"deploy": true,
15+
"name": "AppTeam Registration Flow"
16+
}
17+
}
18+
}
19+
]
20+
}
21+
22+
input_deploy_fail := {
23+
"resource_changes": [
24+
{
25+
"type": "davinci_flow",
26+
"change": {
27+
"actions": ["create"],
28+
"after": {
29+
"deploy": false,
30+
"name": "AppTeam Registration Flow"
31+
}
32+
}
33+
}
34+
]
35+
}
36+
37+
input_name_prefix_fail := {
38+
"resource_changes": [
39+
{
40+
"type": "davinci_flow",
41+
"change": {
42+
"actions": ["create"],
43+
"after": {
44+
"deploy": true,
45+
"name": "NonAppTeam Registration Flow" # Should fail because name does not start with "AppTeam"
46+
}
47+
}
48+
}
49+
]
50+
}
51+
52+
# Test where all conditions pass
53+
test_all_conditions_pass if {
54+
davinci.deny with input as input_all_pass # Expect no deny messages
55+
}
56+
57+
58+
# Test where `deploy` fails
59+
test_deploy_fail if {
60+
davinci.deny with input as input_deploy_fail # Expect a deny message because deploy is false
61+
}
62+
63+
# # Test where name prefix fails
64+
test_name_prefix_fail if {
65+
davinci.deny with input as input_name_prefix_fail # Expect a deny message because name does not start with "AppTeam"
66+
}

opa/policies/flow_checks.rego

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package terraform.flow_checks
2+
3+
import data.terraform.library
4+
import rego.v1
5+
6+
# Retrieve `davinci_flow` resources with a specific action (e.g., "create")
7+
get_relevant_flows(action) = flows if {
8+
flows := [flow |
9+
flow := library.get_resources_by_type_and_action("davinci_flow", action)[_];
10+
is_object(flow.change.after) # Ensure `after` is an object
11+
]
12+
# print("Relevant flows retrieved with action:", action, "flows:", flows) # Debugging output
13+
}
14+
15+
# Check if `deploy` is true for all flows in the input list
16+
deploy_is_true_for_all(flows) if {
17+
print("Checking deploy field for each relevant flow.")
18+
all_true := [flow |
19+
flow := flows[_];
20+
deploy_value := object.get(flow.change.after, "deploy", false)
21+
# print("Flow deploy value:", deploy_value) # Print the actual deploy value for each flow
22+
# print("Deploy value is boolean?", is_boolean(deploy_value)) # Debugging output
23+
deploy_value == true
24+
]
25+
# print("Flows with deploy set to true:", all_true) # Debugging output
26+
# print("Count of flows with deploy true:", count(all_true))
27+
# print("Total number of flows:", count(flows))
28+
count(all_true) == count(flows)
29+
# print("Does count(all_true) == count(flows)?", count(all_true) == count(flows)) # Debugging output
30+
}
31+
32+
# Check if all flow names start with a given prefix
33+
name_starts_with_prefix(flows, prefix) if {
34+
all_prefixed := [flow |
35+
flow := flows[_];
36+
startswith(flow.change.after.name, prefix)
37+
]
38+
# print("Flows with names starting with prefix:", prefix, "flows:", all_prefixed) # Debugging output
39+
count(all_prefixed) == count(flows)
40+
}

opa/policies/library.rego

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package terraform.library
2+
3+
import rego.v1
4+
5+
# Importing resources from input for readability
6+
import input.resource_changes as resources
7+
8+
# Get resources by type
9+
get_resources_by_type(type) = filtered_resources if {
10+
filtered_resources := [resource | resource := resources[_]; resource.type == type]
11+
}
12+
13+
# Get resources by action
14+
get_resources_by_action(action) = filtered_resources if {
15+
filtered_resources := [resource | resource := resources[_]; action in resource.change.actions]
16+
}
17+
18+
# Get resources by type and action
19+
get_resources_by_type_and_action(type, action) = filtered_resources if {
20+
filtered_resources := [resource | resource := resources[_]; resource.type == type; action in resource.change.actions]
21+
}
22+
23+
# Get resource by name
24+
get_resource_by_name(resource_name) = filtered_resources if {
25+
filtered_resources := [resource | resource := resources[_]; resource.name == resource_name]
26+
}
27+
28+
# Get resource by type and name
29+
get_resource_by_type_and_name(type, resource_name) = filtered_resources if {
30+
filtered_resources := [resource | resource := resources[_]; resource.type == type; resource.name == resource_name]
31+
}

terraform/customer_simple_registration.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ resource "davinci_flow" "registration_flow" {
3232
# {@link https://registry.terraform.io/providers/pingidentity/davinci/latest/docs/resources/application}
3333

3434
resource "davinci_application" "registration_flow_app" {
35-
name = "PingOne DaVinci Registration Example"
35+
name = "AppTeam PingOne DaVinci Registration Example"
3636
environment_id = var.pingone_target_environment_id
3737
depends_on = [data.davinci_connections.read_all]
3838
oauth {

terraform/davinci_flows/davinci-widget-reg-authn-flow.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
},
2323
"isInputSchemaSaved": false,
2424
"isOutputSchemaSaved": false,
25-
"name": "PingOne DaVinci Registration Example",
25+
"name": "AppTeam PingOne DaVinci Registration Example",
2626
"publishedVersion": 4,
2727
"settings": {
2828
"csp": "worker-src 'self' blob:; script-src 'self' https://cdn.jsdelivr.net https://code.jquery.com https://devsdk.singularkey.com http://cdnjs.cloudflare.com 'unsafe-inline' 'unsafe-eval';",
@@ -616,7 +616,7 @@
616616
"nodeType": "ANNOTATION",
617617
"properties": {
618618
"annotation": {
619-
"value": "PingOne DaVinci Registration Example"
619+
"value": "AppTeam PingOne DaVinci Registration Example"
620620
},
621621
"annotationTextColor": {
622622
"value": "#ffffffff"

0 commit comments

Comments
 (0)