skills/iam-identity-management/SKILL.md
Use when writing IAM policies, troubleshooting 403/404 permission errors, setting up dynamic groups, or debugging IDCS federation. Covers OCI-specific policy syntax gotchas, principal type confusion, compartment hierarchy rules, verb hierarchy, and common authorization failures. KEYWORDS: IAM, policy, permission denied, dynamic group, compartment, IDCS, federation, 403, 404.
npx skillsauth add acedergren/agentic-tools iam-identity-managementInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
NEVER use overly broad policies in production
# WRONG - grants admin to everyone, instant security audit failure
Allow any-user to manage all-resources in tenancy
# RIGHT - explicit group, specific resource, specific compartment
Allow group AppDevelopers to manage instance-family in compartment AppDev
where target.instance.name =~ 'dev-*'
NEVER place policy in a child compartment when the target resource is in a parent
# WRONG - policy in A/B/C cannot grant access to resources in A
Policy location: Compartment A/B/C
"Allow group X to read buckets in compartment A" # Fails silently
# RIGHT - policy must be AT OR ABOVE the target compartment
Policy location: Compartment A (or root tenancy)
"Allow group X to read buckets in compartment A"
This is the single most common policy misconfiguration in OCI — no error is thrown, access just fails.
NEVER use any-user in production policies
Allow group DataReaders to read buckets in compartment SharedDataNEVER grant access to instances using user principal syntax
# WRONG - instances are NOT users
Allow user <instance-ocid> to read buckets in compartment X
# RIGHT - use dynamic groups for instances
Allow dynamic-group app-instances to read buckets in compartment X
NEVER hardcode resource OCIDs in dynamic group rules
# WRONG - breaks when instance is replaced
ALL {instance.id = 'ocid1.instance.oc1.phx.xxxxx'}
# RIGHT - use compartment or tag matching (survives instance replacement)
ALL {instance.compartment.id = '<compartment-ocid>'}
ANY {instance.freeform-tags.environment = 'production'}
This error is intentionally ambiguous — OCI returns 404 whether the resource doesn't exist OR the caller lacks inspect permission. This prevents enumeration attacks.
404 NotAuthorizedOrNotFound?
│
├─ Does the resource definitely exist?
│ ├─ YES → Permission issue
│ │ └─ Does caller have at least 'inspect' on that resource type?
│ │ └─ Is policy at or above the target compartment?
│ └─ NO → Verify OCID, compartment, region
│
├─ Using dynamic group / instance principal?
│ └─ oci compute instance get --instance-id <ocid> (check compartment + tags)
│ └─ Does instance's compartment/tags match the dynamic group rule?
│
└─ Cross-compartment access?
└─ Policy must be in the compartment containing BOTH source and target
OR in root (tenancy)
Caller is identified but explicitly lacks permission.
Common causes:
read but action requires use or manageinstance-family but accessing volume-familywhere target.instance.name = 'prod-*' but instance is dev-web-1Verb hierarchy (each includes those below it):
inspect < read < use < manage
| Family | Includes | Common Mistake |
|--------|----------|----------------|
| instance-family | instances, console-connections, vnics, vnic-attachments | Does NOT include volumes |
| volume-family | volumes, volume-backups, volume-attachments | Separate from instance-family |
| object-family | buckets, objects | Objects are a separate resource type from buckets |
| database-family | db-systems, databases, autonomous-databases | Very broad — scope carefully |
# Tag-based
where target.resource.tag.environment = 'production'
where target.resource.freeform-tags.CostCenter = 'Engineering'
# Resource name (regex)
where target.instance.name =~ 'web-*'
# Request properties
where request.operation = 'LaunchInstance'
# Combined conditions
where all {target.resource.tag.env = 'prod', target.compartment.name = 'AppProd'}
where any {target.instance.shape = 'VM.Standard.E4.Flex', target.instance.shape = 'VM.Standard.A1.Flex'}
in compartment <name-or-ocid> # Specific compartment only
in tenancy # Root — applies everywhere
in resource <resource-ocid> # Rare; used for delegation
Note: there is no built-in syntax for "compartment + all descendants" — to cover a subtree, put the policy in the parent compartment.
By compartment (most common — covers all current and future instances):
ALL {instance.compartment.id = '<compartment-ocid>'}
By tag (flexible — survives instance replacement):
ANY {instance.freeform-tags.app = 'webserver'}
Restrictive AND rule (production workloads):
ALL {instance.compartment.id = '<comp-ocid>', instance.freeform-tags.environment = 'production'}
# 1. Get instance details (compartment + tags)
oci compute instance get --instance-id <instance-ocid>
# 2. Check dynamic group rule
oci iam dynamic-group get --dynamic-group-id <group-ocid>
# 3. Verify rule matches — if rule is "instance.compartment.id = X",
# confirm the instance's compartment_id field equals X
# 4. Test from the instance (SSH in and run):
oci os ns get # Works only if instance principal is correctly configured
| Method | Use Case | Key Constraint | |--------|----------|----------------| | API Key | Local dev, CI/CD outside OCI | Manual rotation required | | Instance Principal | Apps on OCI compute | Only works on OCI compute | | Resource Principal | OCI Functions, Data Flow | Limited to specific services | | Session Token | Console federation via IDCS | Short-lived (~1 hour) |
# WRONG: Flat structure — no IAM boundary between dev/prod
Tenancy
├─ Application1 (mix of dev/test/prod resources)
└─ SharedServices
# RIGHT: Environment-based hierarchy — clear blast radius, cost reporting
Tenancy
├─ Production
│ ├─ App1
│ └─ App2
├─ Development
│ ├─ App1
│ └─ App2
└─ SharedServices
├─ Networking
└─ Security
Load references/oci-iam-policies-reference.md when:
Do NOT load for quick syntax examples, troubleshooting 403/404, or dynamic group rules — this file covers those.
development
--- name: api-audit description: "Use when auditing API routes for schema drift, missing auth, or validation gaps. Scans routes against shared TypeScript types to find mismatches, missing middleware, and undocumented endpoints. Read-only — produces a severity-grouped report. Keywords: audit routes, schema drift, auth gaps, missing validation, type mismatch, orphaned schemas. Triggers on "audit API routes" or "find schema drift"." --- # API Route & Type Audit Skill ## When to Use Load this skil
development
Use when drafting, translating, polishing, or reviewing Swedish text so it sounds natural, fluent, contemporary, and appropriate for its audience. Triggers include "write better Swedish", "make this sound natural in Swedish", "translate into Swedish", "polish this Swedish", "tech company Swedish", "contemporary Swedish words", "Swedish developer docs", and "avoid Anglicisms".
development
Use when working with shadcn-svelte components, TanStack Table in Svelte 5, or Tailwind v4.1. Covers non-obvious reactivity bugs, library selection trade-offs, and migration pitfalls not in the official docs. Keywords: shadcn-svelte, TanStack Table, Tailwind v4.1, Svelte 5 runes, bits-ui, superforms, data table, svelte-check.
data-ai
Use when mapping IDCS claims to org membership after OAuth login succeeds. Covers mapProfileToUser, session.create.before, session.create.after hooks, MERGE INTO upserts, tenant-org mapping, and first-admin bootstrap. Keywords: IDCS groups, org_members, provisioning, session hooks, tenant map, MERGE INTO.