> ## 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.

# Bedrock Custom Models Should Use Customer Managed Keys For Encryption

### More Info:

Bedrock Custom Models should use Customer Managed Keys for Encryption

### Risk Level

High

### Address

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)
* ISO/IEC 27018
* ISO/IEC 27701
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* SOC2
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* StateRAMP
* UK NCSC Cyber Assessment Framework

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        Below are console-based steps to ensure Amazon Bedrock **custom models** use **customer managed KMS keys (CMKs)** for encryption.

        ***

        ### 1. Create a Customer Managed KMS Key

        1. Sign in to the **AWS Management Console**.
        2. Go to **AWS Key Management Service (KMS)**:\
           Services → search **“Key Management Service”**.
        3. In the left pane, choose **Customer managed keys** → **Create key**.
        4. **Key type**: select **Symmetric** and **Encrypt and decrypt**.
        5. Click **Next**.
        6. **Key alias**: give a clear name (e.g., `alias/bedrock-custom-models`).
        7. (Optional) Add description and tags → **Next**.
        8. **Key administrators**:
           * Add IAM roles/users who can manage the key (e.g., your security/admin role).
           * Click **Next**.
        9. **Key usage permissions**:
           * Under “Other AWS accounts and IAM principals,” add:
             * The IAM role(s) or user(s) you use for Bedrock customization.
             * Optionally, the **Bedrock service principal** for your Region if required:
               * Format: `bedrock.amazonaws.com`
           * Ensure they have `kms:Encrypt`, `kms:Decrypt`, `kms:GenerateDataKey*`, `kms:DescribeKey`.
           * Click **Next**.
        10. Review and click **Finish** to create the key.

        ***

        ### 2. Ensure IAM Role for Bedrock Can Use the KMS Key

        1. Still in **KMS**, click your new key (alias).
        2. Go to the **Key policy** tab.
        3. Confirm the IAM role used by Bedrock (e.g., training/inference role) is listed under “Key users” or in the policy JSON with at least these actions:
           * `kms:Encrypt`
           * `kms:Decrypt`
           * `kms:ReEncrypt*`
           * `kms:GenerateDataKey*`
           * `kms:DescribeKey`
        4. If missing, edit the key policy to include that role.

        ***

        ### 3. Use the CMK When Creating a Custom Model in Bedrock

        > Note: For existing custom models, the KMS key typically cannot be changed. You’ll need to **create a new custom model** configured with the CMK and then migrate usage.

        1. Go to **Amazon Bedrock** console.
        2. In the left menu, choose **Custom models**.
        3. Click **Customize model** (or **Create custom model**).
        4. Choose:
           * Base model provider (e.g., Anthropic, Amazon).
           * Specific model to fine-tune.
        5. In the configuration steps, look for **Encryption** or **KMS key** options. Typically you’ll find:
           * **KMS key for training artifacts / model artifacts / output**.
        6. From the **KMS key** dropdown:
           * Select your customer managed key (`alias/bedrock-custom-models`), **not** the AWS-managed default.
        7. Complete the rest of the customization wizard:
           * Upload or point to training data (S3).
           * Select IAM role that has access to S3 and your KMS key.
           * Configure other training parameters.
        8. Review and **Create** / **Start customization**.

        ***

        ### 4. (If Needed) Recreate Existing Custom Models

        If you already have custom models using AWS-managed keys:

        1. Identify them in **Bedrock → Custom models**.
        2. For each:
           * Document configuration (base model, hyperparameters, data location).
           * Re-run the customization process as in Step 3, but this time selecting your **customer managed KMS key**.
        3. Update any applications/clients to use the **new custom model ARN**.
        4. Once migrated, delete old custom models if no longer needed.

        ***

        ### 5. Optional: Validate Encryption Configuration

        1. In **Bedrock → Custom models**, open the details page of your new custom model.
        2. Confirm:
           * The listed **KMS key ARN** matches your CMK (not an `aws/bedrock` or other AWS-managed key).
        3. In **KMS → Key usage**, verify that your CMK shows use by the Bedrock principal/role.

        This ensures your Bedrock custom models’ artifacts and data are encrypted with your **customer managed KMS key**, meeting the requirement.
      </Accordion>

      <Accordion title="Using CLI">
        Below are AWS CLI–focused steps to ensure Amazon Bedrock **custom models** use **customer managed KMS keys** instead of AWS‑owned keys.

        ***

        ## 1. Create a customer managed KMS key

        ```bash theme={null}
        aws kms create-key \
          --description "CMK for Bedrock custom model encryption" \
          --key-usage ENCRYPT_DECRYPT \
          --origin AWS_KMS \
          --region <REGION>
        ```

        Note the `KeyId` in the output.

        Optionally create an alias:

        ```bash theme={null}
        aws kms create-alias \
          --alias-name alias/bedrock-custom-model-cmk \
          --target-key-id <KEY_ID> \
          --region <REGION>
        ```

        You can then use either the `KeyId` or the alias ARN.

        ***

        ## 2. Add a key policy that allows Bedrock to use the key

        Get your account ID:

        ```bash theme={null}
        ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
        ```

        Create a key policy file `bedrock-kms-policy.json` like:

        ```json theme={null}
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "AllowAccountAdminsFullAccess",
              "Effect": "Allow",
              "Principal": { "AWS": "arn:aws:iam::ACCOUNT_ID:root" },
              "Action": "kms:*",
              "Resource": "*"
            },
            {
              "Sid": "AllowBedrockUseOfTheKey",
              "Effect": "Allow",
              "Principal": {
                "Service": "bedrock.amazonaws.com"
              },
              "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
              ],
              "Resource": "*",
              "Condition": {
                "StringEquals": {
                  "aws:SourceAccount": "ACCOUNT_ID"
                }
              }
            }
          ]
        }
        ```

        Replace `ACCOUNT_ID` with your account ID or use `sed`:

        ```bash theme={null}
        sed -i "s/ACCOUNT_ID/$ACCOUNT_ID/g" bedrock-kms-policy.json
        ```

        Attach the policy:

        ```bash theme={null}
        aws kms put-key-policy \
          --key-id <KEY_ID> \
          --policy-name default \
          --policy file://bedrock-kms-policy.json \
          --region <REGION>
        ```

        ***

        ## 3. Use the CMK when creating a **custom model** (model customization job)

        When you start a model customization job, specify the KMS key in the output data config and (where supported) for the model artifacts.

        Example (skeleton):

        ```bash theme={null}
        aws bedrock create-model-customization-job \
          --region <REGION> \
          --job-name my-custom-model-job \
          --custom-model-name my-custom-model \
          --base-model-identifier "arn:aws:bedrock:<REGION>::foundation-model/amazon.titan-text-lite-v1" \
          --training-data-config '{
              "s3Uri": "s3://my-bucket/training-data/"
            }' \
          --output-data-config "{
              \"s3Uri\": \"s3://my-bucket/bedrock-output/\",
              \"kmsKeyId\": \"arn:aws:kms:<REGION>:${ACCOUNT_ID}:alias/bedrock-custom-model-cmk\"
            }" \
          --role-arn arn:aws:iam::${ACCOUNT_ID}:role/BedrockModelCustomizationRole \
          --hyper-parameters '{
              "batchSize": "8"
            }'
        ```

        Check the Bedrock API version you use; some regions/APIs also take a `customModelKmsKeyId` or similar field in the job request for encrypting the resulting model. If available, set it to your CMK ARN or alias ARN as well.

        ***

        ## 4. Use the CMK when provisioning throughput for the custom model

        When you create provisioned throughput for the resulting custom model, specify `kmsKeyId`:

        ```bash theme={null}
        aws bedrock create-provisioned-model-throughput \
          --region <REGION> \
          --provisioned-model-name my-custom-model-pt \
          --model-arn <CUSTOM_MODEL_ARN> \
          --model-units 1 \
          --kms-key-id arn:aws:kms:<REGION>:${ACCOUNT_ID}:alias/bedrock-custom-model-cmk
        ```

        If `create-provisioned-model-throughput` in your region/API variant supports an explicit KMS field (e.g. `kmsKeyId`), always set it. For existing throughput that does *not* use your CMK, you typically must:

        1. Create new provisioned throughput with the CMK.
        2. Update clients to use the new provisioned model ARN.
        3. Delete the old provisioned throughput.

        ***

        ## 5. Ensure Bedrock logging (optional but related) also uses CMK

        If you use model invocation logging, configure it with your CMK:

        ```bash theme={null}
        aws bedrock put-model-invocation-logging-configuration \
          --region <REGION> \
          --logging-config '{
            "cloudWatchConfig": {
              "logGroupName": "/aws/bedrock/model-invocations",
              "roleArn": "arn:aws:iam::'"$ACCOUNT_ID"':role/BedrockLoggingRole",
              "largeDataDeliveryS3Config": {
                "bucketName": "my-bedrock-logs-bucket",
                "keyPrefix": "invocations/",
                "kmsKeyId": "arn:aws:kms:<REGION>:'"$ACCOUNT_ID"':alias/bedrock-custom-model-cmk"
              }
            },
            "textDataDeliveryEnabled": true,
            "imageDataDeliveryEnabled": true,
            "videoDataDeliveryEnabled": true
          }'
        ```

        ***

        ## 6. Migrating existing custom models that don’t use CMK

        If an existing custom model or job was created without a CMK (using AWS‑owned keys), KMS settings are generally **not mutable**. To remediate:

        1. Start a new model customization job (step 3) using the CMK.
        2. Provision new throughput using the CMK (step 4).
        3. Point applications to the new model/provisioned ARN.
        4. Decommission the old model resources.

        ***

        If you share your region and current Bedrock API version/CLI output of `aws bedrock help`, I can adjust the exact field names (`kmsKeyId` vs `customModelKmsKeyId`, etc.) to match your environment.
      </Accordion>

      <Accordion title="Using Python">
        To fix this, you must (a) use a **customer-managed KMS key (CMK)** and (b) ensure every new Bedrock custom model is created with that key. Existing models can’t be “retrofitted”; you have to recreate them with a CMK, then delete the old ones.

        Below are step‑by‑step instructions and Python examples.

        ***

        ## 1. Create or choose a customer-managed KMS key

        You can create a CMK via console or Python. Example with Python (boto3):

        ```python theme={null}
        import boto3

        kms = boto3.client("kms", region_name="us-east-1")

        response = kms.create_key(
            Description="CMK for Amazon Bedrock custom models",
            KeyUsage="ENCRYPT_DECRYPT",
            CustomerMasterKeySpec="SYMMETRIC_DEFAULT",
            Origin="AWS_KMS",
            MultiRegion=False
        )

        cmk_arn = response["KeyMetadata"]["Arn"]
        print("CMK ARN:", cmk_arn)
        ```

        ***

        ## 2. Update the KMS key policy to allow Bedrock to use it

        Add a statement like this to the key policy (via console or `put_key_policy`) so Bedrock can use the key. Replace:

        * `REGION` with your region
        * `ACCOUNT_ID` with your AWS account ID
        * `KEY_ID` with the key ID or ARN
        * Principals as appropriate for your org

        Example (conceptual JSON; merge into existing policy):

        ```json theme={null}
        {
          "Sid": "AllowBedrockToUseKeyForEncryption",
          "Effect": "Allow",
          "Principal": {
            "Service": "bedrock.amazonaws.com"
          },
          "Action": [
            "kms:Encrypt",
            "kms:Decrypt",
            "kms:GenerateDataKey*",
            "kms:DescribeKey"
          ],
          "Resource": "*",
          "Condition": {
            "StringEquals": {
              "aws:SourceAccount": "ACCOUNT_ID"
            },
            "ArnLike": {
              "aws:SourceArn": "arn:aws:bedrock:REGION:ACCOUNT_ID:*"
            }
          }
        }
        ```

        If you use an execution role for Bedrock jobs, also allow that role to use the key (Principal = that role ARN).

        ***

        ## 3. Ensure S3 buckets used by Bedrock are also using CMK (optional but recommended)

        If you store training/output data in S3, configure bucket default encryption with the same CMK or another CMK:

        ```python theme={null}
        import boto3

        s3 = boto3.client("s3", region_name="us-east-1")

        bucket_name = "my-bedrock-training-bucket"
        cmk_arn = "arn:aws:kms:us-east-1:ACCOUNT_ID:key/KEY_ID"

        s3.put_bucket_encryption(
            Bucket=bucket_name,
            ServerSideEncryptionConfiguration={
                "Rules": [
                    {
                        "ApplyServerSideEncryptionByDefault": {
                            "SSEAlgorithm": "aws:kms",
                            "KMSMasterKeyID": cmk_arn
                        }
                    }
                ]
            }
        )
        ```

        ***

        ## 4. Create a new custom model with a CMK (Python)

        Use the Bedrock client and specify:

        * `customModelKmsKeyId` – for the model artifacts
        * `outputDataConfig["kmsKeyId"]` – for training job outputs in S3 (optional but recommended)

        Example using `boto3` (Bedrock “control plane” client):

        ```python theme={null}
        import boto3
        import time

        region = "us-east-1"
        bedrock = boto3.client("bedrock", region_name=region)

        role_arn = "arn:aws:iam::ACCOUNT_ID:role/BedrockModelCustomizationRole"
        cmk_arn = "arn:aws:kms:us-east-1:ACCOUNT_ID:key/KEY_ID"

        response = bedrock.create_model_customization_job(
            jobName="my-custom-model-job",
            customModelName="my-custom-model-with-cmk",
            baseModelIdentifier="anthropic.claude-3-haiku-20240307-v1:0",  # example
            customModelKmsKeyId=cmk_arn,
            roleArn=role_arn,
            trainingDataConfig={
                "s3Uri": "s3://my-bedrock-training-bucket/training-data/"
            },
            outputDataConfig={
                "s3Uri": "s3://my-bedrock-output-bucket/custom-models/",
                "kmsKeyId": cmk_arn
            },
            hyperParameters={
                # Only if applicable to your base model
                # "epochCount": "3",
                # "learningRate": "0.0001"
            }
        )

        job_arn = response["jobArn"]
        print("Customization job ARN:", job_arn)

        # Wait for completion (simple poll loop)
        while True:
            desc = bedrock.get_model_customization_job(jobIdentifier=job_arn)
            status = desc["status"]
            print("Status:", status)
            if status in ["Completed", "Failed", "Stopped"]:
                break
            time.sleep(60)

        if status != "Completed":
            raise RuntimeError(f"Job did not complete successfully: {status}")

        print("Custom model ARN:", desc["customModelArn"])
        ```

        If you’re using the `CreateCustomModel` API directly (for some feature sets), the pattern is similar: include `customModelKmsKeyId` and `outputDataConfig.kmsKeyId`.

        ***

        ## 5. Migrate from existing non‑CMK models

        1. Identify misconfigured models (created without `customModelKmsKeyId` or using AWS‑owned keys).
        2. Re‑run your customization/creation process using the CMK as shown above.
        3. Test the new custom model.
        4. Update any applications to use the new model ARN.
        5. Delete the old model and its associated S3 data if no longer needed.

        ***

        ## 6. Enforce CMK usage going forward

        * Wrap your model‑creation logic in a Python function that always passes `customModelKmsKeyId` and `outputDataConfig.kmsKeyId`.
        * Optionally, use organization/CI checks (e.g., IaC scanning or custom config rules) to block non‑CMK Bedrock model creations.

        If you share your current creation code (or CloudFormation/Terraform), I can show the exact changes needed.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
