> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# OCI IAM Admin Users Should Not Have API Signing Keys

### More Info:

Administrator users should not have API signing keys. API keys for admin accounts increase the risk of privilege escalation if keys are leaked or compromised

### Risk Level

Medium

### Address

Compliance, Security

### Compliance Standards

* APRA CPS 234 (Australia)
* AWS Startup Security Baseline
* AWS Well Architected Framework
* BSI C5 (Germany)
* Brazil LGPD
* CCPA / CPRA (California)
* CIS AWS
* CIS Critical Security Controls v8
* CMMC 2.0
* CSA Cloud Controls Matrix v4
* Cloudanix Best Practice
* DPDPA
* Digital Operational Resilience Act (EU)
* Essential 8
* FedRAMP
* GDPR
* HIPAA
* HITRUST CSF
* ISO 27001
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST
* NIST CSF
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* PCI
* Reserve Bank of India (RBI) Cyber Security Framework
* Reserve Bank of India (RBI) Master Direction – Information Technology Framework
* SOC2
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* UK NCSC Cyber Assessment Framework

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        Here’s how to remediate “OCI IAM Admin Users Should Not Have API Signing Keys” **using the OCI Console**, focusing on IAM and monitoring.

        ***

        ## 1. Identify Your Admin Users

        In OCI, “admin” users are typically those in groups that have powerful policies like `manage all-resources in tenancy`.

        1. In the OCI Console, go to:
           **Identity & Security → Identity → Users**
        2. For each user you consider an “admin”:
           * Click the **user name**.
           * Go to the **Groups** tab.
           * Note any group that has admin-level policies, e.g.:
             ```text theme={null}
             Allow group <GroupName> to manage all-resources in tenancy
             Allow group <GroupName> to manage users in tenancy
             ```
           * Any user in such groups should be treated as an admin for this control.

        If you’re using a dedicated `Administrators` or similar group, you can just list that group’s members:

        1. Go to **Identity & Security → Identity → Groups**
        2. Click your **admin group** (e.g., `Administrators`).
        3. Go to the **Members** tab and see all admin users.

        ***

        ## 2. Remove API Signing Keys from Admin Users

        For each admin user:

        1. Go to **Identity & Security → Identity → Users**.
        2. Click the **admin user**.
        3. Go to the **API Keys** tab.
        4. For **each API key** listed:
           * Click the **Actions (⋯)** menu next to the key.
           * Click **Delete**.
           * Confirm the deletion.

        Repeat this for all admin users that should not have API signing keys.

        ***

        ## 3. (Optional) Restrict Future Use of API Keys for Admins

        While OCI doesn’t have a direct toggle “disallow API keys,” you can reduce the risk by:

        * Using **federated SSO** (IdP) for admins so they don’t need local OCI user credentials.
        * Keeping admin access in **separate groups** and periodically auditing API keys for that group’s members (see section 4).

        ***

        ## 4. Set Up Monitoring / Detection in OCI (Cloud Guard)

        If you’re using **Cloud Guard** for IAM monitoring, you can detect this issue when it happens again.

        ### 4.1 Enable and Configure Cloud Guard (if not already)

        1. Go to **Identity & Security → Cloud Guard**.
        2. If not enabled, click **Enable Cloud Guard**.
        3. Choose:
           * **Target**: usually your **tenancy**.
           * **Detector recipes**: use the **Oracle-managed** recipes to start.

        ### 4.2 Use or Customize an IAM Detector

        1. In **Cloud Guard**, go to **Detector Recipes**.
        2. Select the **IAM Detector Recipe** associated with your target.
        3. Look for a detector rule related to:
           * “Users with high-privilege policies with API keys” or similar IAM/API-key related rule. Names may vary by tenancy/version.
        4. If available:
           * Make a **copy** of the Oracle-managed recipe (you cannot edit an Oracle-managed one directly).
           * In your **custom IAM detector recipe**, **enable** the relevant rule and set:
             * **Risk level** (e.g., High).
             * **Condition**: ensure it applies to:
               * Users in groups with admin-level privileges.
        5. Attach the **custom IAM detector recipe** to your **Cloud Guard target**.

        Now, whenever an admin user gets an API key, Cloud Guard will generate a **Problem**.

        ***

        ## 5. (Optional) Add Automatic or Guided Remediation (Responder)

        If you want Cloud Guard to help remediate:

        1. Go to **Cloud Guard → Responder Recipes**.
        2. Create a **custom responder recipe** (copy from Oracle-managed if needed).
        3. Add or enable a **responder rule** for the corresponding IAM detector:
           * Example action: **Notify** (via email) or automatic **Function** that removes keys (requires custom function; console-only deletion is manual).
        4. Attach the **custom responder recipe** to your **Cloud Guard target**.

        At minimum, set notifications so security/IAM admins are alerted when a new API key is added to an admin user.

        ***

        **Summary of console actions:**

        * Identify admin users (groups with `manage all-resources` or similar).
        * For each admin user: **Users → \[User] → API Keys → Delete all keys**.
        * Enable/Configure **Cloud Guard** IAM detector recipes to monitor for this condition going forward.
      </Accordion>

      <Accordion title="Using CLI">
        Below is a concise, CLI-focused way to remediate “OCI IAM Admin Users Should Not Have API Signing Keys” by:

        1. Identifying admin users.
        2. Listing their API signing keys.
        3. Deleting those keys.

        Assumptions:

        * You have OCI CLI configured (`oci setup config` done).
        * You have tenancy OCID available.
        * “Admin users” = users in groups that effectively grant `manage all-resources` on the tenancy or equivalent broad admin policies.

        ***

        ## 1. Identify Administrator Groups

        First, find groups with admin‑level policies.

        ```bash theme={null}
        TENANCY_OCID="<your-tenancy-ocid>"
        HOME_REGION="<home-region>"   # e.g. us-phoenix-1
        ```

        List policies in the root compartment (tenancy):

        ```bash theme={null}
        oci iam policy list \
          --compartment-id "$TENANCY_OCID" \
          --all \
          --query "data[].{name:name,statements:statements}" \
          --region "$HOME_REGION"
        ```

        Look for policy statements like:

        * `Allow group <GroupName> to manage all-resources in tenancy`
        * Or any equivalent that gives broad admin rights.

        Collect the group names you determine are “admin groups”. Suppose they are:

        ```bash theme={null}
        ADMIN_GROUPS=("Administrators" "SecurityAdmins")
        ```

        ***

        ## 2. List Users in Admin Groups

        For each admin group, list users:

        ```bash theme={null}
        for GROUP_NAME in "${ADMIN_GROUPS[@]}"; do
          echo "=== Group: $GROUP_NAME ==="
          GROUP_OCID=$(oci iam group list \
            --compartment-id "$TENANCY_OCID" \
            --name "$GROUP_NAME" \
            --query "data[0].id" \
            --raw-output \
            --region "$HOME_REGION")

          oci iam group list-users \
            --group-id "$GROUP_OCID" \
            --query "data[].{name:name,id:id}" \
            --all \
            --region "$HOME_REGION"
        done
        ```

        Capture the user OCIDs you want to check (admin users).

        You can also assemble an array:

        ```bash theme={null}
        ADMIN_USER_IDS=()

        for GROUP_NAME in "${ADMIN_GROUPS[@]}"; do
          GROUP_OCID=$(oci iam group list \
            --compartment-id "$TENANCY_OCID" \
            --name "$GROUP_NAME" \
            --query "data[0].id" \
            --raw-output \
            --region "$HOME_REGION")

          USER_IDS=$(oci iam group list-users \
            --group-id "$GROUP_OCID" \
            --query "data[].id" \
            --raw-output \
            --all \
            --region "$HOME_REGION")

          for U in $USER_IDS; do
            ADMIN_USER_IDS+=("$U")
          done
        done
        ```

        ***

        ## 3. List API Signing Keys for Each Admin User

        For each admin user, list their API keys:

        ```bash theme={null}
        for USER_ID in "${ADMIN_USER_IDS[@]}"; do
          echo "=== API keys for user: $USER_ID ==="
          oci iam user api-key list \
            --user-id "$USER_ID" \
            --query "data[].{keyId:key-id,fingerprint:fingerprint,timeCreated:\"time-created\"}" \
            --all \
            --region "$HOME_REGION"
        done
        ```

        Review this output. Decide which keys must be removed (typically all keys for admin users to satisfy the control).

        ***

        ## 4. Delete API Signing Keys for Admin Users

        To delete a specific key by its `key-id`:

        ```bash theme={null}
        oci iam user api-key delete \
          --user-id "<user-ocid>" \
          --fingerprint "<api-key-fingerprint>" \
          --force \
          --region "$HOME_REGION"
        ```

        If you’re satisfied removing all keys for all admin users, you can script it:

        ```bash theme={null}
        for USER_ID in "${ADMIN_USER_IDS[@]}"; do
          KEY_FPS=$(oci iam user api-key list \
            --user-id "$USER_ID" \
            --query "data[].fingerprint" \
            --raw-output \
            --all \
            --region "$HOME_REGION")

          for FP in $KEY_FPS; do
            echo "Deleting API key $FP for user $USER_ID"
            oci iam user api-key delete \
              --user-id "$USER_ID" \
              --fingerprint "$FP" \
              --force \
              --region "$HOME_REGION"
          done
        done
        ```

        ***

        ## 5. (Optional) Prevent Reintroduction

        To reduce recurrence (useful for IAM Monitoring / continuous compliance):

        * Use IAM policies and process controls so that:
          * Admins primarily use federation (IdP/SAML) or ephemeral tokens rather than user API keys.
        * Use Cloud Guard / IAM Monitoring recipes to detect:
          * Any API key creation for users in admin groups.
        * Hook Cloud Guard detector → responder rule that triggers automation (e.g., OCI Function or script) that:
          * Calls `oci iam user api-key delete` for admin users automatically.

        ***

        If you share how IAM Monitoring/Cloud Guard is currently reporting this finding (detector type / payload), I can give a CLI-based remediation script tailored to that detector output.
      </Accordion>

      <Accordion title="Using Python">
        Below are concrete steps and a Python example using the OCI SDK to:

        1. Find IAM users with **Admin privileges**
        2. Check if they have **API signing keys**
        3. Optionally **delete those API keys** (remediation)

        Assumptions:

        * “Admin users” = users who get `manage all-resources` on `tenancy` (or equivalent).
        * You have:
          * OCI tenancy with IAM enabled
          * API signing config set up locally (`~/.oci/config`) or environment variables
          * `oci` Python SDK installed: `pip install oci`

        ***

        ## 1. Define what “Admin user” means in your tenancy

        In OCI, privileges come from **policies**, not from user flags.\
        Common examples of Admin policies:

        ```text theme={null}
        Allow group Administrators to manage all-resources in tenancy
        Allow group tenancy-admins to manage all-resources in tenancy
        ```

        You will:

        1. List all policies in the root compartment.
        2. Parse their statements.
        3. Identify those granting:
           * `manage all-resources`
           * at `tenancy` (or root compartment)

        Then any user in the groups referenced by those policies is an “Admin user”.

        ***

        ## 2. Monitoring logic (high level)

        1. Get the tenancy OCID.
        2. List all **groups** and **policies** in the root compartment.
        3. From policies, extract groups that have `manage all-resources` on tenancy.
        4. For each such “Admin group”:
           * List group members (users).
        5. For each “Admin user”:
           * List user API keys.
           * If keys exist → **violation**.
        6. (Optional remediation) Delete the API keys for those users.

        ***

        ## 3. Python example: Detect & remediate

        > WARNING: Deleting API keys is destructive.\
        > First run in **read-only (dry-run)** mode and log what would be deleted.\
        > Only then enable the delete section.

        ```python theme={null}
        import oci
        import re

        # -----------------------
        # CONFIG
        # -----------------------
        PROFILE_NAME = "DEFAULT"  # profile in ~/.oci/config
        DRY_RUN = True            # True = detect only, False = actually delete keys

        # Regex patterns to identify admin-like policy statements
        ADMIN_ACTION_PATTERN = re.compile(r"\bmanage\s+all-resources\b", re.IGNORECASE)
        ADMIN_SCOPE_PATTERN = re.compile(r"\b(in\s+tenancy|in\s+compartment\s+tenancy)\b", re.IGNORECASE)

        def is_admin_policy_statement(stmt: str) -> bool:
            """
            Very simple parser: checks if a statement contains "manage all-resources"
            and is scoped "in tenancy" (or equivalent).
            E.g.: "Allow group Administrators to manage all-resources in tenancy"
            """
            return bool(ADMIN_ACTION_PATTERN.search(stmt) and ADMIN_SCOPE_PATTERN.search(stmt))

        def main():
            # 1. Set up config and clients
            config = oci.config.from_file("~/.oci/config", PROFILE_NAME)
            tenancy_ocid = config["tenancy"]

            identity_client = oci.identity.IdentityClient(config)

            # 2. Get root compartment (tenancy) details
            tenancy = identity_client.get_tenancy(tenancy_ocid).data
            root_compartment_id = tenancy.id  # same as tenancy OCID

            # 3. List all groups
            groups = oci.pagination.list_call_get_all_results(
                identity_client.list_groups,
                compartment_id=root_compartment_id
            ).data
            groups_by_name = {g.name: g for g in groups}

            # 4. List all policies in the tenancy (root compartment)
            policies = oci.pagination.list_call_get_all_results(
                identity_client.list_policies,
                compartment_id=root_compartment_id
            ).data

            admin_group_ocids = set()

            # 5. Identify admin groups from policies
            for policy in policies:
                for stmt in policy.statements:
                    if is_admin_policy_statement(stmt):
                        # Typical pattern: "Allow group <GroupName> to manage all-resources in tenancy"
                        # Extract group name after 'group'
                        m = re.search(r"Allow\s+group\s+([^\s]+)", stmt, re.IGNORECASE)
                        if not m:
                            continue
                        group_name = m.group(1)
                        group_obj = groups_by_name.get(group_name)
                        if group_obj:
                            admin_group_ocids.add(group_obj.id)

            if not admin_group_ocids:
                print("No admin groups detected based on policies.")
                return

            print("Admin groups detected:")
            for g in groups:
                if g.id in admin_group_ocids:
                    print(f"  - {g.name} ({g.id})")

            # 6. For each admin group, list members
            admin_user_ocids = set()

            for group_id in admin_group_ocids:
                memberships = oci.pagination.list_call_get_all_results(
                    identity_client.list_user_group_memberships,
                    compartment_id=root_compartment_id,
                    group_id=group_id
                ).data

                for m in memberships:
                    admin_user_ocids.add(m.user_id)

            if not admin_user_ocids:
                print("No users found in admin groups.")
                return

            print("\nAdmin users (candidates to check for API keys):")
            users = []
            for user_id in admin_user_ocids:
                user = identity_client.get_user(user_id).data
                users.append(user)
                print(f"  - {user.name} ({user.id})")

            # 7. For each admin user, list and (optionally) delete API keys
            print("\nChecking API keys for admin users...")
            for user in users:
                api_keys = oci.pagination.list_call_get_all_results(
                    identity_client.list_api_keys,
                    user_id=user.id
                ).data

                if not api_keys:
                    print(f"User {user.name} ({user.id}) has NO API signing keys.")
                    continue

                print(f"User {user.name} ({user.id}) has {len(api_keys)} API signing key(s):")
                for key in api_keys:
                    print(f"  - Key fingerprint: {key.fingerprint}, key_id: {key.key_id}")

                    if DRY_RUN:
                        print("    [DRY RUN] Would delete this key.")
                    else:
                        print("    Deleting this key...")
                        identity_client.delete_api_key(user_id=user.id, key_id=key.key_id)
                        print("    Deleted.")

            print("\nDone.")

        if __name__ == "__main__":
            main()
        ```

        ***

        ## 4. How to use this for monitoring

        1. **Deploy as a scheduled job**:
           * Use an OCI **Functions** function or a **Compute** instance + cron to run the script periodically.
        2. Run in **DRY\_RUN = True** to:
           * Log non-compliant users and keys.
           * Send alerts (e.g., via OCI Notifications, email, Slack, etc.).
        3. Once processes are agreed with security/operations:
           * Switch to `DRY_RUN = False` to automatically **remediate** by deleting keys.

        ***

        ## 5. Hardening / production tips

        * Tighten the `is_admin_policy_statement` logic to match your exact policies.
        * Maintain an **allowlist** of exceptions if needed.
        * Log actions (before/after) to Object Storage or a SIEM.
        * Run under a dedicated service principal (dynamic group + policy) with:
          ```text theme={null}
          Allow dynamic-group <DynGroupName> to manage users in tenancy
          Allow dynamic-group <DynGroupName> to manage groups in tenancy
          ```
          (Adjust least-privilege as needed – at minimum, it needs to list users, groups, policies, and manage API keys.)

        If you share your exact admin policy text, I can refine the parsing logic and permission policies.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        # Example: API keys are managed with oci_identity_api_key
        # Remediation: do NOT create api keys for admin users; remove/destroy any existing ones.

        resource "oci_identity_user" "admin_user" {
          # Replace with your admin user details
          compartment_id = var.tenancy_ocid
          name           = "ADMIN_USERNAME"        # <- substitute with the actual admin username
          description    = "Admin user without API signing keys"
          email          = "ADMIN_EMAIL@example.com"
        }

        # If you currently have something like this, it must be removed to remediate:
        # resource "oci_identity_api_key" "admin_api_key" {
        #   user_id     = oci_identity_user.admin_user.id
        #   key_value   = file("PATH_TO_PUBLIC_API_KEY_PEM")  # <- this creates an API signing key
        #   description = "API key for admin user"
        # }

        # Instead, only create API keys for NON-admin users, e.g.:
        resource "oci_identity_user" "non_admin_user" {
          compartment_id = var.tenancy_ocid
          name           = "NON_ADMIN_USERNAME"    # <- substitute with the actual non-admin username
          description    = "Non-admin user allowed to have API signing keys"
          email          = "NON_ADMIN_EMAIL@example.com"
        }

        resource "oci_identity_api_key" "non_admin_api_key" {
          user_id     = oci_identity_user.non_admin_user.id
          key_value   = file("PATH_TO_NON_ADMIN_PUBLIC_API_KEY_PEM") # <- path to the PEM public key
          description = "API key for non-admin user"
        }
        ```

        Removing or editing an `oci_identity_api_key` resource for an admin user will cause Terraform to delete that API key from OCI; this is irreversible and the corresponding private key will no longer work.

        If any API signing keys were created for admin users outside Terraform, they cannot be removed via Terraform; delete them in the OCI Console under Identity & Security → Users → *ADMIN\_USERNAME* → API Keys.

        For verification, `terraform plan` should show that all `oci_identity_api_key` resources associated with admin users are planned for destruction (or no longer exist in configuration), and only non-admin users retain `oci_identity_api_key` resources.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
