> ## 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 Encryption Vaults Should Use Private Endpoints

### More Info:

OCI Vaults should use private endpoints (VIRTUAL\_PRIVATE vault type). Private endpoints ensure key management operations never traverse the public internet, reducing exposure to interception.

### Risk Level

Medium

### Address

Compliance, Security

### Compliance Standards

* APRA CPS 234 (Australia)
* AWS Well Architected Framework
* 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
* GDPR
* 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
* PCI
* 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">
        To remediate “OCI Encryption Vaults Should Use Private Endpoints” using the OCI Console, you need to ensure that each vault is created/available via a **virtual private endpoint** in a **VCN subnet** (not via a public endpoint).

        Below are step‑by‑step instructions.

        ***

        ## 1. Identify Vaults Using Public Endpoints

        1. Sign in to the **OCI Console**.
        2. In the top‑left hamburger menu, go to:\
           **Identity & Security → Vault**.
        3. Select the **Compartment** where your vaults reside.
        4. For each vault:
           * Click the vault name.
           * On the vault details page, check the **Endpoint Type**:
             * If it shows **Public endpoint**, this is non‑compliant.
             * If it shows a **Private endpoint** (with associated VCN/subnet), it’s already compliant.

        You cannot convert an existing public vault to private; you must create a new one with a private endpoint and migrate usage.

        ***

        ## 2. Prepare Network for Private Endpoints

        You need a VCN and private subnet where the vault private endpoint will live.

        1. In the Console: **Networking → Virtual Cloud Networks**.
        2. Ensure you have:
           * A **VCN** in the same region as the vault.
           * A **private subnet** (no public IPs) with:
             * Appropriate **route table** (traffic to Vault goes through OCI Service Gateway or within OCI backbone).
             * Appropriate **security lists / NSG rules** to allow traffic from your workloads to the private endpoint.
        3. If you don’t have a suitable subnet:
           * Create one under the VCN:
             * **Create Subnet** → choose **Private** and configure CIDR/security accordingly.

        ***

        ## 3. Create a New Vault with a Private Endpoint

        1. Go to **Identity & Security → Vault**.
        2. Click **Create Vault**.
        3. Fill in:
           * **Name**: e.g., `app-prod-vault-private`.
           * **Compartment**: select appropriate.
        4. Under **Type**:
           * Choose **Default** vault type (or **Virtual private vault** if your policy requires it).
        5. Under **Endpoint Type** (or similar section, name may vary slightly by console version):
           * Select **Private endpoint**.
        6. Configure the private endpoint:
           * **VCN**: choose the VCN prepared in step 2.
           * **Subnet**: choose the private subnet.
           * (Optional) Select **Network Security Groups** for tighter control, if required.
        7. Click **Create Vault**.

        The vault will be provisioned with a private endpoint IP in that subnet.

        ***

        ## 4. Recreate Keys and Secrets in the New Vault

        For encryption monitoring to remain accurate and to keep systems working, you must recreate current crypto material in the new private‑endpoint vault.

        1. Open the new vault.
        2. Under **Resources**, create new keys:
           * Click **Master Encryption Keys → Create Key**.
           * Configure **Key Shape, Algorithm, Key Size**, and **Protection Mode** to match the old key as closely as possible.
        3. If you use **Secrets**:
           * Go to **Secrets → Create Secret**.
           * Copy values from old secrets or re‑generate them securely.
        4. If you used **Key Version** pinning in clients, plan to reference the new keys/versions accordingly.

        ***

        ## 5. Update All Dependent Services and Applications

        You must repoint every service that uses the old (public endpoint) vault to use the new (private endpoint) vault and keys.

        Typical locations to update:

        * **Block Volumes / Boot Volumes / File Storage / Object Storage**:
          * For volumes or buckets using a customer‑managed key:
            * Go to each resource in the Console.
            * Edit encryption settings (if supported) to use the new key in the private‑endpoint vault.
            * If OCI doesn’t let you change the CMK in‑place, you may need to create new resources encrypted with the new key and migrate data.
        * **Databases (ADB, DB Systems)**:
          * Check the **Encryption Key** / **Customer-Managed Key** section.
          * Point to the new key in the private vault (if the service supports key switch).
        * **OCI Logging, Streaming, Functions, OKE, etc.**:
          * For any service configured with a customer‑managed KMS key, update it to reference the new key OCID (from the new vault).
        * **Custom Applications**:
          * Update configuration (environment variables, config files, or Vault SDK usage) to:
            * Use the **new key OCID** and/or **secret OCID**.
            * Ensure the application accesses the vault from within the VCN or over a private connection (FastConnect / VPN), not via public internet.

        Verify your monitoring/“Encryption Monitoring” layer now tracks the new vault and keys (e.g., check dashboards, metrics, and alerts for the new vault OCID).

        ***

        ## 6. Validate Private Connectivity

        From a compute instance or workload in the same VCN:

        1. Ensure it’s in a subnet that can route to the vault’s private endpoint (subnet / NSG rules allow traffic).
        2. Run an application test that performs:
           * `Encrypt`, `Decrypt`, `Sign`, `Verify`, or `Get Secret` calls through the OCI SDK or CLI using the new vault/key/secret OCIDs.
        3. Confirm:
           * No public internet is required (no public IP necessity, traffic stays within VCN/Service Gateway).
           * Your **network flow logs** / **VPC Flow Logs** (if enabled) show traffic only through private paths.

        ***

        ## 7. Decommission Old Public-Endpoint Vaults

        After everything uses the new private‑endpoint vault and you’ve validated:

        1. In **Identity & Security → Vault**, open the old (public) vault.
        2. Ensure:
           * No keys or secrets are referenced by any live resources (double‑check services and application configs).
        3. Optionally **schedule key deletion** (or rotate and disable usage) as per your retention policy.
        4. Once sure nothing uses it:
           * Delete keys and secrets (if your policy allows).
           * Delete the vault:
             * On the vault details page, choose **Delete**.
             * Confirm.

        ***

        ## 8. Ensure Continuous Monitoring Shows Compliance

        1. Re‑run your **OCI Security / Compliance / Encryption Monitoring** checks:
           * If using OCI Cloud Guard / Security Zones / custom monitoring, verify the “Vaults should use private endpoints” rule is now passing for the relevant compartments.
        2. Confirm that **all new vaults** are created going forward with:
           * **Endpoint type: Private**.
           * Optionally enforce via:
             * **Security Zones** with policies that disallow public KMS endpoints.
             * **IAM / Governance** standards and provisioning templates (e.g., Terraform with private endpoints only).

        ***

        If you provide details of one specific vault (whether it is “default” or “virtual private vault,” region, and what resources use its keys), I can give a targeted sequence of exactly what to click and in what order for that scenario.
      </Accordion>

      <Accordion title="Using CLI">
        In OCI, a vault’s endpoint type (PUBLIC vs PRIVATE) **cannot be changed after creation**. To remediate, you must:

        1. **Identify public vaults**
        2. **Create replacement vaults with PRIVATE endpoints in the correct VCN/subnet**
        3. **Recreate/migrate keys**
        4. **Point apps/services to the new vault/key OCIDs**
        5. **Schedule deletion of the old public vaults**

        Below are concise, CLI-focused steps.

        ***

        ## 1. Identify vaults using PUBLIC endpoints

        ```bash theme={null}
        COMPARTMENT_OCID="<compartment-ocid>"

        oci kms management vault list \
          --compartment-id "$COMPARTMENT_OCID" \
          --all \
          --query "data[?\"endpoint-type\"=='PUBLIC'].{name:\"display-name\", id:id, endpoint:\"management-endpoint\"}" \
          --output table
        ```

        Any rows returned are non-compliant vaults.

        ***

        ## 2. Create a vault with a PRIVATE endpoint

        You need:

        * VCN OCID
        * Subnet OCID (in that VCN, with correct routing to your workloads)

        ```bash theme={null}
        NEW_VAULT_NAME="my-private-vault"
        VCN_ID="<vcn-ocid>"
        SUBNET_ID="<subnet-ocid>"
        COMPARTMENT_OCID="<compartment-ocid>"

        oci kms management vault create \
          --compartment-id "$COMPARTMENT_OCID" \
          --display-name "$NEW_VAULT_NAME" \
          --vault-type DEFAULT \
          --endpoint-type PRIVATE \
          --network-id "$SUBNET_ID" \
          --wait-for-state ACTIVE \
          --query "data.{id:id,\"management-endpoint\":\"management-endpoint\",name:\"display-name\"}" \
          --output table
        ```

        Note: `--network-id` should be the **subnet OCID** for a PRIVATE endpoint.

        ***

        ## 3. Recreate/migrate keys into the new private vault

        List keys in the old (public) vault:

        ```bash theme={null}
        OLD_VAULT_ID="<public-vault-ocid>"

        oci kms management key list \
          --compartment-id "$COMPARTMENT_OCID" \
          --vault-id "$OLD_VAULT_ID" \
          --all \
          --query "data[].{name:\"display-name\", id:id}" \
          --output table
        ```

        For each key, create a new key in the private vault (no direct “move”; you must recreate):

        ```bash theme={null}
        NEW_VAULT_ID="<private-vault-ocid>"
        KEY_NAME="app-encryption-key"
        ALGORITHM="AES"
        LENGTH="32"  # 32 bytes = 256-bit key, adjust per your policy

        oci kms management key create \
          --compartment-id "$COMPARTMENT_OCID" \
          --vault-id "$NEW_VAULT_ID" \
          --display-name "$KEY_NAME" \
          --protection-mode HSM \
          --key-shape "{\"algorithm\":\"$ALGORITHM\",\"length\":$LENGTH}" \
          --wait-for-state ACTIVE \
          --query "data.{id:id,\"display-name\":\"display-name\"}" \
          --output table
        ```

        If you must preserve an existing key’s material, use **imported keys**:

        1. Get an import job in the new vault (`oci kms management import-job create`).
        2. Wrap key material and import using `oci kms management key import-key`.

        (Only do this if compliance allows key export/import.)

        ***

        ## 4. Update applications and OCI services to use the new key/vault

        * For each workload (DB, Object Storage, Block Volumes, Functions, custom apps, etc.), change:
          * Vault OCID (if used directly)
          * Key OCID to the new key in the PRIVATE vault
        * This change is typically in:
          * Service-specific KMS configuration (e.g., DB system TDE config)
          * Application configuration / environment variables
          * Terraform/Ansible/IaC definitions

        Verify encryption and normal operation after changes.

        ***

        ## 5. Disable and then delete the old public vault

        ### Disable and schedule deletion of old keys

        ```bash theme={null}
        OLD_KEY_ID="<old-key-ocid>"

        # Disable key
        oci kms management key update \
          --key-id "$OLD_KEY_ID" \
          --state DISABLED

        # Schedule deletion (example: 30 days)
        oci kms management key schedule-deletion \
          --key-id "$OLD_KEY_ID" \
          --time-of-deletion "2026-08-24T00:00:00+00:00"
        ```

        Repeat for all keys in the old vault once you are certain they are no longer used.

        ### Schedule deletion of the old vault

        ```bash theme={null}
        OLD_VAULT_ID="<public-vault-ocid>"

        oci kms management vault schedule-deletion \
          --vault-id "$OLD_VAULT_ID" \
          --time-of-deletion "2026-08-24T00:00:00+00:00"
        ```

        ***

        ## 6. (Optional) Confirm compliance via CLI

        Re-run the public-vault check:

        ```bash theme={null}
        oci kms management vault list \
          --compartment-id "$COMPARTMENT_OCID" \
          --all \
          --query "data[?\"endpoint-type\"=='PUBLIC']" \
          --output table
        ```

        The table should now be empty for compartments in scope of your “Encryption Monitoring” rule.

        If you share your current vault and key structure (OCIDs, counts, which services use them), I can tailor exact CLI sequences and sample `time-of-deletion` values for your environment.
      </Accordion>

      <Accordion title="Using Python">
        In OCI, a Vault’s endpoint type (PUBLIC vs PRIVATE) **cannot be changed after creation**.\
        So “remediation” means:

        1. Find all PUBLIC vaults.
        2. Create equivalent PRIVATE vaults in a subnet with private access.
        3. Re‑point any dependent resources (keys, services using those keys) to the new vaults.
        4. (Optionally) schedule deletion of old PUBLIC vaults.

        Below is how to do this with the OCI Python SDK for “encryption monitoring” remediation.

        ***

        ## 1. Prerequisites

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

        `~/.oci/config`:

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

        Or use instance/principals config if running on OCI compute/functions.

        ***

        ## 2. Identify Vaults Using PUBLIC Endpoints

        ```python theme={null}
        import oci

        config = oci.config.from_file()  # or from_file("~/.oci/config", "PROFILE")
        kms_management = oci.key_management.KmsManagementClientCompositeOperations
        vault_client = oci.key_management.KmsManagementClient
        kms_vault_client = oci.key_management.KmsVaultClient(config)

        compartment_id = "<OCID_OF_ROOT_OR_TARGET_COMPARTMENT>"

        def list_public_vaults(compartment_id):
            public_vaults = []
            response = oci.pagination.list_call_get_all_results(
                kms_vault_client.list_vaults,
                compartment_id=compartment_id
            )
            for v in response.data:
                if v.endpoint_type == "PUBLIC":   # values: PUBLIC | PRIVATE
                    public_vaults.append(v)
            return public_vaults

        public_vaults = list_public_vaults(compartment_id)
        for v in public_vaults:
            print(f"PUBLIC vault: {v.display_name} ({v.id}) in {v.lifecycle_state}")
        ```

        ***

        ## 3. Ensure You Have a VCN/Subnet for Private Endpoints

        The private vault must be reachable in a private subnet.\
        If you already have a VCN + private subnet, just note the subnet OCID.

        Otherwise (one‑time setup, not per vault):

        ```python theme={null}
        core_client = oci.core.VirtualNetworkClient(config)

        # 3.1 Create VCN
        create_vcn_details = oci.core.models.CreateVcnDetails(
            cidr_block="10.0.0.0/16",
            compartment_id=compartment_id,
            display_name="kms-private-vcn",
            dns_label="kmsvcn"
        )
        vcn = core_client.create_vcn(create_vcn_details).data
        oci.wait_until(
            core_client, core_client.get_vcn(vcn.id), 'lifecycle_state', 'AVAILABLE'
        )

        # 3.2 Create Subnet
        create_subnet_details = oci.core.models.CreateSubnetDetails(
            compartment_id=compartment_id,
            vcn_id=vcn.id,
            cidr_block="10.0.1.0/24",
            display_name="kms-private-subnet",
            dns_label="kmspriv",
            prohibit_public_ip_on_vnic=True
        )
        subnet = core_client.create_subnet(create_subnet_details).data
        oci.wait_until(
            core_client, core_client.get_subnet(subnet.id), 'lifecycle_state', 'AVAILABLE'
        )

        subnet_id = subnet.id
        print("Subnet for private vaults:", subnet_id)
        ```

        If you already have a private subnet, just set:

        ```python theme={null}
        subnet_id = "<OCID_OF_EXISTING_PRIVATE_SUBNET>"
        ```

        ***

        ## 4. Create a PRIVATE Vault (Replacement for Each PUBLIC Vault)

        Endpoint type is set at creation time:

        ```python theme={null}
        from oci.key_management import KmsVaultClient

        kms_vault_client = KmsVaultClient(config)

        def create_private_vault(compartment_id, display_name, subnet_id):
            create_vault_details = oci.key_management.models.CreateVaultDetails(
                compartment_id=compartment_id,
                display_name=display_name,
                vault_type="DEFAULT",   # or VIRTUAL_PRIVATE for HSM when applicable
                encryption_algorithm="AES_256_GCM",  # or appropriate default
                endpoint_type="PRIVATE",
                subnet_id=subnet_id
            )
            vault = kms_vault_client.create_vault(create_vault_details).data
            oci.wait_until(
                kms_vault_client,
                kms_vault_client.get_vault(vault.id),
                'lifecycle_state',
                'ACTIVE'
            )
            return vault

        new_vaults = {}
        for v in public_vaults:
            new_name = v.display_name + "-private"
            new_vault = create_private_vault(v.compartment_id, new_name, subnet_id)
            new_vaults[v.id] = new_vault.id
            print(f"Created PRIVATE vault {new_name}: {new_vault.id} (replaces {v.id})")
        ```

        ***

        ## 5. Migrate Keys from Old PUBLIC Vault to New PRIVATE Vault

        You cannot move keys directly between vaults; you must:

        * Export key material from the old vault (if exportable).
        * Import into a new key in the private vault.
        * Update dependent services to use the new key OCID.

        Example (simplified, exportable keys only):

        ```python theme={null}
        import base64
        from oci.key_management import KmsManagementClient
        from oci.key_management import KmsCryptoClient

        def get_management_client(vault):
            return KmsManagementClient(
                config,
                service_endpoint=vault.management_endpoint
            )

        def list_keys_in_vault(vault):
            mgmt_client = get_management_client(vault)
            keys = []
            resp = oci.pagination.list_call_get_all_results(
                mgmt_client.list_keys,
                compartment_id=vault.compartment_id
            )
            keys.extend(resp.data)
            return keys

        def export_key_material(mgmt_client, key_id):
            # NOTE: In real env, use a secure wrapping key, proper export flow.
            # Here we just sketch invocation.
            export_details = oci.key_management.models.ExportKeyDetails(
                key_id=key_id,
                # supply correct parameters: algorithm, public_key, etc.
            )
            export_resp = mgmt_client.export_key(export_details)
            return export_resp.data.encrypted_key

        def import_key_material(new_vault, encrypted_key_material):
            mgmt_client = get_management_client(new_vault)
            import_details = oci.key_management.models.ImportKeyDetails(
                # Required fields: wrapped_import_key, algorithm, etc.
                # This is just a schematic example.
            )
            new_key = mgmt_client.import_key(import_details).data
            return new_key

        for old_vault in public_vaults:
            print(f"Migrating keys for vault {old_vault.display_name}")
            new_vault_id = new_vaults[old_vault.id]
            new_vault = kms_vault_client.get_vault(new_vault_id).data

            old_mgmt_client = get_management_client(old_vault)
            keys = list_keys_in_vault(old_vault)

            key_mapping = {}  # old_key_id -> new_key_id

            for k in keys:
                # If key is not exportable, you must create a new key and re-encrypt data manually.
                encrypted_material = export_key_material(old_mgmt_client, k.id)
                new_key = import_key_material(new_vault, encrypted_material)
                key_mapping[k.id] = new_key.id
                print(f"Key {k.display_name}: {k.id} -> {new_key.id}")

            # You need to store key_mapping somewhere (DB, file) to later update applications/services.
        ```

        Because export/import is very specific to your setup (key algorithms, wrapping keys, compliance constraints), in practice you will:

        * For **non‑exportable keys**:\
          Create new keys in the private vault and re‑encrypt application data, DB tablespaces, object storage, etc., with the new keys.

        * For **OCI native services** (block volumes, database, object storage, etc.):\
          Use service‑specific API calls to change the KMS key ID to the new key in the private vault.

        ***

        ## 6. Update Dependent Services to Use the New PRIVATE Vault Keys

        For each service that uses an old key OCID, call its update API with the new key OCID.\
        Examples (sketches):

        **Block Volume example:**

        ```python theme={null}
        block_client = oci.core.BlockstorageClient(config)
        volume_id = "<VOLUME_OCID>"
        new_kms_key_id = "<NEW_KEY_OCID_IN_PRIVATE_VAULT>"

        update_details = oci.core.models.UpdateVolumeDetails(
            kms_key_id=new_kms_key_id
        )
        block_client.update_volume(volume_id, update_details)
        ```

        **Object Storage Bucket example:**

        ```python theme={null}
        object_storage = oci.object_storage.ObjectStorageClient(config)
        ns = object_storage.get_namespace().data
        bucket_name = "<BUCKET_NAME>"
        new_kms_key_id = "<NEW_KEY_OCID>"

        update_bucket_details = oci.object_storage.models.UpdateBucketDetails(
            kms_key_id=new_kms_key_id
        )
        object_storage.update_bucket(ns, bucket_name, update_bucket_details)
        ```

        Do this for every resource that used keys in the old PUBLIC vault.

        ***

        ## 7. Decommission Old PUBLIC Vaults

        After you confirm:

        * All data is re‑encrypted with keys in private vaults.
        * All services use new key OCIDs.

        Then:

        ```python theme={null}
        for old_vault in public_vaults:
            print(f"Scheduling deletion for old PUBLIC vault {old_vault.display_name}")
            deletion_details = oci.key_management.models.ScheduleVaultDeletionDetails(
                time_of_deletion=None  # optional: time; if None, minimal allowed window
            )
            kms_vault_client.schedule_vault_deletion(old_vault.id, deletion_details)
        ```

        ***

        ## 8. Making This an Automated “Monitoring Remediation” Script

        Wrap the logic:

        1. List vaults in target compartments.
        2. Find vaults with `endpoint_type == "PUBLIC"`.
        3. For each:
           * Check if a matching `*-private` vault exists.
           * If not, create it.
           * Log vault and key mappings so you can:
             * Manually or automatically run service‑specific updates to re‑point keys.
        4. Optionally send alerts if manual steps are required (e.g., non‑exportable keys).

        You can run this via:

        * OCI Functions (triggered by Monitoring/Events when a new PUBLIC vault is detected).
        * A scheduled job (OCI DevOps, external CI, cron, etc.).

        ***

        If you share a specific service (e.g., “Object Storage only” or “Autonomous DB only”), I can give you a concrete Python snippet for updating its KMS key to a vault with a private endpoint.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        resource "oci_kms_vault" "encryption_vault" {
          # Replace with your tenancy / compartment OCID
          compartment_id = "OCID_OF_COMPARTMENT"

          # Human-readable name for the vault
          display_name = "ENCRYPTION_VAULT_NAME"

          # This is the critical setting to use a private endpoint
          # NOTE: Changing an existing vault from DEFAULT to VIRTUAL_PRIVATE requires
          #       destroying and recreating the vault; keys cannot be moved in-place.
          #       Plan and migrate keys to a new vault before applying.
          vault_type = "VIRTUAL_PRIVATE"

          # Required for VIRTUAL_PRIVATE vaults: configure the private endpoint
          network_endpoint_details {
            network_endpoint_type = "VIRTUAL_PRIVATE"

            # Substitute with your subnet and VCN OCIDs that have private connectivity
            subnet_id = "OCID_OF_PRIVATE_SUBNET"
            vcn_id    = "OCID_OF_VCN"

            # Optional: attach a specific private IP from the subnet
            # private_endpoint_ip = "10.0.1.10"

            # Optional: control which IPs can reach the endpoint
            # whitelist_ips = [
            #   "10.0.0.0/16",
            # ]
          }

          # Optional freeform and defined tags
          # freeform_tags = {
          #   "Environment" = "PROD"
          # }
        }
        ```

        Changing an existing `oci_kms_vault` from a public (`DEFAULT`) vault to `VIRTUAL_PRIVATE` is a **replacement** operation: Terraform will show the old vault as destroyed and a new one created; you must recreate keys and re-point any using services to the new vault.

        For verification, `terraform plan` should show `vault_type` set to `"VIRTUAL_PRIVATE"` and a populated `network_endpoint_details` block with `network_endpoint_type = "VIRTUAL_PRIVATE"` on the `oci_kms_vault` resource.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
