Skip to main content

OCI IAM Admin Full Access Policies Should Have WHERE

More Info:

Admin full-access policies (manage all-resources) should include WHERE conditions. Unconditional full access violates least privilege and increases blast radius if admin credentials are compromised.

Risk Level

High

Address

Compliance, Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS Critical Security Controls v8
  • CMMC 2.0
  • CSA Cloud Controls Matrix v4
  • Cloudanix Best Practice
  • DPDPA
  • Digital Operational Resilience Act (EU)
  • Essential 8
  • ISO/IEC 27017
  • ISO/IEC 27018
  • ISO/IEC 27701
  • KSA PDPL
  • MAS Technology Risk Management (Singapore)
  • MITRE ATT&CK (Cloud)
  • NIS2 Directive
  • NIST SP 800-171
  • NYDFS 23 NYCRR 500
  • SWIFT Customer Security Controls Framework
  • Sarbanes-Oxley IT General Controls
  • UK NCSC Cyber Assessment Framework

Triage and Remediation

Remediation

Using Console

Below are the minimal, practical steps to remediate this using the OCI Console by tightening IAM admin policies with where conditions and aligning them with OCI IAM Monitoring findings.


1. Find the Violating Policy from IAM Monitoring

  1. Sign in to the OCI Console.
  2. Open the navigation menu → Identity & SecurityIdentity & Access Monitoring (or IAM Monitoring / Security Center → IAM Monitoring, depending on your tenancy UI).
  3. Go to Findings / Risky Policies.
  4. Filter by rule / description containing:
    OCI IAM Admin Full Access Policies Should Have WHERE Conditions
  5. Open the finding and note:
    • Policy name
    • Compartment (or Tenancy)
    • Policy statement(s) that are flagged (you will usually see statements like
      Allow group <Admins> to manage all-resources in tenancy or similar full admin rights without where).

2. Open and Edit the Policy

  1. From the navigation menu → Identity & SecurityIdentity & GovernancePolicies.
  2. In the Compartment dropdown, choose:
    • Tenancy (root) if the policy is at tenancy level, or
    • The compartment containing the policy as seen in the finding.
  3. Search for the policy name you noted in step 1.
  4. Click the policy, then click Edit Policy Statements (or Edit Policy).

You will see one or more statements like:

Allow group Admins to manage all-resources in tenancy
Allow group SuperAdmins to manage all-resources in compartment my-compartment

These are what need conditions.


3. Decide on Appropriate where Conditions

You must decide what constraint is appropriate for your environment. Common patterns:

Allow group Admins to manage all-resources in tenancy
where target.resource.tag.namespace = 'CostCenter' &&
target.resource.tag.key = 'Critical'

b) Network-based restriction (admin only from trusted IPs / CIDRs)

Allow group Admins to manage all-resources in tenancy
where request.network.source.ip.address in ('203.0.113.0/24')

c) Time-based restriction (admin only within business hours)

Allow group Admins to manage all-resources in tenancy
where request.time < '2026-12-31T23:59:59Z'

or:

Allow group Admins to manage all-resources in tenancy
where request.time > '2026-07-25T08:00:00Z' &&
request.time < '2026-07-25T18:00:00Z'

d) Restrict to specific compartments (if using overly broad “tenancy”)

Instead of in tenancy, use compartment-scoped statements, or compensate with conditions:

Allow group Admins to manage all-resources in tenancy
where target.compartment.id = 'ocid1.compartment.oc1..aaaa...'

Or even better, change it to more specific statements per compartment, each with conditions.


4. Rewrite the Problematic Statement(s)

For each flagged full-admin statement:

  1. Copy the existing statement to a text editor.
  2. Add a WHERE clause that matches your control choice (tag, IP, time, compartment, etc.).

Example transformation:

Before (violation):

Allow group Admins to manage all-resources in tenancy

After (remediated):

Allow group Admins to manage all-resources in tenancy
where request.network.source.ip.address in ('203.0.113.0/24')

Or:

Allow group Admins to manage all-resources in tenancy
where target.resource.tag.namespace = 'AdminScope' &&
target.resource.tag.key = 'Allowed'
  1. Replace the old statement with the new one in the policy editor.
  2. Review for typos (invalid conditions can break policy evaluation).
  3. Click Save changes.

5. Validate in IAM Monitoring

  1. Return to Identity & Access Monitoring / IAM Monitoring.
  2. Open the previous finding.
  3. After a short interval (or by manually triggering re-evaluation, if available), verify that:
    • The finding is now Resolved or No longer detected, OR
    • A new finding clearly indicates any further issue (e.g., syntactic problem with your where clause).

6. If You Need a Safe Migration Approach

If you are worried about locking out admins:

  1. Create a new policy with the intended where-restricted statements.
  2. Have one or two admins verify they can still perform required operations.
  3. Once confirmed:
    • Edit the original policy and remove or tighten the overly broad statements.
  4. Re-check IAM Monitoring findings.

If you tell me:

  • Your current exact policy statement(s), and
  • How you prefer to restrict admin (by IP, tag, compartment, or time),

I can give you a ready-to-paste where-clause example tailored to your tenancy.

Using CLI

Below is a minimal, CLI‑only workflow you can use to remediate the finding “OCI IAM Admin Full Access Policies Should Have WHERE Conditions” for IAM Monitoring.

Assumptions:

  • You already have the OCI CLI configured (oci setup config done).
  • You know (or can discover) the compartment(s) where the IAM policies are defined.
  • Your goal is to add a WHERE condition to “admin” / “full access” style statements such as manage all-resources.

1. Identify affected IAM policies

List policies in the tenancy (or a specific compartment) and search for “manage all-resources” without a where clause.

TENANCY_OCID="<your-tenancy-ocid>"

oci iam policy list \
--compartment-id "$TENANCY_OCID" \
--all \
--output json \
| jq -r '
.data[]
| select(.statements[] | test("manage all-resources in tenancy(?!.*where).*"; "i"))
| {name: .name, id: .id, statements: .statements}
'

Adjust the regex if your statements use in compartment <name> instead of in tenancy.

From this output, note:

  • id – the policy OCID
  • statements – the existing statements that need to be edited

2. Decide the appropriate WHERE condition

You must pick a condition that makes sense for IAM Monitoring. Common patterns:

  1. Limit by compartment:

    where target.compartment.id = 'ocid1.compartment.oc1..xxxx'
  2. Limit to IAM‑related resources:

    where any {
    target.resource.type = 'policy',
    target.resource.type = 'group',
    target.resource.type = 'user',
    target.resource.type = 'dynamic-group'
    }
  3. Limit to read‑only monitoring:

    where all {
    request.permission in ('POLICY_INSPECT','POLICY_READ','GROUP_INSPECT','GROUP_READ','USER_INSPECT','USER_READ','DYNAMIC-GROUP_INSPECT','DYNAMIC-GROUP_READ')
    }

For example, a previous statement:

Allow group IAM-Monitors to manage all-resources in tenancy

could be tightened to something like:

Allow group IAM-Monitors to manage all-resources in tenancy
where any {
target.resource.type = 'policy',
target.resource.type = 'group',
target.resource.type = 'user',
target.resource.type = 'dynamic-group'
}

Pick and design the where that matches your security requirement.


3. Build the updated list of statements (locally)

  1. Export the current policy to a file:

    POLICY_OCID="<policy-ocid-from-step-1>"

    oci iam policy get \
    --policy-id "$POLICY_OCID" \
    --output json \
    > policy-orig.json
  2. Extract the current statements to a simple JSON array:

    jq '.data.statements' policy-orig.json > statements-orig.json
  3. Edit statements-orig.json with any text editor.

    • Replace each “admin/full access” statement, e.g.:

      "Allow group IAM-Monitors to manage all-resources in tenancy"
    • With a version that includes an appropriate WHERE condition, e.g.:

      "Allow group IAM-Monitors to manage all-resources in tenancy where any { target.resource.type = 'policy', target.resource.type = 'group', target.resource.type = 'user', target.resource.type = 'dynamic-group' }"

    Make sure the file remains valid JSON (array of strings).


4. Update the policy with the new statements (CLI)

Once statements-orig.json contains your fixed statements:

oci iam policy update \
--policy-id "$POLICY_OCID" \
--statements file://statements-orig.json

Optionally preserve / update description:

DESC=$(jq -r '.data.description' policy-orig.json)

oci iam policy update \
--policy-id "$POLICY_OCID" \
--description "$DESC" \
--statements file://statements-orig.json

5. Verify

oci iam policy get \
--policy-id "$POLICY_OCID" \
--output json \
| jq '.data.statements'

Confirm every “full access” / manage all-resources statement now contains a where clause.


6. Automate (optional)

To remediate many policies, you can script:

  1. Use the list + jq filter from step 1 to enumerate candidate policies.
  2. For each:
    • Pull policy JSON
    • Use a small script (bash + jq or Python) to find statements matching manage all-resources or other full‑admin patterns and append a standard where clause for IAM Monitoring.
    • Call oci iam policy update with the transformed list of statements.

If you tell me the exact IAM Monitoring group(s) and what they should be allowed to do, I can give a concrete where template and a sample automation script.

Using Python

Below is a practical way to detect and then remediate overly‑permissive IAM policies in OCI (those with admin/full access and no where conditions) using Python and the OCI SDK.


1. What “Admin Full Access Without WHERE” Means

In OCI, a risky policy typically looks like:

Allow group Admins to manage all-resources in tenancy

or

Allow group DevOps to manage all-resources in compartment MyCompartment

These give broad “admin” rights without any limiting where clause such as:

... where request.principal.type = 'user'
... where request.user.name != 'service-xyz'
... where target.compartment.id = 'ocid1.compartment.oc1..xxxxx'

The goal is to:

  1. Find statements that are “full access” (e.g., manage all-resources, manage *).
  2. Ensure they have a where condition.
  3. If not, either:
    • Automatically replace them with a safer version, or
    • Alert and require a human to decide the proper condition.

2. Prerequisites

  1. Install the OCI Python SDK:
pip install oci
  1. Configure your OCI credentials (e.g., ~/.oci/config) and note:

    • Tenancy OCID
    • User OCID
    • Key file path
    • Fingerprint
    • Region
  2. Give your monitoring principal (user or dynamic group) permission to read and update policies, for example:

Allow group IamMonitors to inspect policies in tenancy
Allow group IamMonitors to manage policies in tenancy

(You can weaken manage to specific compartments if needed.)


3. Detection Logic (Python)

This script:

  • Lists all policies
  • Parses each statement
  • Flags those that appear to be “admin/full access” and that do not include where
import oci
import re

# ---------- CONFIG ----------
PROFILE = "DEFAULT" # Profile in ~/.oci/config
TENANCY_OCID = "<your-tenancy-ocid>" # or read from config
DRY_RUN = True # True = only report; False = also remediate (see section 4)
# ----------------------------

config = oci.config.from_file(profile_name=PROFILE)
identity_client = oci.identity.IdentityClient(config)


def is_admin_full_access(statement: str) -> bool:
"""
Very simple heuristic: adjust as needed.
We look for 'to manage all-resources' or 'to manage *'
"""
s = statement.lower()
return (
" to manage all-resources" in s
or " to manage *" in s
or re.search(r"\bto\s+manage\s+all-resources\b", s)
)


def has_where_clause(statement: str) -> bool:
return " where " in statement.lower()


def get_all_policies(identity_client, tenancy_ocid):
policies = []
response = identity_client.list_policies(
compartment_id=tenancy_ocid,
compartment_id_in_subtree=True
)
policies.extend(response.data)
while response.has_next_page:
response = identity_client.list_policies(
compartment_id=tenancy_ocid,
compartment_id_in_subtree=True,
page=response.next_page
)
policies.extend(response.data)
return policies


def main():
policies = get_all_policies(identity_client, TENANCY_OCID)

print("Scanning policies for admin full access without WHERE conditions...\n")

for policy in policies:
risky_statements = []
for stmt in policy.statements:
if is_admin_full_access(stmt) and not has_where_clause(stmt):
risky_statements.append(stmt)

if risky_statements:
print(f"Policy: {policy.name} (OCID: {policy.id}) in compartment {policy.compartment_id}")
for rs in risky_statements:
print(f" RISKY: {rs}")

if not DRY_RUN:
remediate_policy(identity_client, policy, risky_statements)

print("-" * 80)


def remediate_policy(identity_client, policy, risky_statements):
"""
This function just shows one *pattern* of remediation:
- Append a WHERE condition to the risky statements.
Adjust the 'SAFE_WHERE_CLAUSE' to your real guardrails.
"""
SAFE_WHERE_CLAUSE = " where request.principal.type = 'user'"

updated_statements = []
for stmt in policy.statements:
if stmt in risky_statements:
# Example: add a simple where clause if none is present
new_stmt = stmt + SAFE_WHERE_CLAUSE
updated_statements.append(new_stmt)
print(f" REMEDIATING: {stmt}")
print(f" -> NEW: {new_stmt}")
else:
updated_statements.append(stmt)

update_details = oci.identity.models.UpdatePolicyDetails(
description=policy.description,
statements=updated_statements,
version_date=policy.version_date
)

response = identity_client.update_policy(policy.id, update_details)
print(f" Policy updated: {response.data.name}")


if __name__ == "__main__":
main()

4. Remediation Strategy (What to Actually Change)

You must decide what restriction makes sense for your environment. Some common patterns:

  1. Limit to users (not instance principals / services):

    where request.principal.type = 'user'
  2. Exclude specific break‑glass / automation accounts:

    where request.user.name != 'break-glass-admin'
  3. Restrict by compartment:

    where target.compartment.id = 'ocid1.compartment.oc1..xxxx'
  4. Combine:

    where request.principal.type = 'user'
    and target.compartment.id = 'ocid1.compartment.oc1..xxxx'

Update the SAFE_WHERE_CLAUSE (or build more complex logic) in remediate_policy() to match your standard.


5. Safe Rollout Pattern

  1. Run with DRY_RUN = True and just log all risky statements.
  2. Export findings and decide per policy what the correct where conditions should be.
  3. Implement a mapping (e.g., dict by policy name or compartment) to apply the right where condition.
  4. Change DRY_RUN = False, run in a test tenancy/compartment.
  5. Then run in production.

If you tell me your preferred restriction model (for example: “all admin policies must be limited to request.principal.type = 'user' and only to two specific compartments”), I can adjust the sample remediation function to match that exactly.

Using Terraform
resource "oci_identity_policy" "iam_monitoring_admin_full_access" {
# Replace with your own values
compartment_id = "OCID_OF_TENANCY_OR_COMPARTMENT"
name = "IAM_MONITORING_ADMIN_POLICY"
description = "IAM Monitoring admins with constrained full access"

# This example keeps 'manage all-resources' but adds a WHERE condition,
# satisfying the control while reducing blast radius.
statements = [
# Replace IAM_MONITORING_ADMINS with your IAM group name
# Replace OCID_OF_ALLOWED_COMPARTMENT with the compartment to which you want to constrain admin actions
"Allow group IAM_MONITORING_ADMINS to manage all-resources in tenancy where target.compartment.id = 'OCID_OF_ALLOWED_COMPARTMENT'"
]
}

This change updates the policy in place (no resource replacement, but effective permissions change for the group).

To verify, terraform plan should show the existing oci_identity_policy with its statements argument changing from a manage all-resources in tenancy statement without a where clause to one that includes the where target.compartment.id = 'OCID_OF_ALLOWED_COMPARTMENT' condition.