> ## 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 Instance Principals Should Be Used Instead Of API Keys

### More Info:

Instance principals should be used instead of API keys for compute workloads. Instance principals eliminate the need to store and rotate credentials, reducing the risk of key leakage.

### Risk Level

Medium

### Address

Compliance, Security

### Compliance Standards

* APRA CPS 234 (Australia)
* 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
* GDPR
* HIPAA
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* 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">
        Below are the steps to replace API key–based access with Instance Principals for an OCI IAM-based monitoring setup, using only the OCI Console wherever possible. This assumes monitoring code/agent is running on a Compute instance.

        ***

        ## 1. Identify what is currently using API Keys

        1. In the Console, go to **Identity & Security > Identity > Users**.
        2. Open the user whose API keys are being used for monitoring calls.
        3. Under **API Keys**, confirm keys exist and are used by the monitoring scripts/agent (e.g., in `~/.oci/config` on the instance).

        You will be replacing this access with instance principals for the instance(s) running the monitoring.

        ***

        ## 2. Create (or verify) a Dynamic Group for the Monitoring Instances

        1. In the Console, go to **Identity & Security > Identity > Dynamic Groups**.
        2. Click **Create Dynamic Group**.
        3. Give it a name like `monitoring-instances-dg`.
        4. Under **Matching Rule**, add a rule to include the specific instance(s) running monitoring. For example:
           * By compartment:
             ```text theme={null}
             ALL {instance.compartment.id = 'ocid1.compartment.oc1..xxxxx'}
             ```
           * Or by instance OCID:
             ```text theme={null}
             ANY {instance.id = 'ocid1.instance.oc1..aaaa', instance.id = 'ocid1.instance.oc1..bbbb'}
             ```
        5. Click **Create**.

        This dynamic group will represent the instance principals for those instances.

        ***

        ## 3. Create IAM Policy to Allow Instance Principals to Do the Same Monitoring Actions

        Determine what services the monitoring function needs (for example: Monitoring, Logging, Events, or others).

        1. In the Console, go to **Identity & Security > Identity > Policies**.
        2. Choose the compartment that will contain the policy (often the root compartment or the compartment containing your monitoring resources).
        3. Click **Create Policy**.
        4. Name it something like `monitoring-instance-principals-policy`.
        5. Add statements to allow the dynamic group to access required services.

        Examples (replace compartment and dynamic group names):

        * For Monitoring (read metrics / push custom metrics):
          ```text theme={null}
          Allow dynamic-group monitoring-instances-dg to use metrics in compartment <compartment-name>
          Allow dynamic-group monitoring-instances-dg to read metric-compartments in compartment <compartment-name>
          ```
        * For Logging (if your monitoring needs to write logs):
          ```text theme={null}
          Allow dynamic-group monitoring-instances-dg to use log-groups in compartment <compartment-name>
          Allow dynamic-group monitoring-instances-dg to use logs in compartment <compartment-name>
          ```
        * For Events or Alarms (if needed):
          ```text theme={null}
          Allow dynamic-group monitoring-instances-dg to use alarms in compartment <compartment-name>
          Allow dynamic-group monitoring-instances-dg to read metrics in compartment <compartment-name>
          ```

        Adjust to the minimum required verbs:

        * `read` (list/get)
        * `use` (read + create/update in some cases)
        * `manage` (full control, only if absolutely required).

        Click **Create** to save the policy.

        ***

        ## 4. Update the Monitoring Code/Agent on the Instance to Use Instance Principals

        This step is done on the instance itself (SSH), but doesn’t require console changes other than what you’ve already done.

        ### 4.1. If using OCI CLI or SDK in scripts

        Your current config file likely uses:

        ```ini theme={null}
        [DEFAULT]
        user=ocid1.user.oc1..
        fingerprint=xx:xx:...
        key_file=/path/to/private_key.pem
        tenancy=ocid1.tenancy.oc1..
        region=eu-frankfurt-1
        ```

        For Instance Principals:

        * You can either remove the profile OR create a new one and reference `--auth instance_principal`.

        Example for Python SDK:

        ```python theme={null}
        import oci

        signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
        monitoring_client = oci.monitoring.MonitoringClient(config={}, signer=signer)
        ```

        Example for CLI commands in scripts:

        ```bash theme={null}
        oci --auth instance_principal monitoring metric-data post ... 
        ```

        No API keys, user OCID, fingerprint, or private keys are needed when using `--auth instance_principal`.

        ### 4.2. If using the Monitoring/Management Agent

        * Ensure the Management Agent’s host (the compute instance) is part of the dynamic group you created.
        * The agent itself typically uses instance principals or resource principals automatically once IAM is correctly configured.
        * Verify by checking the agent configuration or documentation for your specific monitoring integration; ensure no user-level API keys are configured in the agent config files.

        ***

        ## 5. Test and Then Remove API Keys

        1. From the instance, run a simple call using instance principals (e.g., list metrics):

           ```bash theme={null}
           oci --auth instance_principal monitoring metric list --compartment-id <compartment-ocid> --namespace oci_computeagent
           ```

        2. Confirm:
           * Command succeeds.
           * Monitoring data/alarms/logs are still working as expected.

        3. When confirmed:

           * Go to **Identity & Security > Identity > Users**.
           * Open the user previously used.
           * Under **API Keys**, click the trash icon next to the now-unused API key(s).
           * Confirm deletion.

        This removes the misconfigured API key usage and leaves monitoring using secure Instance Principals.

        ***

        If you tell me which exact monitoring component you’re using (e.g., OCI Alarms + custom script, OCI Management Agent, Prometheus exporter, etc.), I can give you very specific commands/config lines to change.
      </Accordion>

      <Accordion title="Using CLI">
        Below are the practical steps to move from using user/API keys to using **Instance Principals** for OCI Monitoring via the **OCI CLI**.

        ***

        ## 1. Confirm Your Instance Has Instance Principals Enabled

        If your Compute instance was created normally with the default settings, instance principals are usually available automatically via the instance’s **instance metadata / resource principal token**. No extra agent is required.

        On the instance, verify the CLI can see a resource principal:

        ```bash theme={null}
        oci iam region list --auth instance_principal
        ```

        If this returns regions, instance principals are working. If it fails with auth errors, continue the next steps (dynamic group + policy).

        ***

        ## 2. Create a Dynamic Group for Your Instances

        You must group your instances in a **Dynamic Group** so IAM policies can be applied to them.

        ### 2.1. Get Your Compartment OCID (where the instance lives)

        ```bash theme={null}
        oci iam compartment list --all \
          --query "data[?\"name\"=='<YOUR_COMPARTMENT_NAME>'].id | [0]" \
          --raw-output
        ```

        Save this as `COMPARTMENT_OCID`.

        ### 2.2. Get Your Instance OCID (optional; or use conditions by compartment/tag)

        ```bash theme={null}
        oci compute instance list \
          --compartment-id "$COMPARTMENT_OCID" \
          --query "data[?\"display-name\"=='<YOUR_INSTANCE_NAME>'].id | [0]" \
          --raw-output
        ```

        Save as `INSTANCE_OCID` (if you want to target this specific instance).

        ### 2.3. Create Dynamic Group

        You can define the dynamic group by instance OCID:

        ```bash theme={null}
        oci iam dynamic-group create \
          --name oci-monitoring-dg \
          --description "Instances allowed to call Monitoring APIs" \
          --matching-rule "ANY {instance.id = '<INSTANCE_OCID>'}"
        ```

        Or by compartment:

        ```bash theme={null}
        oci iam dynamic-group create \
          --name oci-monitoring-dg \
          --description "Instances in compartment for monitoring" \
          --matching-rule "ANY {instance.compartment.id = '<COMPARTMENT_OCID>'}"
        ```

        Save the dynamic group OCID if needed:

        ```bash theme={null}
        oci iam dynamic-group list \
          --query "data[?\"name\"=='oci-monitoring-dg'].id | [0]" \
          --raw-output
        ```

        ***

        ## 3. Create IAM Policies to Allow Monitoring Operations

        You now allow this dynamic group (i.e., the instances) to use the Monitoring APIs.

        Determine your **tenancy OCID** (root compartment):

        ```bash theme={null}
        oci iam tenancy get --tenancy-id <TENANCY_OCID>
        ```

        Policies can be created in root or in a specific compartment.

        ### 3.1. Example Policy (Root Compartment)

        Replace `<TENANCY_NAME>` and use your dynamic group name.

        Create a policy file `monitoring-policy.txt`:

        ```text theme={null}
        Allow dynamic-group oci-monitoring-dg to read metrics in tenancy
        Allow dynamic-group oci-monitoring-dg to use metrics in tenancy
        Allow dynamic-group oci-monitoring-dg to manage alarms in tenancy
        ```

        Create the policy:

        ```bash theme={null}
        oci iam policy create \
          --name oci-monitoring-instance-principals-policy \
          --description "Allow instances to use Monitoring via instance principals" \
          --compartment-id <TENANCY_OCID> \
          --statements file://monitoring-policy.txt
        ```

        If your monitoring is limited to a specific compartment, adjust:

        ```text theme={null}
        Allow dynamic-group oci-monitoring-dg to read metrics in compartment <COMPARTMENT_NAME>
        Allow dynamic-group oci-monitoring-dg to use metrics in compartment <COMPARTMENT_NAME>
        Allow dynamic-group oci-monitoring-dg to manage alarms in compartment <COMPARTMENT_NAME>
        ```

        ***

        ## 4. Use OCI CLI with Instance Principals for Monitoring

        On the instance:

        ### 4.1. Stop Using User/API Key Profiles

        If your scripts currently use:

        ```bash theme={null}
        oci monitoring metric-data post --config-file ~/.oci/config --profile user1 ...
        ```

        you will switch to `--auth instance_principal` and omit user config entirely.

        ### 4.2. Example CLI Calls with Instance Principals

        **Post custom metrics:**

        ```bash theme={null}
        oci monitoring metric-data post \
          --auth instance_principal \
          --compartment-id "$COMPARTMENT_OCID" \
          --metric-data '[
            {
              "namespace": "custom_namespace",
              "resourceGroup": "my_resource_group",
              "compartmentId": "'"$COMPARTMENT_OCID"'",
              "name": "cpu_load",
              "dimensions": {"instanceId": "'"$INSTANCE_OCID"'"},
              "datapoints": [{"timestamp": "'$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")'" , "value": 0.5}]
            }
          ]'
        ```

        **List metrics:**

        ```bash theme={null}
        oci monitoring metric list \
          --auth instance_principal \
          --compartment-id "$COMPARTMENT_OCID" \
          --namespace custom_namespace
        ```

        **Manage alarms (example – list alarms):**

        ```bash theme={null}
        oci monitoring alarm list \
          --auth instance_principal \
          --compartment-id "$COMPARTMENT_OCID"
        ```

        Use `--auth instance_principal` in all monitoring-related OCI CLI commands executed **from the instance**.

        ***

        ## 5. Remove Old API Keys (Clean-Up)

        Once your monitoring scripts work with instance principals:

        1. Identify the user whose API key was used:
           ```bash theme={null}
           oci iam user list --all
           oci iam api-key list --user-id <USER_OCID>
           ```

        2. Delete the old API key:
           ```bash theme={null}
           oci iam api-key delete \
             --user-id <USER_OCID> \
             --fingerprint <API_KEY_FINGERPRINT> \
             --force
           ```

        This removes reliance on long‑lived user API keys and fully shifts the monitoring to **OCI IAM Instance Principals**.
      </Accordion>

      <Accordion title="Using Python">
        Below are concise, step‑by‑step instructions to move from API keys to Instance Principals for OCI IAM (for Monitoring) using Python.

        ***

        ### 1. Prerequisites

        * Your Python code runs on an OCI **Compute instance**.
        * The instance is in a **compartment** where you can create IAM policies and dynamic groups.
        * Python `oci` SDK installed:

        ```bash theme={null}
        pip install oci
        ```

        ***

        ### 2. Create a Dynamic Group

        1. In OCI Console, go to: **Identity & Security → Identity → Dynamic Groups → Create Dynamic Group**.

        2. Define:
           * **Name**: e.g., `dg-monitoring-instance`
           * **Description**: e.g., `Dynamic group for monitoring Python scripts using instance principals`

        3. In **Matching Rules**, target the instance(s) where your Python script runs. Example rule (by instance OCID):

           ```text theme={null}
           ANY {instance.id = 'ocid1.instance.oc1..<unique_id>'}
           ```

           or by compartment:

           ```text theme={null}
           ANY {instance.compartment.id = 'ocid1.compartment.oc1..<compartment_id>'}
           ```

        4. Click **Create**.

        ***

        ### 3. Create IAM Policies for the Dynamic Group

        1. In OCI Console, go to: **Identity & Security → Identity → Policies → Create Policy**.

        2. Select the **compartment** where Monitoring is used (or the root compartment if appropriate).

        3. Example policy statements (adjust compartments as needed):

           To **read metrics** (Monitoring):

           ```text theme={null}
           Allow dynamic-group dg-monitoring-instance to read metrics in compartment <TARGET_COMPARTMENT_NAME>
           ```

           To use **Monitoring Queries and Alarms** (if needed):

           ```text theme={null}
           Allow dynamic-group dg-monitoring-instance to read metric-data in compartment <TARGET_COMPARTMENT_NAME>
           Allow dynamic-group dg-monitoring-instance to inspect alarms in compartment <TARGET_COMPARTMENT_NAME>
           Allow dynamic-group dg-monitoring-instance to use metrics-family in compartment <TARGET_COMPARTMENT_NAME>
           ```

        4. Save the policy.

        ***

        ### 4. Remove API Key Usage from Python Code

        Remove any code that:

        * Builds config from `~/.oci/config` with user keys (e.g., `oci.config.from_file()` using `user`, `fingerprint`, `key_file`).
        * Explicitly sets API key details in code.

        ***

        ### 5. Use Instance Principals in the Python SDK

        In your Python script, use `InstancePrincipalsSecurityTokenSigner` instead of user API keys.

        Minimal example for Monitoring:

        ```python theme={null}
        import oci
        from oci.auth.signers import InstancePrincipalsSecurityTokenSigner

        # Use Instance Principals signer
        signer = InstancePrincipalsSecurityTokenSigner()

        # Replace with your region and compartment
        region = "us-ashburn-1"
        compartment_id = "ocid1.compartment.oc1..<compartment_id>"

        # Create Monitoring client with Instance Principals signer
        monitoring_client = oci.monitoring.MonitoringClient(
            config={"region": region},
            signer=signer
        )

        # Example: list metrics
        list_metrics_response = monitoring_client.list_metrics(
            compartment_id=compartment_id,
            list_metrics_details=oci.monitoring.models.ListMetricsDetails(
                namespace="oci_computeagent",  # example namespace
                name="CpuUtilization"          # example metric
            )
        )

        for metric in list_metrics_response.data:
            print(metric.name, metric.namespace)
        ```

        Key points:

        * `config` only needs a `region` when using Instance Principals.
        * Authentication is handled automatically via the instance’s identity.

        ***

        ### 6. Test on the Target Instance

        1. SSH into the instance that matches the dynamic group rule.
        2. Run your Python script.
        3. If you get authorization errors:
           * Confirm the instance is correctly in the **Dynamic Group** (matching rule is correct).
           * Verify **Policies** are in the correct compartment and reference the correct dynamic group name.
           * Make sure the script is using the **right region**.

        ***

        ### 7. Clean Up API Keys

        Once confirmed working:

        * Remove user API keys from:
          * OCI Console (user’s **API Keys** section) if no longer needed.
          * Any `~/.oci/config` entries that were only used for this script.
        * Rotate or disable old keys in accordance with your security policy.

        ***

        If you paste a short snippet of your current API‑key‑based Python code, I can show you the exact before/after using Instance Principals.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        # Use instance principals by putting compute instances in a dynamic group
        # and granting that dynamic group permissions on Monitoring.

        resource "oci_identity_dynamic_group" "MONITORING_INSTANCE_PRINCIPALS" {
          # OCID of the tenancy where the dynamic group is created
          compartment_id = var.TENANCY_OCID   # set to your tenancy OCID

          name        = "monitoring-instance-principals"
          description = "Instances allowed to call Monitoring using instance principals"

          # Example: all instances in a specific compartment
          matching_rule = "ALL {instance.compartment.id = '${var.MONITORED_COMPARTMENT_OCID}'}"
        }

        resource "oci_identity_policy" "MONITORING_INSTANCE_PRINCIPALS_POLICY" {
          # OCID of the tenancy (IAM policies always live at tenancy level)
          compartment_id = var.TENANCY_OCID   # set to your tenancy OCID

          name        = "monitoring-instance-principals-policy"
          description = "Allow monitoring instances dynamic group to use Monitoring APIs"

          # Replace NAMESPACE with your Monitoring service namespace if needed,
          # or keep generic "metrics" for all metrics in the compartment.
          statements = [
            "Allow dynamic-group ${oci_identity_dynamic_group.MONITORING_INSTANCE_PRINCIPALS.name} to use metrics in compartment ${var.MONITORED_COMPARTMENT_NAME}",
            "Allow dynamic-group ${oci_identity_dynamic_group.MONITORING_INSTANCE_PRINCIPALS.name} to use alarms in compartment ${var.MONITORED_COMPARTMENT_NAME}"
          ]
        }

        # VARIABLES TO DEFINE:
        # variable "TENANCY_OCID" {
        #   type        = string
        #   description = "OCID of the tenancy where IAM resources are created"
        # }
        #
        # variable "MONITORED_COMPARTMENT_OCID" {
        #   type        = string
        #   description = "OCID of the compartment containing the compute instances"
        # }
        #
        # variable "MONITORED_COMPARTMENT_NAME" {
        #   type        = string
        #   description = "Name of the compartment used in IAM policy text"
        # }

        ```

        This Terraform adds dynamic-group and policy resources only; existing instances and other IAM objects are not replaced. You must then configure your monitoring agents or applications on those instances to use instance principals (no API key in config or environment), which cannot be enforced directly via Terraform.

        To verify, `terraform plan` should show two resources to add (`+ oci_identity_dynamic_group.MONITORING_INSTANCE_PRINCIPALS` and `+ oci_identity_policy.MONITORING_INSTANCE_PRINCIPALS_POLICY`) and no changes to existing resources.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
