> ## 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 Database Passwords Should Be Rotated Periodically

### More Info:

Database user passwords should be rotated periodically (every 90 days). Regular password changes limit the impact of credential theft or brute-force attacks.

### 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
* DPDPA
* Digital Operational Resilience Act (EU)
* Essential 8
* HITRUST CSF
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST CSF
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* PCI
* 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 Database Passwords Should Be Rotated Periodically” for databases monitored via **OCI Database Management** using the OCI Console.

        You need to do two things:

        1. Rotate the password in the actual database
        2. Update the monitoring credential in OCI (preferably using an OCI Vault secret with rotation)

        ***

        ## 1. Rotate the password in the database itself

        Use your normal database procedure to change the password for the user that OCI uses for monitoring (often a low‑privileged monitoring user).

        For example (generic approach):

        * Connect to the DB as a privileged user (e.g., SYS or admin).
        * Run a password change:
          * For Oracle DB:
            ```sql theme={null}
            ALTER USER monitoring_user IDENTIFIED BY "NewStrongPassword!";
            ```
        * Confirm login works with the new password.

        Keep that new password ready for the next steps (or store it directly in OCI Vault).

        ***

        ## 2. Store the credential in OCI Vault (recommended)

        1. In OCI Console, go to **Identity & Security** → **Vault**.
        2. Select your **Vault** (or create one if needed).
        3. Under the vault, go to **Secrets** → **Create Secret**:
           * Name: e.g. `db-monitoring-password-<dbname>`.
           * Secret type: **Plaintext**.
           * Secret content: the new DB user password.
           * Click **Create Secret**.

        (Optional but recommended)\
        4\. Configure **Secret Rotation**:

        * In the secret’s details page, choose **Configure Rotation**.
        * Set:
          * Rotation interval (e.g., 30 days, 60 days).
          * A rotation function (OCI Function) if you want fully automatic rotation (function changes DB password and updates secret).
        * Save.

        If you don't have automated rotation implemented yet, you can still manually rotate: update DB password, then update the secret value each time.

        ***

        ## 3. Update Database Monitoring credentials in OCI

        ### A. For managed Oracle Databases (Database Management)

        1. In OCI Console, go to **Observability & Management** → **Database Management** → **Managed Databases**.
        2. Click your **database** that is being monitored.
        3. In the DB Management page, look for **Administration** → **Credentials** (or **Database Credentials** tab, depending on UI).
        4. Find the credential used for monitoring (often labeled as “DB Management credential”, “Monitoring credential”, or similar).
        5. Click **Edit / Update Credential** (or **Create Credential** if none exists):
           * **User name**: the monitoring user in the database.
           * **Password source**:
             * Preferred: select **Vault Secret** and choose the secret you created above.
             * Alternative: directly provide the new password (less secure; you’ll need to edit this manually each rotation).
        6. Save/Update the credential.

        Verify:
        7\. From the same DB Management page, run a quick check, for example:

        * Open **Performance Hub** or **Metrics**; confirm data is loading.
        * If there’s a **Test Connection** button for the credential, use it.

        ***

        ### B. For External Databases (if applicable)

        If you have **External Databases** added to Database Management:

        1. Go to **Observability & Management** → **Database Management** → **External Databases**.
        2. Select the specific external DB.
        3. Go to **Associated Credentials** / **Database Credentials**.
        4. Update the monitoring credential the same way:
           * Set the username.
           * Use the Vault secret (recommended) or direct password.
        5. Save and verify connectivity.

        ***

        ## 4. Establish a rotation process (policy)

        * If using Vault with automated rotation:
          * Ensure the rotation function updates both:
            1. The DB user password in the database.
            2. The secret value in OCI Vault.
        * If rotating manually:
          * Create a schedule (e.g., every 60–90 days):
            1. Change DB password.
            2. Update Vault secret (or OCI console credential) immediately.
            3. Validate Database Management connectivity.

        This satisfies the requirement that **database passwords used by OCI Database Monitoring are rotated periodically** and that the monitoring configuration is kept in sync through the OCI Console.
      </Accordion>

      <Accordion title="Using CLI">
        Here’s how to remediate “OCI Database Passwords Should Be Rotated Periodically” for databases monitored by OCI Database Management, using the OCI CLI.

        Assumptions:

        * Your database is already onboarded to OCI Database Management (Database Monitoring).
        * You have a database user (monitoring user) whose credentials are stored in OCI Database Management.
        * You can use the OCI CLI with appropriate permissions.

        ***

        ## 1. Identify the managed database and current DB credential

        1. List all managed databases:

        ```bash theme={null}
        oci db-management managed-database list
        ```

        2. Note the `id` of the target database (call it `MANAGED_DB_ID`).

        3. List existing DB credentials for that managed database:

        ```bash theme={null}
        oci db-management database-credentials list \
          --managed-database-id MANAGED_DB_ID
        ```

        You’ll see credential names/IDs (e.g., `DB_MONITORING_USER`).

        ***

        ## 2. Rotate the password inside the database

        You must first change the password in the actual database (this is NOT done by OCI):

        Example (Oracle DB, run as DBA via SQL\*Plus or similar):

        ```sql theme={null}
        ALTER USER monitoring_user IDENTIFIED BY "NewStr0ngP@ssw0rd!";
        ```

        Verify the user can log in with the new password.

        ***

        ## 3. Update the password stored in OCI (Database Management credential)

        Now update the credential that Database Management uses, via CLI:

        1. Put the new password into a local file (avoid shell history):

        ```bash theme={null}
        read -s NEW_PWD
        echo -n "$NEW_PWD" > /tmp/new_db_pwd.txt
        chmod 600 /tmp/new_db_pwd.txt
        unset NEW_PWD
        ```

        2. Update the database credential (replace placeholders):

        * `MANAGED_DB_ID` – from step 1.
        * `CRED_NAME` – name of the existing credential (or use its ID).
        * `DB_USER` – database username (e.g. `monitoring_user`).

        ```bash theme={null}
        oci db-management database-credentials update \
          --managed-database-id MANAGED_DB_ID \
          --credential-name CRED_NAME \
          --username DB_USER \
          --password file:///tmp/new_db_pwd.txt
        ```

        If your environment uses a different field name/flag, check:

        ```bash theme={null}
        oci db-management database-credentials update --help
        ```

        3. Clean up the temporary file:

        ```bash theme={null}
        shred -u /tmp/new_db_pwd.txt
        ```

        ***

        ## 4. Verify Database Monitoring is still working

        1. Test a Database Management connection:

        ```bash theme={null}
        oci db-management managed-database get \
          --managed-database-id MANAGED_DB_ID
        ```

        2. In the OCI Console (Database Management → Databases → \[your DB]) confirm:

        * Metrics are being collected.
        * Performance/monitoring pages load without authentication errors.

        ***

        ## 5. Automate periodic rotation (optional but recommended)

        1. Store DB credentials in OCI Vault (recommended).
        2. Create a script that:
           * Generates a new strong password.
           * Connects to DB and runs `ALTER USER ... IDENTIFIED BY ...`.
           * Updates the Vault secret (if used).
           * Calls `oci db-management database-credentials update` with the new password.
        3. Run the script on a schedule (cron, OCI DevOps pipeline, or external scheduler).

        Example cron entry (monthly):

        ```cron theme={null}
        0 2 1 * * /usr/local/bin/rotate_oci_db_monitoring_pwd.sh >> /var/log/oci-db-rotation.log 2>&1
        ```

        ***

        If you share the exact output of `oci db-management database-credentials update --help`, I can give you a fully concrete command tailored to your environment.
      </Accordion>

      <Accordion title="Using Python">
        Below is a practical way to **monitor and rotate Oracle Database passwords in OCI using Python**. This assumes you’re using **OCI Database (DB System/Autonomous)** and want to automate checks and rotation.

        ***

        ## 1. High-level approach

        1. Store DB passwords in **OCI Vault** (never hardcode them).
        2. Use **Python + OCI SDK** to:
           * Read the current password from Vault.
           * Connect to the database and check when passwords were last changed.
           * If older than your policy (e.g., 90 days), generate a new password.
           * Run `ALTER USER` in the DB to rotate the password.
           * Update the password in **OCI Vault**.
        3. Run this Python script on a schedule (e.g., OCI **Scheduled Task / Cron on Compute** / **Function**).

        ***

        ## 2. Prerequisites

        1. **OCI SDK for Python**

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

        2. **OCI config**\
           Create `~/.oci/config` or use instance principal. Example profile:

        ```ini theme={null}
        [DEFAULT]
        user=ocid1.user.oc1..xxxx
        fingerprint=xx:xx:xx:xx
        key_file=/path/to/oci_api_key.pem
        tenancy=ocid1.tenancy.oc1..xxxx
        region=us-ashburn-1
        ```

        3. **Vault setup**
           * Create a **Vault**, **Key**, and **Secret** in OCI.
           * Store the DB user password as a secret (e.g., `db-admin-password-secret`).
           * Give the script principal (user/instance) permissions to `SECRET-READ` and `SECRET-UPDATE`.

        4. **DB connectivity**
           * Have connection details: host/port/service\_name or wallet for Autonomous.
           * Open security lists/NSG for the machine running the script.

        ***

        ## 3. Core Python logic

        Below is an example script that:

        * Reads current password from OCI Vault
        * Connects to DB as a user (e.g., `ADMIN`)
        * Checks password age using `DBA_USERS`
        * Rotates password if older than `MAX_AGE_DAYS`
        * Updates password in Vault

        Adjust details to your environment (Autonomous vs DB System).

        ```python theme={null}
        import oci
        import cx_Oracle
        import datetime
        import random
        import string
        from base64 import b64decode, b64encode

        # ========= CONFIG =========
        OCI_PROFILE = "DEFAULT"
        VAULT_SECRET_OCID = "ocid1.vaultsecret.oc1..xxxx"  # DB password secret
        DB_USER = "APP_USER"
        DB_ADMIN_USER = "ADMIN"        # or SYS AS SYSDBA if needed
        MAX_AGE_DAYS = 90

        # DB connectivity
        DB_HOST = "mydb.subnet.vcn.oraclevcn.com"
        DB_PORT = 1521
        DB_SERVICE = "mydb_high"       # service name
        DB_ADMIN_PASSWORD_SECRET_OCID = "ocid1.vaultsecret.oc1..yyyy"  # if admin pwd also in Vault

        # ========= OCI CLIENTS =========
        config = oci.config.from_file("~/.oci/config", OCI_PROFILE)
        secrets_client = oci.secrets.SecretsClient(config)
        kms_vault_client = oci.vault.VaultsClient(config)
        secrets_mgmt_client = oci.secrets.SecretsManagementClient(config)

        def get_secret_value(secret_ocid: str) -> str:
            secret_bundle = secrets_client.get_secret_bundle(secret_ocid).data
            content = secret_bundle.secret_bundle_content
            if isinstance(content, oci.secrets.models.Base64SecretBundleContentDetails):
                return b64decode(content.content).decode("utf-8")
            else:
                raise RuntimeError("Unsupported secret content type")

        def update_secret_value(secret_ocid: str, new_value: str):
            encoded = b64encode(new_value.encode("utf-8")).decode("utf-8")
            details = oci.secrets.models.UpdateSecretDetails(
                secret_content=oci.secrets.models.Base64SecretContentDetails(
                    content_type="BASE64",
                    content=encoded
                )
            )
            secrets_mgmt_client.update_secret(secret_id=secret_ocid, update_secret_details=details)

        def make_conn(user, password):
            dsn = cx_Oracle.makedsn(DB_HOST, DB_PORT, service_name=DB_SERVICE)
            return cx_Oracle.connect(user=user, password=password, dsn=dsn, encoding="UTF-8")

        def get_password_age_days(conn, username):
            sql = """
                SELECT password_change_time
                FROM dba_users
                WHERE username = :uname
            """
            with conn.cursor() as cur:
                cur.execute(sql, uname=username.upper())
                row = cur.fetchone()
                if not row or not row[0]:
                    return None
                # row[0] is a datetime
                delta = datetime.datetime.now(row[0].tzinfo) - row[0]
                return delta.days

        def generate_password(length=20):
            chars = string.ascii_letters + string.digits + "!@#$%^&*()-_+=[]{}"
            return "".join(random.choice(chars) for _ in range(length))

        def rotate_db_password():
            # Get admin password for DB
            admin_pwd = get_secret_value(DB_ADMIN_PASSWORD_SECRET_OCID)

            # Connect as admin to check password age
            with make_conn(DB_ADMIN_USER, admin_pwd) as admin_conn:
                age_days = get_password_age_days(admin_conn, DB_USER)
                if age_days is None:
                    print(f"User {DB_USER} not found or password_change_time null.")
                    return

                print(f"Password age for {DB_USER}: {age_days} days")
                if age_days < MAX_AGE_DAYS:
                    print("Rotation not required.")
                    return

                # Generate new password
                new_pwd = generate_password()

                # Rotate password in DB
                sql = f"ALTER USER {DB_USER} IDENTIFIED BY \"{new_pwd}\""
                with admin_conn.cursor() as cur:
                    cur.execute(sql)
                    admin_conn.commit()
                print(f"Password rotated in DB for {DB_USER}")

                # Update app user password secret in Vault
                update_secret_value(VAULT_SECRET_OCID, new_pwd)
                print("Updated password in OCI Vault")

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

        **Notes:**

        * For **Autonomous DB**, you often use `ADMIN` and connect via wallet. Replace host/port/service with wallet `tnsnames.ora` and use `dsn="db_alias"` (after configuring `TNS_ADMIN`).
        * Ensure DB user has privileges (`ALTER USER` via admin account).

        ***

        ## 4. Integrate with Monitoring

        To align with “OCI Database Passwords Should Be Rotated Periodically”:

        1. **Schedule the script**:
           * On a Compute instance using `cron`, or
           * As an **OCI Function** triggered by **OCI Events + Scheduled** or **DevOps build pipeline**.

        2. **Optional: send metrics/alerts**:
           * After checking age, publish a custom metric to OCI Monitoring for `"password_age_days"`.
           * Set an OCI alarm to notify (email/Slack) when age > threshold.

        ***

        ## 5. Minimal Monitoring-Only Variant

        If you only want **monitoring** (detect, not rotate):

        * Remove the `ALTER USER` and `update_secret_value` parts.
        * Just:
          * Query `DBA_USERS.password_change_time`
          * Publish to OCI Monitoring or log to OCI Logging
          * Trigger Alarms if age > limit.

        If you tell me your exact DB type (Autonomous vs DB System) and where you run this (Function/Compute), I can adapt the script to that environment.
      </Accordion>

      <Accordion title="Using Terraform">
        Terraform cannot rotate OCI database user passwords or set a per-user rotation schedule on `oci_database_db_system` (or related resources); this is a runtime/operational task not exposed as a configurable argument in the OCI provider.

        To remediate:

        * Use the OCI Console or SQL\*Plus/SQL Developer to:
          * Enforce password aging in the Oracle database profile (e.g., `ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME 90;`).
          * Rotate application and admin user passwords manually or via an external secret manager/automation tool (e.g., OCI Vault + scripts), outside of Terraform.

        `terraform plan` will not show any password-rotation-related changes because no such arguments exist on the Terraform resources.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
