Symptoms
ServiceError: 404 NotAuthorizedOrNotFoundfrom SDK calls on an instance that worked before.- Started after an instance was recreated, moved to another compartment, or after IAM was reorganised into identity domains.
1. Test from the instance
oci os ns get --auth instance_principal
oci secrets secret-bundle get --secret-id <secret-ocid> --auth instance_principal
If os ns get fails, the instance can't get a principal token at all (network to the metadata service or IAM endpoints). If it works but the specific call fails, it's a policy or matching problem.
2. Does the dynamic group still match the instance?
curl -s -H "Authorization: Bearer Oracle" http://169.254.169.254/opc/v2/instance/ | jq '{id, compartmentId, definedTags}'
Compare with the dynamic group rule (identity domain → Dynamic groups):
ANY {instance.compartment.id = 'ocid1.compartment.oc1..aaaa'}
ALL {instance.compartment.id = 'ocid1.compartment.oc1..aaaa', tag.app.role.value = 'web'}
| Change | Breaks rules that use |
|---|---|
| Instance recreated | instance.id = '...' |
| Instance or compartment moved | instance.compartment.id = '...' |
| Tag removed or renamed | tag.<ns>.<key>.value |
Prefer compartment or tag-based rules over instance OCIDs.
3. Does a policy grant the dynamic group?
Allow dynamic-group 'Default'/'app-instances' to read secret-family in compartment prod-security
Allow dynamic-group 'Default'/'app-instances' to manage objects in compartment prod-data where target.bucket.name = 'app-exports'
Check:
- The domain prefix: a dynamic group in a non-default domain must be referenced as
'<domain>'/'<name>'. - The policy is attached at the right compartment (the target resource's compartment or an ancestor).
- Conditions (
where target.bucket.name = ...) still match renamed resources.
4. Resource principals (Functions, OKE)
Functions use resource.type = 'fnfunc' in dynamic group rules:
ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaa'}
For OKE pods, use OKE Workload Identity policies with request.principal.type = 'workload' and namespace/service account conditions; check the current documentation for the exact attribute names.
5. Token and network on the instance
- The SDK fetches a token from the instance metadata service (
169.254.169.254) and federation endpoint (auth.<region>.oraclecloud.com). Egress must allow HTTPS to OCI services (NAT gateway or Service Gateway with All Services). - Instance clock must be correct (NTP); large skew breaks request signing.
- Long-running processes cache tokens; they refresh automatically in current SDKs — update old SDK versions.
6. Wait for propagation
Dynamic group membership and policy changes usually apply quickly but can take a few minutes. Retest before changing more.
Prevent it next time
- Tag- or compartment-based matching rules; avoid instance OCIDs.
- Policies and dynamic groups in Terraform alongside the workload.
- A health check in the app that calls a cheap authorised API at start-up and fails loudly.