Mechanism per workload
| Workload | Identity |
|---|---|
| Compute instance (VM/BM) | Instance principal via a dynamic group matching the instance |
| OCI Functions | Resource principal (dynamic group matching resource.type = 'fnfunc') |
| Data Flow, Data Science, other supporting services | Resource principal (service-specific) |
| OKE pod | Workload identity (enhanced clusters): policies target namespace + service account |
| On-premises server, other cloud, CI/CD | API key for a dedicated service user (least privilege, rotated), or token exchange / federation where available |
| Humans | Identity domain users via SSO (not part of workload identity) |
Instance principals
# dynamic group "orders-app-instances"
ALL {instance.compartment.id = 'ocid1.compartment.oc1..prod-orders', tag.Operations.App.value = 'orders'}
# policy
Allow dynamic-group orders-app-instances to read secret-bundles in compartment prod-orders
Allow dynamic-group orders-app-instances to manage objects in compartment prod-orders where target.bucket.name = 'orders-exports'
Match on compartment and a tag so a random instance in the compartment doesn't inherit the access. Protect the tag with tag namespace permissions.
SDK use:
import oci
signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
client = oci.object_storage.ObjectStorageClient(config={}, signer=signer)
Resource principals (Functions)
ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..prod-orders'}
signer = oci.auth.signers.get_resource_principals_signer()
OKE workload identity
Policies refer to the cluster, namespace and service account directly; no dynamic group needed:
Allow any-user to read secret-bundles in compartment prod-orders where all {
request.principal.type = 'workload',
request.principal.namespace = 'orders',
request.principal.service_account = 'orders-api',
request.principal.cluster_id = 'ocid1.cluster.oc1..xxxx' }
Pods use the SDK's OKE workload identity signer. Prefer this over instance principals for pods: node-level instance principals give every pod on the node the node's permissions.
Scoping rules
- One dynamic group / workload identity per application, not per team.
read/useverbs beforemanage; conditions on target names or tags.- Separate policies per environment compartment.
- Review with IAM policy analysis tools and audit logs for unused permissions.
When API keys are unavoidable
- Dedicated service user per integration, member of a narrowly scoped group.
- Key stored in a secret manager, not in code; rotate at least every 90 days.
- Alert on API key creation (Events rule on
CreateApiKey), and review keys older than the rotation period.
Guardrails
- Restrict who can create API keys and auth tokens (policies and identity domain settings).
- Cloud Guard detectors for old API keys and overly permissive policies.
- Template modules that create dynamic groups and policies for each app, so teams don't hand-write broad ones.
Warning
A dynamic group matching only on compartment gives every instance there the same rights, including ones launched later for unrelated reasons. Always add a tag or instance-OCID condition for sensitive permissions.
Checklist
- Identity mechanism chosen per workload type
- Dynamic groups match compartment + protected tag
- OKE workload identity instead of node instance principals for pods
- Policies least-privilege per app and environment
- Remaining API keys owned, stored safely, rotated, alerted
- Guardrails via policy, Cloud Guard and modules