Skip to content

Commit

Permalink
dynamic policy setup
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Macdonald <macdonald.peter90@gmail.com>
  • Loading branch information
Parsifal-M committed Dec 1, 2024
1 parent b31f837 commit 9f4075f
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 46 deletions.
7 changes: 7 additions & 0 deletions docs/opa-permissions-wrapper-module/example-rbac-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,10 @@ decision := conditional("scaffolder", "scaffolder-action", {"not": {"anyOf": [{
not is_admin
}
```

## Dynamic Policies

Its also possible to have a dynamic policy setup, you can read a great blog post by Anders Eknert [Dynamic Policy Composition](https://www.styra.com/blog/dynamic-policy-composition-for-opa/) you can find a similar example of this setup
[here](https://github.com/Parsifal-M/backstage-opa-plugins/blob/main/policies/rbac_policy.rego) you'll notice the `imports` where we are importing other policies and routing decisions to them.

There are also some great examples of this here [PlaTT Policy Template](https://github.com/ap-communications/platt-policy-template)
25 changes: 25 additions & 0 deletions policies/catalog.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package catalog_rules

import rego.v1

claims := input.identity.claims

# Shared helper functions
conditional(plugin_id, resource_type, conditions) := {
"result": "CONDITIONAL",
"pluginId": plugin_id,
"resourceType": resource_type,
"conditions": conditions,
}

catalog_entity_delete_rule := conditional("catalog", "catalog-entity", {"anyOf": [{
"resourceType": "catalog-entity",
"rule": "IS_ENTITY_OWNER",
"params": {"claims": claims},
}]})

catalog_entity_read_rules := conditional("catalog", "catalog-entity", {"anyOf": [{
"resourceType": "catalog-entity",
"rule": "IS_ENTITY_KIND",
"params": {"kinds": ["Component"]},
}]})
70 changes: 24 additions & 46 deletions policies/rbac_policy.rego
Original file line number Diff line number Diff line change
@@ -1,66 +1,44 @@
package rbac_policy

import rego.v1
import data.catalog_rules
import data.scaffolder_rules
import data.http_rules

# Helper method for constructing a conditional decision
conditional(plugin_id, resource_type, conditions) := {
"result": "CONDITIONAL",
"pluginId": plugin_id,
"resourceType": resource_type,
"conditions": conditions,
}

default decision := {"result": "ALLOW"}
default decision := {"result": "DENY"}

permission := input.permission.name

claims := input.identity.claims

is_admin if "group:twocodersbrewing/maintainers" in claims

# decision := {"result": "DENY"} if {
# permission == "catalog.entity.create"
# not is_admin
# }
is_admin if "group:default/maintainers" in claims

# Conditional based on claims (groups a user belongs to) unless they are an admin
decision := conditional("catalog", "catalog-entity", {"anyOf": [{
"resourceType": "catalog-entity",
"rule": "IS_ENTITY_OWNER",
"params": {"claims": claims},
}]}) if {
permission == "catalog.entity.delete"
not is_admin
# Admins have god mode
decision := {"result": "ALLOW"} if {
is_admin
}

# Allow users to only see components unless they are an admin
# decision := conditional("catalog", "catalog-entity", {"anyOf": [{
# "resourceType": "catalog-entity",
# "rule": "IS_ENTITY_KIND",
# "params": {"kinds": ["API"]},
# }]}) if {
# permission == "catalog.entity.read"
# not is_admin
# }
# Non-admins can only read components
# Does not apply to admins
decision := catalog_rules.catalog_entity_read_rule if {
permission == "catalog.entity.read"
not is_admin
}

# Scaffolder Permissions
# Only owners of the entity can delete it
# Does not apply to admins
decision := catalog_rules.catalog_entity_delete_rule if {
permission == "catalog.entity.delete"
not is_admin
}

# Conditional based on scaffolder template tags unless they are an admin
decision := conditional("scaffolder", "scaffolder-template", {"not": {"anyOf": [{
"resourceType": "scaffolder-template",
"rule": "HAS_TAG",
"params": {"tag": "admin"},
}]}}) if {
# Only admins can read templates with the admin tag
decision := scaffolder_rules.scaffolder_entity_read_rule if {
permission == "scaffolder.template.parameter.read"
not is_admin
}

# Conditional based on scaffolder actionID tags unless they are an admin
decision := conditional("scaffolder", "scaffolder-action", {"not": {"anyOf": [{
"resourceType": "scaffolder-action",
"rule": "HAS_ACTION_ID",
"params": {"actionId": "debug:log"},
}]}}) if {
# Only admins can execute the debug action
decision := scaffolder_rules.scaffolder_entity_action_rule if {
permission == "scaffolder.action.execute"
not is_admin
}
25 changes: 25 additions & 0 deletions policies/scaffolder.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package scaffolder_rules

import rego.v1

# Helper function to create a conditional decision
conditional(plugin_id, resource_type, conditions) := {
"result": "CONDITIONAL",
"pluginId": plugin_id,
"resourceType": resource_type,
"conditions": conditions,
}

claims := input.identity.claims

scaffolder_entity__read_rules := conditional("scaffolder", "scaffolder-template", {"not": {"anyOf": [{
"resourceType": "scaffolder-template",
"rule": "HAS_TAG",
"params": {"tag": "admin"},
}]}})

scaffolder_entity_action_rules := conditional("scaffolder", "scaffolder-action", {"not": {"anyOf": [{
"resourceType": "scaffolder-action",
"rule": "HAS_ACTION_ID",
"params": {"actionId": "debug:log"},
}]}})

0 comments on commit 9f4075f

Please sign in to comment.