Most tenancies start with broad compartment-level policies. As teams grow, you need finer control without a compartment per person. Policy conditions (the where clause) and tag-based access get you there.
Anatomy of a conditional policy
Allow group <group> to <verb> <resource-type> in compartment <name> where <conditions>
Conditions use variables:
| Variable family | Examples |
|---|---|
request.* | request.user.id, request.groups.id, request.operation, request.permission, request.region, request.principal.type |
target.* | target.compartment.name, target.bucket.name, target.vcn.id, target.resource.tag.<ns>.<key> |
request.principal.group.tag / request.principal.compartment.tag | Tags on the caller's group or compartment |
Combine with all { ... } and any { ... }.
Pattern 1: least privilege by permission
Allow a support group to restart instances but not terminate them:
Allow group L2-Support to use instances in compartment App1-Prod
where any { request.permission = 'INSTANCE_POWER_ACTIONS', request.permission = 'INSTANCE_READ' }
Use request.permission (finer) where the service documents permissions; request.operation matches API operation names.
Pattern 2: one bucket, not all buckets
Allow group Reports-Writers to manage objects in compartment Data
where all { target.bucket.name = 'monthly-reports', any { request.permission = 'OBJECT_CREATE', request.permission = 'OBJECT_INSPECT', request.permission = 'OBJECT_READ' } }
Pattern 3: tag-based access (resource tags)
Create a defined tag namespace and key:
NS=$(oci iam tag-namespace create --compartment-id $TENANCY_OCID --name Ops --description "Operational tags" --query 'data.id' --raw-output)
oci iam tag create --tag-namespace-id $NS --name Team --description "Owning team"
Then:
Allow group Team-Payments to manage instance-family in compartment Workloads
where target.resource.tag.Ops.Team = 'payments'
Team Payments can manage only instances tagged Ops.Team=payments, even though all teams share the compartment.
Warning
Not every resource type and operation supports
target.resource.tag. For create operations the resource does not exist yet, so the target tag condition cannot match; grant create separately (often withrequest.permission) and enforce the tag with a tag default or Security Zone. Test each action you expect to work.
Pattern 4: tags on the caller
Tag the group instead of writing a policy per team:
Allow any-user to manage instance-family in compartment Workloads
where all { request.principal.group.tag.Ops.Team = target.resource.tag.Ops.Team }
Check the IAM docs for which comparisons between variables are supported in your realm before relying on this; otherwise write one policy per tag value.
Protect the tags
Tag-based access is only as strong as control over who can change the tags.
Allow group Tag-Admins to use tag-namespaces in tenancy
Allow group Tag-Admins to manage tag-namespaces in tenancy
Only Tag-Admins should have use tag-namespaces for the Ops namespace. Anyone who can apply Ops.Team=payments to a resource can bring it into the payments team's scope. Mark sensitive tag namespaces as retired-protected in process, and audit UpdateInstance events that change tags.
Pattern 5: restrict regions and principal types
Allow group Developers to manage all-resources in compartment Sandbox
where request.region = 'eu-frankfurt-1'
Allow dynamic-group dg-ci to manage repos in compartment Build
where request.principal.type = 'instance'
Testing policies
There is no simulator in the CLI, so test with real identities:
- Create a test user in a test group.
- Write the policy.
- Try each action with that user's API key or Cloud Shell session, expecting allowed and denied results.
oci compute instance action --instance-id $TAGGED_PAYMENTS --action SOFTRESET --profile test-payments # expect success
oci compute instance action --instance-id $TAGGED_ORDERS --action SOFTRESET --profile test-payments # expect 404 NotAuthorizedOrNotFound
OCI returns 404 NotAuthorizedOrNotFound for denied access as well as for missing resources, so do not read a 404 as "it does not exist" during testing.
Common mistakes
| Mistake | Effect |
|---|---|
| Typo in a variable or tag name | Condition never matches; access silently denied |
where with a variable the service does not support | Statement grants nothing for that resource type |
| Using freeform tags | Freeform tags cannot be used in policy conditions; use defined tags |
| Case mismatch in values | Comparisons can be case sensitive; standardise values |
Forgetting inspect/read | Users cannot list resources to find the ones they may manage |
Prevent it next time
- Store policies in Terraform with comments explaining each condition.
- Keep a small test suite (test users plus scripted actions) and run it after policy changes.
- Audit who holds
use tag-namespaceson namespaces used in policies.