Policies
On this page
Policies define what actions a caller can perform on which resources. This guide explains the JSON structure, the evaluation logic (Allow vs. Deny), wildcard matching, resource formats, and ready-to-use examples.
See also: Permissions Reference
TL;DR (key takeaways)
- Default is deny; you need an explicit Allow to pass, and any matching Deny wins.
- Actions and resources match exactly or by trailing wildcard (e.g.,
compute:*,exc:compute:instance/*). - Many list endpoints pass
resource=""; scope using Action only in those cases. - Managed policies (global) always apply in addition to org policies.
- Changes take up to ~10s to take effect due to caching.
What is a policy
- A policy is a JSON document with
Versionand an array ofStatements. - Statements decide whether a request is allowed or denied based on
ActionandResource.
Policy JSON structure
- PolicyDocument
- Version: string (optional)
- Statements: array of StatementEntry (required)
- StatementEntry
- Sid: string (optional label)
- Effect: “Allow” or “Deny” (required)
- Action: string or string[] (required)
- Resource: string or string[] (required; use “*” if not scoping)
- Condition: any (present but not enforced today)
Example Admin policy (full access):
{
"Version": "2024-03-05",
"Statements": [
{ "Sid": "stmt1", "Effect": "Allow", "Action": "*", "Resource": "*" }
]
}Evaluation model
- Default is deny. Access is only granted if:
- At least one statement matches AND Effect == Allow, AND
- No matching statement has Effect == Deny.
- All policies bound to the caller are merged. Policies apply if:
- policy.OrgID == request’s orgId, OR
- policy.IsManaged == true (global managed policies).
- Matching is case-insensitive.
Matching rules
- Exact or prefix wildcard matching:
compute:instance:listmatches exactly that action.compute:*matches all compute actions.exc:compute:instance/*matches any instance with that resource prefix.*matches everything.
- Wildcards are trailing-only:
prefix*. - If a handler passes empty resource (
""), resource matching is skipped; onlyActionis checked.
Caching and propagation
- Policy sets are cached per caller for ~10 seconds.
- After creating/updating/deleting/binding a policy, allow up to 10s for enforcement to reflect.
Managed vs. Org policies
- Managed policies (
IsManaged=true) are global and always apply. - Org policies apply only within that org.
Resource naming conventions
- Compute
- Instance lifecycle:
exc:compute:instance/<id> - Instance connect:
compute:instance:connect/<id> - Security group:
exc:compute:securitygroup/<id> - Interface (for SG bindings list):
exc:compute:interface/<id> - Security group rule:
exc:compute:securitygroup:rule/<id> - SSH public key:
exc:compute:sshpubkey/<id> - Many list actions use
resource="", so resource scoping doesn’t apply there.
- Instance lifecycle:
- DNS
- Zone:
exc:dns:zone/<zoneName>
- Zone:
- Database
- Cluster:
exc:database:cluster/<id> - Node:
exc:database:node/<id>
- Cluster:
- IAM, Billing
- Typically
resource="*"(or""), not resource-scoped in current handlers.
- Typically
Resource formats cheat sheet
| Service | Resource format | Example |
|---|---|---|
| Compute (instance) | exc:compute:instance/<id> | exc:compute:instance/42 |
| Compute (connect) | compute:instance:connect/<id> | compute:instance:connect/42 |
| Compute (security group) | exc:compute:securitygroup/<id> | exc:compute:securitygroup/sg-1 |
| Compute (sg rule) | exc:compute:securitygroup:rule/<id> | exc:compute:securitygroup:rule/r-10 |
| Compute (interface) | exc:compute:interface/<id> | exc:compute:interface/eni-1 |
| Compute (ssh key) | exc:compute:sshpubkey/<id> | exc:compute:sshpubkey/k-1 |
| DNS (zone) | exc:dns:zone/<zoneName> | exc:dns:zone/example.com |
| Database (cluster) | exc:database:cluster/<id> | exc:database:cluster/db-1 |
| Database (node) | exc:database:node/<id> | exc:database:node/n-1 |
Current action catalog
- Compute
- Instances:
compute:instance:create,compute:instance:list,compute:instance:start,compute:instance:restart,compute:instance:stop,compute:instance:terminate,compute:instance:connect - Security groups:
compute:securitygroup:create,compute:securitygroup:list,compute:securitygroup:delete - SG bindings:
compute:securitygroup:binding:create,compute:securitygroup:binding:list,compute:securitygroup:binding:delete - SG rules:
compute:securitygroup:rule:create,compute:securitygroup:rule:list,compute:securitygroup:rule:delete - SSH keys:
compute:sshpubkey:create,compute:sshpubkey:list,compute:sshpubkey:delete - Subnets:
compute:subnet:list - Volumes:
compute:volume:create,compute:volume:list,compute:volume:resize,compute:volume:delete - Snapshots:
compute:snapshot:create,compute:snapshot:list,compute:snapshot:delete
- Instances:
- DNS
dns:record:create,dns:record:update,dns:record:delete,dns:record:listdns:zone:create,dns:zone:delete,dns:zone:list
- Database
database:cluster:create,database:cluster:restart,database:cluster:terminate,database:cluster:resetpassword,database:cluster:listdatabase:node:add,database:node:restart,database:node:terminate
- IAM
iam:account:invite,iam:account:listiam:serviceaccount:create,iam:serviceaccount:list,iam:serviceaccount:update,iam:serviceaccount:deleteiam:policy:create,iam:policy:list,iam:policy:update,iam:policy:deleteiam:policy:binding:create,iam:policy:binding:list,iam:policy:binding:deleteiam:billing:get,iam:billing:updateiam:org:rename
- Billing
billing:ca(Cost Explorer)
Note: Some informational endpoints don’t enforce policies (e.g., instance types or images). Those are not listed as actions.
Common policy recipes
Project admin (all within an org):
{
"Version": "2024-03-05",
"Statements": [
{ "Sid": "all-compute", "Effect": "Allow", "Action": "compute:*", "Resource": "*" },
{ "Sid": "all-dns", "Effect": "Allow", "Action": "dns:*", "Resource": "*" },
{ "Sid": "all-db", "Effect": "Allow", "Action": "database:*", "Resource": "*" },
{ "Sid": "iam-basic", "Effect": "Allow", "Action": [
"iam:serviceaccount:create", "iam:serviceaccount:list", "iam:serviceaccount:update", "iam:serviceaccount:delete",
"iam:policy:create", "iam:policy:list", "iam:policy:update", "iam:policy:delete", "iam:policy:binding:create", "iam:policy:binding:list", "iam:policy:binding:delete",
"iam:account:list"
], "Resource": "*" },
{ "Sid": "billing-read", "Effect": "Allow", "Action": ["iam:billing:get", "billing:ca"], "Resource": "*" }
]
}DNS admin:
{
"Version": "2024-03-05",
"Statements": [
{ "Sid": "zones", "Effect": "Allow", "Action": ["dns:zone:create", "dns:zone:delete", "dns:zone:list"], "Resource": "*" },
{ "Sid": "records", "Effect": "Allow", "Action": ["dns:record:create", "dns:record:update", "dns:record:delete", "dns:record:list"], "Resource": "*" }
]
}Compute operator (no deletes):
{
"Version": "2024-03-05",
"Statements": [
{ "Sid": "instances", "Effect": "Allow", "Action": [
"compute:instance:create", "compute:instance:list", "compute:instance:start", "compute:instance:restart", "compute:instance:stop", "compute:instance:connect"
], "Resource": "*" },
{ "Sid": "volumes", "Effect": "Allow", "Action": [
"compute:volume:create", "compute:volume:list", "compute:volume:resize"
], "Resource": "*" },
{ "Sid": "securitygroups", "Effect": "Allow", "Action": [
"compute:securitygroup:create", "compute:securitygroup:list",
"compute:securitygroup:binding:create", "compute:securitygroup:binding:list",
"compute:securitygroup:rule:create", "compute:securitygroup:rule:list"
], "Resource": "*" }
]
}Billing-only:
{
"Version": "2024-03-05",
"Statements": [
{ "Sid": "billing", "Effect": "Allow", "Action": ["iam:billing:get", "billing:ca"], "Resource": "*" }
]
}Ready-to-use policies
Strict ReadOnly (no connect):
{
"Version": "2024-03-05",
"Statements": [
{
"Sid": "read-only",
"Effect": "Allow",
"Action": [
"compute:instance:list",
"compute:securitygroup:list",
"compute:securitygroup:binding:list",
"compute:securitygroup:rule:list",
"compute:sshpubkey:list",
"compute:subnet:list",
"compute:volume:list",
"compute:snapshot:list",
"dns:zone:list",
"dns:record:list",
"database:cluster:list",
"iam:policy:list",
"iam:policy:binding:list",
"iam:serviceaccount:list",
"iam:account:list",
"iam:billing:get",
"billing:ca"
],
"Resource": "*"
}
]
}ReadOnly + Connect (allows ephemeral terminal access):
{
"Version": "2024-03-05",
"Statements": [
{
"Sid": "read-and-connect",
"Effect": "Allow",
"Action": [
"compute:instance:list",
"compute:securitygroup:list",
"compute:securitygroup:binding:list",
"compute:securitygroup:rule:list",
"compute:sshpubkey:list",
"compute:subnet:list",
"compute:volume:list",
"compute:snapshot:list",
"compute:instance:connect",
"dns:zone:list",
"dns:record:list",
"database:cluster:list",
"iam:policy:list",
"iam:policy:binding:list",
"iam:serviceaccount:list",
"iam:account:list",
"iam:billing:get",
"billing:ca"
],
"Resource": "*"
}
]
}Scoped example: allow viewing SG bindings for one security group:
{
"Version": "2024-03-05",
"Statements": [
{
"Sid": "view-one-sg",
"Effect": "Allow",
"Action": ["compute:securitygroup:binding:list", "compute:securitygroup:rule:list"],
"Resource": ["exc:compute:securitygroup/123"]
}
]
}Deny carve-out example (deny SSH key listing everywhere):
{
"Version": "2024-03-05",
"Statements": [
{
"Sid": "allow-read",
"Effect": "Allow",
"Action": ["*"],
"Resource": ["*"]
},
{
"Sid": "block-ssh-key-list",
"Effect": "Deny",
"Action": ["compute:sshpubkey:list"],
"Resource": ["*"]
}
]
}Authoring guidelines
- Start least-privileged; add only needed actions.
- Use Resource scoping where possible; otherwise keep
Resource="*". - Apply Deny for must-not rules; Deny always wins.
- Avoid legacy or non-enforced actions (e.g.,
iam:policy:bind,compute:instance:describe,database:cluster:describe,compute:subnet:create,orgs:create).
Validation rules
- Action/Resource strings are lowercase; accept string or array.
- Wildcards: only trailing
*supported. - Require at least one statement.
- Effect must be
AlloworDeny. - Changes take up to ~10s to take effect (caching).
FAQ
- Why do my changes not apply immediately?
- Policies are cached for ~10s per caller.
- Why am I denied even though an Allow is present?
- A matching Deny exists; Deny overrides Allow.
- How do I scope to a specific resource?
- Use the resource formats above (e.g.,
exc:compute:instance/42).
- Use the resource formats above (e.g.,