Skip to main content

OCI IAM Admin Group Should Be Protected From

More Info:​

A deny policy statement should prevent administrators from modifying the admin group membership. This prevents privilege escalation by ensuring no single admin can grant themselves additional access.

Risk Level​

Medium

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 is how to remediate the finding “OCI IAM Admin Group Should Be Protected From Self-Modification” using the OCI Console.

The goal:
No group that has permission to manage IAM groups/administrators should be able to change its own membership or policies directly.


1. Identify the High‑Privilege Admin Group​

  1. Sign in to the OCI Console as a tenancy administrator (or root user).
  2. Open the navigation menu → Identity & Security → Identity → Groups.
  3. Locate the group that is flagged (often called Administrators or similar).
    Note its exact name; assume it’s Administrators for the examples below.

2. Check Current Policies That Let It Manage Itself​

  1. Navigation menu → Identity & Security → Identity → Policies.
  2. Filter or search policies where the Subject (left side of the statement) includes the admin group, e.g.:
    • Allow group Administrators to manage all-resources in tenancy
    • Allow group Administrators to manage groups in tenancy
  3. For each such policy, verify whether it allows this group to:
    • manage groups
    • manage users
    • manage policies
    • manage tenancy or all-resources (which implicitly includes groups).

These are the policies that allow self-modification and must be adjusted.


3. Create a Separate IAM Admin Group (if you don’t already have one)​

If you don’t already have a dedicated group for IAM management that is different from the group you want to protect:

  1. Go to Identity & Security → Identity → Groups → Create Group.
  2. Name it something like IAM-Admins.
  3. Add at least one trusted admin user to this group:
    • Go to Identity & Security → Identity → Users.
    • Open a user you trust.
    • Under Groups, click Add User to Group → select IAM-Admins → Add.

This group will hold IAM management permissions instead of the protected admin group.


4. Move IAM Management Permissions Off the Protected Group​

4.1. Create a Policy for the IAM-Admins Group​

  1. Go to Identity & Security → Identity → Policies → Create Policy.
  2. Place it in the root compartment (so it can manage tenancy-level IAM).
  3. Give it a name like policy-iam-admins.
  4. In the Policy Builder, add statements such as:
Allow group IAM-Admins to manage groups in tenancy
Allow group IAM-Admins to manage policies in tenancy
Allow group IAM-Admins to manage users in tenancy

(Adjust to your requirements, but ensure this group can manage groups/users/policies.)

  1. Click Create.

4.2. Remove or Restrict IAM Management from the Original Admin Group​

For each policy that currently grants IAM powers to the protected group (e.g., Administrators):

  1. Open the policy.

  2. Click Edit Policy Statements.

  3. Either:

    • Remove statements such as:

      Allow group Administrators to manage groups in tenancy
      Allow group Administrators to manage all-resources in tenancy
      Allow group Administrators to manage users in tenancy
      Allow group Administrators to manage policies in tenancy
    • Or narrow them to exclude IAM resources (e.g., change to manage only specific non-IAM resources/compartments).

  4. Save the edited policy.

Result: the Administrators group (or equivalent) no longer has the ability to modify groups, users, or policies, including itself.


5. Optionally Add a Condition to Explicitly Protect the Group (Advanced)​

If you want more granular control (for example, other groups can manage groups but not the critical admin group):

  1. In the policy for IAM-Admins, you can use a condition to protect the Administrators group:

    Allow group IAM-Admins to manage groups in tenancy
    where any {target.group.name != 'Administrators'}
  2. Edit the IAM-Admins policy and replace the generic manage groups line with the conditional one above.

  3. Save the policy.

Now IAM-Admins can manage groups except the protected one; any change to the protected group can only be done by higher-trust mechanisms (e.g., root user or a break-glass identity).


6. Validate​

  1. Log in as a member of the protected admin group (e.g., Administrators).

  2. Confirm:

    • They cannot:
      • Add/remove users to/from their own group.
      • Edit policies that grant themselves IAM control.
    • But they can still perform whatever non-IAM tasks you intended for them (if any).
  3. Log in as a member of IAM-Admins:

    • Confirm they can manage other groups/policies as designed.

This configuration ensures that the OCI IAM admin group is protected from self-modification, satisfying the monitoring/control requirement while preserving an administrative path through a separate IAM-admin group or root identity.

Using CLI

Below is how to remediate the issue “OCI IAM Admin Group Should Be Protected From Self-Modification” using OCI CLI. The main idea is:

  • Remove “IAM‑management” permissions from your general admin group (typically Administrators)
  • Create a separate iam-admins group that manages IAM
  • Optionally script a check (monitoring) with OCI CLI to ensure the problem doesn’t return

1. Prerequisites​

Make sure OCI CLI is configured and you have a user with enough permission to modify policies and groups at the tenancy level.

oci setup config

You will also need the tenancy OCID:

TENANCY_OCID="<your_tenancy_ocid>"

2. Identify the “Administrators” group​

ADMIN_GROUP_OCID=$(
oci iam group list \
--compartment-id "$TENANCY_OCID" \
--all \
--query "data[?name=='Administrators'].id | [0]" \
--raw-output
)

echo "Administrators group OCID: $ADMIN_GROUP_OCID"

3. List all policies in the tenancy and find IAM‑related permissions for the admin group​

You’re looking for statements like:

  • Allow group Administrators to manage users in tenancy
  • Allow group Administrators to manage groups in tenancy
  • Allow group Administrators to manage policies in tenancy
  • Allow group Administrators to manage dynamic-groups in tenancy
  • etc.

List policies:

oci iam policy list \
--compartment-id "$TENANCY_OCID" \
--all \
--query 'data[].{id:id, name:name}' \
--output table

For each policy ID, inspect statements:

POLICY_ID="<policy_ocid_here>"

oci iam policy get --policy-id "$POLICY_ID" \
--query "data.{name:name, statements:statements}" \
--output json

Find and note the specific statements that give the Administrators group the ability to manage IAM resources (users, groups, policies, dynamic-groups, identity-providers, tag-namespaces, etc.).


4. Create a dedicated IAM admin group​

Create a new group for IAM management (example name: iam-admins):

IAM_ADMINS_GROUP=$(
oci iam group create \
--name "iam-admins" \
--description "Dedicated group to manage IAM (users, groups, policies) for the tenancy" \
--query "data.id" \
--raw-output
)

echo "iam-admins group OCID: $IAM_ADMINS_GROUP"

Add at least one trusted user to this group (replace <user_ocid>):

USER_OCID="<user_ocid_to_become_iam_admin>"

oci iam group add-user \
--group-id "$IAM_ADMINS_GROUP" \
--user-id "$USER_OCID"

5. Create new IAM policy for the iam-admins group​

Define a policy that gives iam-admins the IAM management powers you are about to remove from Administrators:

Example (adjust as needed):

oci iam policy create \
--compartment-id "$TENANCY_OCID" \
--name "iam-admins-policy" \
--description "Policy granting IAM management rights to iam-admins group" \
--statements '[
"Allow group iam-admins to manage users in tenancy",
"Allow group iam-admins to manage groups in tenancy",
"Allow group iam-admins to manage policies in tenancy",
"Allow group iam-admins to manage dynamic-groups in tenancy",
"Allow group iam-admins to manage federation-providers in tenancy",
"Allow group iam-admins to manage tag-namespaces in tenancy"
]'

6. Remove IAM-management permissions from the Administrators group​

For each policy that currently gives IAM‑management to Administrators, you must:

  1. Download current statements.
  2. Remove/adjust the lines giving IAM management to Administrators.
  3. Update the policy with the modified list.

6.1 Export current statements​

POLICY_ID="<policy_ocid_with_admin_iam_perms>"

oci iam policy get --policy-id "$POLICY_ID" \
--query "data.statements" \
--output json > policy-statements.json

Edit policy-statements.json locally and delete any line like:

"Allow group Administrators to manage users in tenancy",
"Allow group Administrators to manage groups in tenancy",
"Allow group Administrators to manage policies in tenancy",
"Allow group Administrators to manage dynamic-groups in tenancy",
"Allow group Administrators to manage tag-namespaces in tenancy",
...

Leave all other non‑IAM permissions intact.

6.2 Update the policy​

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

Repeat this for every affected policy.

After this, the Administrators group can no longer modify IAM (including itself); IAM changes are now only possible via iam-admins.


7. (Optional) Basic CLI-based monitoring script​

You can periodically check (e.g., via cron/OCI Functions) that no new policy grants IAM‑manage rights to Administrators.

Example check (Linux shell):

oci iam policy list \
--compartment-id "$TENANCY_OCID" \
--all \
--query "data[*].{name:name, id:id, statements:statements}" \
--output json > all-policies.json

grep -n '"Allow group Administrators to manage ' all-policies.json || echo "No self-modifying IAM policy found for Administrators."

You can refine the grep for specific IAM verbs/resources as needed and alert if any match is found.


These steps remove IAM self‑modification capability from the admin/default group and place it under a separate controlled group, satisfying the control “OCI IAM Admin Group Should Be Protected From Self-Modification,” and all changes are done using OCI CLI.

Using Python

Below are (1) the IAM remediation steps in OCI and (2) a Python example you can use for monitoring / detection.


1. Remediation concept in OCI​

Goal: Ensure your “Admin” group cannot modify its own membership, policies, or other IAM primitives that control itself.

Step 1 – Identify your admin group(s)​

Typical names:

  • Administrators
  • SecurityAdmins
  • Or any group that:
    • can manage all-resources in tenancy, or
    • can manage groups / manage policies / manage users.

In the Console:

  1. Go to Identity & Security → Domains (or Identity → Groups in classic).
  2. Open each candidate group (e.g., Administrators).
  3. Note the group name and OCID.

Create a new group to own IAM administration (and especially the admin group itself):

  1. In Identity → Groups, click Create group.
  2. Name it something like IAM-Security-Admins.
  3. Add only your highest-trust break-glass users.

This group will get exclusive ability to manage the admin group and IAM policies.

Step 3 – Adjust policies so Admin group cannot self‑modify​

Find all tenancy (root) policies that give your admin group broad permissions. Common risky statements:

Allow group Administrators to manage all-resources in tenancy
Allow group Administrators to manage groups in tenancy
Allow group Administrators to manage users in tenancy
Allow group Administrators to manage policies in tenancy

You want to:

  • Remove or narrow these for the Admin group.
  • Move IAM-management privileges to IAM-Security-Admins.
  • Optionally, use a condition to explicitly deny managing the Admin group.

Example safer pattern:

-- Give Admin group general admin, but NOT IAM:
Allow group Administrators to manage all-resources in tenancy
where target.service.name != 'identity'

-- Give IAM-Security-Admins full IAM control:
Allow group IAM-Security-Admins to manage identity-domains in tenancy
Allow group IAM-Security-Admins to manage users in tenancy
Allow group IAM-Security-Admins to manage groups in tenancy
Allow group IAM-Security-Admins to manage policies in tenancy

Or, if using conditional policies (Identity Domains / advanced conditions), you can be more explicit, e.g.:

Allow group Administrators to manage groups in tenancy
where target.group.name != 'Administrators'

The exact condition keys vary slightly by domain type; check OCI docs for “IAM policy conditions” to confirm target.group.name / target.iam.group.name in your environment.

Key point: the admin group should not have permission to:

  • manage groups on itself, or
  • manage policies that define its own power, or
  • broad manage all-resources including identity, unless constrained with conditions.

2. Python monitoring for “self‑modifiable” admin groups (OCI SDK)​

This script does detection (for monitoring). It scans tenancy policies and flags lines where an admin group has risky powers like manage all-resources, manage groups, or manage policies without any condition.

2.1. Prerequisites​

  1. Install OCI Python SDK:
    pip install oci
  2. Have a working OCI config (e.g., ~/.oci/config) with a profile that can read policies at tenancy level:
    [DEFAULT]
    user=ocid1.user.oc1..xxxx
    fingerprint=...
    key_file=~/.oci/oci_api_key.pem
    tenancy=ocid1.tenancy.oc1..xxxx
    region=us-phoenix-1

2.2. Python example​

import oci
import re

# ---------------- CONFIG ----------------
PROFILE_NAME = "DEFAULT"
# Admin-like groups you want to protect from self-modification:
PROTECTED_GROUPS = [
"Administrators",
"SecurityAdmins",
"TenantAdmins",
]
# ----------------------------------------


def is_risky_statement(stmt: str, group: str) -> bool:
"""
Heuristic: flags statements where a protected group can manage:
- all-resources
- groups
- policies
- users
without a 'where' clause restricting IAM or itself.
"""
normalized = " ".join(stmt.split()).lower()

# must have: "allow group <group>" or "allow dynamic-group <group>" etc.
if f"allow group {group.lower()}" not in normalized:
return False

# simple pattern checks
risky_verbs = [
"manage all-resources",
"manage groups",
"manage users",
"manage policies",
"manage identity-domains",
]
has_risky_verb = any(rv in normalized for rv in risky_verbs)
if not has_risky_verb:
return False

# If there is a WHERE clause, you might want a deeper parse;
# here we treat ANY condition as "less risky", but you can tighten this.
has_condition = " where " in normalized

# Flag when powerful AND no condition
return has_risky_verb and not has_condition


def main():
config = oci.config.from_file(profile_name=PROFILE_NAME)
identity = oci.identity.IdentityClient(config)

tenancy_id = config["tenancy"]

print(f"Scanning policies in tenancy {tenancy_id} ...")

# List all policies in the tenancy (root compartment)
list_policies_response = oci.pagination.list_call_get_all_results(
identity.list_policies,
compartment_id=tenancy_id
)

risky_findings = []

for policy in list_policies_response.data:
for stmt in policy.statements:
for group in PROTECTED_GROUPS:
if is_risky_statement(stmt, group):
risky_findings.append({
"policy_name": policy.name,
"policy_id": policy.id,
"compartment_id": policy.compartment_id,
"group": group,
"statement": stmt,
})

if not risky_findings:
print("No risky self-modification statements found for protected groups.")
return

print("\nRISKY STATEMENTS FOUND:")
for f in risky_findings:
print("-------------------------------------------------")
print(f"Policy Name : {f['policy_name']}")
print(f"Policy OCID : {f['policy_id']}")
print(f"Compartment : {f['compartment_id']}")
print(f"Group : {f['group']}")
print(f"Statement : {f['statement']}")
print("-------------------------------------------------")
print(f"Total findings: {len(risky_findings)}")

# Here you could:
# - push to monitoring system (e.g., send to OCI Logging, Splunk, etc.)
# - send an email or Slack alert
# - write to a file for compliance reports


if __name__ == "__main__":
main()

2.3. How to use this for continuous monitoring​

  • Run this script on a schedule (e.g., with:
    • OCI Functions + Events,
    • a cron job on a bastion / CI runner,
    • or an OCI DevOps pipeline).
  • When risky_findings is non-empty:
    • Notify security / cloud team.
    • Manually update the flagged policies as described in Section 1.

If you share a sample of your current policy statements for the admin group, I can adjust the detection logic and give an exact “before/after” policy example.

Using Terraform
resource "oci_identity_policy" "IAM_ADMIN_GROUP_PROTECTION" {
compartment_id = "TENANCY_OCID" # Replace with your tenancy OCID (the root compartment)
name = "ADMIN_GROUP_PROTECTION_POLICY" # Replace with your desired policy name
description = "Prevent the Administrators group from modifying its own membership"

statements = [
# Add this deny rule alongside any existing allow rules that grant admin privileges.
# If you already manage an IAM policy for admins, add this statement into that resource's `statements` list.
"Deny group Administrators to manage groups in tenancy where target.group.name = 'Administrators'",
]

# Optional: pin to the date when policy language was valid
# version_date = "2024-01-01"
}

This change is in-place and does not force replacement of the policy resource; it only updates its statements.

To verify, terraform plan should show the oci_identity_policy.IAM_ADMIN_GROUP_PROTECTION resource with an updated statements attribute including the new Deny group Administrators to manage groups in tenancy where target.group.name = 'Administrators' entry and no resource replacement (-/+ or +/-) for this policy.