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

# Kms secrets rotation enabled remediation

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        Below are the minimal console steps to **enable rotation for an AWS Secrets Manager secret** that’s encrypted with a KMS key.

        > Note: Secrets rotation is configured per *secret*. The KMS key only encrypts the secret; enabling rotation is done in Secrets Manager, not on the KMS key itself.

        ***

        ### 1. Identify the secret

        1. Sign in to the **AWS Management Console**.
        2. Go to **Secrets Manager**:\
           `Services → Security, Identity, & Compliance → Secrets Manager`.
        3. On **Secrets**, click the **secret** you want to enable rotation for (it can be encrypted with a customer-managed KMS key).

        ***

        ### 2. Set up (or select) a rotation Lambda function

        1. On the secret’s details page, click **Rotate secret** (or edit rotation from the **Rotation** tab/section).

        2. Check **Enable automatic rotation**.

        3. Under **Rotation schedule**, choose the rotation period (e.g., **30 days**).

        4. Under **Rotation function**, choose one of:
           * **Use an existing Lambda function** (if you already have a rotation function for this secret’s type).
           * Or **Create a new Lambda function** (recommended if you don’t have one):
             * Choose the database/service type (e.g., **RDS**, **DocumentDB**, etc.).
             * Provide a name for the new Lambda function.
             * AWS will create a Lambda from a template and an IAM role with required permissions.

        5. Save/confirm the Lambda creation (if you created a new one) and return to the **Rotate secret** configuration.

        ***

        ### 3. Configure rotation schedule and save

        1. Set **Rotation schedule**:
           * Choose **Automatic rotation**.
           * Set the **rotation interval** (e.g., 30, 60, or 90 days).
           * (Optional) Configure a **specific start time** if needed.
        2. Click **Save** or **Schedule rotation**.

        ***

        ### 4. (Optional) Test rotation

        1. On the secret’s page, use **Rotate secret immediately** (or **Test rotation**) if available.
        2. Confirm that:
           * The Lambda function completes without errors.
           * The target resource (DB, service, etc.) can be accessed using the updated secret value.
           * The secret remains encrypted with your intended **KMS key** (check **Secret details → Encryption key**).

        This remediates the “Secrets Manager secrets rotation disabled” issue for a KMS-encrypted secret via the AWS Console.
      </Accordion>

      <Accordion title="Using CLI">
        To fix this finding using AWS KMS via AWS CLI, you typically need to **enable automatic rotation on the KMS keys** that encrypt your Secrets Manager secrets.

        Below are the step‑by‑step commands.

        ***

        ### 1. Identify the KMS key used by the secret

        If you already know the KMS key ID/ARN, skip to step 2.

        Otherwise, get the secret’s details:

        ```bash theme={null}
        aws secretsmanager describe-secret \
          --secret-id <your-secret-id>
        ```

        In the output, note the `KmsKeyId` field. That is the KMS key you must configure.

        ***

        ### 2. Check current rotation status of the KMS key

        ```bash theme={null}
        aws kms get-key-rotation-status \
          --key-id <kms-key-id-or-arn>
        ```

        Look at `KeyRotationEnabled`:

        * `false` → rotation not enabled (this triggers your finding).
        * `true` → rotation already enabled.

        ***

        ### 3. Enable automatic rotation for the KMS key

        ```bash theme={null}
        aws kms enable-key-rotation \
          --key-id <kms-key-id-or-arn>
        ```

        Notes:

        * This can only be done for **symmetric customer managed keys** (CMKs), not AWS‑managed keys.
        * Rotation interval is fixed at **1 year** for KMS automatic rotation.

        ***

        ### 4. Re‑verify rotation status

        ```bash theme={null}
        aws kms get-key-rotation-status \
          --key-id <kms-key-id-or-arn>
        ```

        Confirm `KeyRotationEnabled` is now `true`.

        ***

        If you also need **Secrets Manager secret rotation** (rotating the *secret value* itself, e.g., database password), I can give you the separate CLI steps for setting up a rotation Lambda and enabling `rotate-secret`.
      </Accordion>

      <Accordion title="Using Python">
        Below is a practical, minimal set of steps and Python snippets to **enable automatic rotation for AWS Secrets Manager secrets that use KMS**.

        ***

        ## 1. Prerequisites

        1. A secret already exists in AWS Secrets Manager (e.g. `my-db-secret`).
        2. The secret is encrypted with a KMS key (default or customer-managed).
        3. You have:
           * `awscli` or AWS Console access
           * `boto3` installed for Python
           * IAM permissions for:
             * `secretsmanager:*`
             * `lambda:*`
             * `iam:PassRole`

        ***

        ## 2. Create an IAM Role for the Rotation Lambda

        Create a role (e.g. `SecretsRotationRole`) with:

        * **Trust policy** (principal is Lambda):

        ```json theme={null}
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": { "Service": "lambda.amazonaws.com" },
              "Action": "sts:AssumeRole"
            }
          ]
        }
        ```

        * **Permissions policy** for Secrets Manager, KMS, logging, and your target resource (e.g. DB, API, etc.):

        ```json theme={null}
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "secretsmanager:GetSecretValue",
                "secretsmanager:PutSecretValue",
                "secretsmanager:UpdateSecretVersionStage"
              ],
              "Resource": "arn:aws:secretsmanager:REGION:ACCOUNT_ID:secret:my-db-secret-*"
            },
            {
              "Effect": "Allow",
              "Action": [
                "kms:Decrypt",
                "kms:Encrypt",
                "kms:GenerateDataKey"
              ],
              "Resource": "arn:aws:kms:REGION:ACCOUNT_ID:key/YOUR_KMS_KEY_ID"
            },
            {
              "Effect": "Allow",
              "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
              ],
              "Resource": "*"
            }
            // Add DB permissions if you are rotating DB credentials
          ]
        }
        ```

        Attach this policy to the role.

        ***

        ## 3. Write the Rotation Lambda in Python

        A rotation Lambda must implement these steps:\
        `createSecret`, `setSecret`, `testSecret`, `finishSecret`.

        Below is a **minimal template** (you must customize the actual secret-change logic, e.g., DB password rotation):

        ```python theme={null}
        import boto3
        import json
        import logging
        import os

        logger = logging.getLogger()
        logger.setLevel(logging.INFO)

        secrets_client = boto3.client('secretsmanager')

        def lambda_handler(event, context):
            arn = event['SecretId']
            token = event['ClientRequestToken']
            step = event['Step']

            metadata = secrets_client.describe_secret(SecretId=arn)

            if not metadata['RotationEnabled']:
                raise ValueError("Secret rotation not enabled for secret {}".format(arn))

            versions = metadata['VersionIdsToStages']
            if token not in versions or 'AWSPENDING' not in versions[token]:
                raise ValueError("Secret version not set as AWSPENDING for rotation")

            if step == "createSecret":
                create_secret(arn, token)
            elif step == "setSecret":
                set_secret(arn, token)
            elif step == "testSecret":
                test_secret(arn, token)
            elif step == "finishSecret":
                finish_secret(arn, token)
            else:
                raise ValueError("Invalid step parameter")

        def create_secret(arn, token):
            # If a pending secret already exists, don’t recreate
            try:
                secrets_client.get_secret_value(SecretId=arn, VersionId=token, VersionStage="AWSPENDING")
                logger.info("createSecret: AWSPENDING already exists for %s", arn)
                return
            except secrets_client.exceptions.ResourceNotFoundException:
                pass

            # Get the current secret (to use as base)
            current = secrets_client.get_secret_value(SecretId=arn, VersionStage="AWSCURRENT")
            current_dict = json.loads(current['SecretString'])

            # TODO: Implement logic to generate new secret value, e.g. new password
            new_secret_dict = current_dict.copy()
            new_secret_dict["password"] = "NEW_GENERATED_PASSWORD"  # replace with real generation

            secrets_client.put_secret_value(
                SecretId=arn,
                ClientRequestToken=token,
                SecretString=json.dumps(new_secret_dict),
                VersionStages=["AWSPENDING"]
            )
            logger.info("createSecret: Created new pending secret for %s", arn)

        def set_secret(arn, token):
            # TODO: Apply the new secret to the target system (e.g., update DB user password)
            logger.info("setSecret: Apply pending secret in target system for %s", arn)
            # Example stub; implement per your target:
            # 1. Get AWSPENDING
            # 2. Connect to DB / service
            # 3. Update password / key
            pass

        def test_secret(arn, token):
            # TODO: Verify that AWSPENDING secret works against target system
            logger.info("testSecret: Testing pending secret for %s", arn)
            # Example stub:
            # 1. Get AWSPENDING
            # 2. Attempt to connect/login
            # 3. Raise on failure
            pass

        def finish_secret(arn, token):
            metadata = secrets_client.describe_secret(SecretId=arn)
            current_version = None

            for version, stages in metadata['VersionIdsToStages'].items():
                if "AWSCURRENT" in stages:
                    current_version = version
                    break

            # Mark the new version as current
            secrets_client.update_secret_version_stage(
                SecretId=arn,
                VersionStage="AWSCURRENT",
                MoveToVersionId=token,
                RemoveFromVersionId=current_version
            )
            logger.info("finishSecret: Set AWSCURRENT to version %s for %s", token, arn)
        ```

        Package this as a ZIP and deploy as a Lambda (via console or CLI).\
        Set:

        * Runtime: Python 3.x
        * Role: `SecretsRotationRole`
        * Timeout: long enough for rotation (e.g. 15–30 seconds; more if needed).

        ***

        ## 4. Enable Rotation on the Secret Using Python (boto3)

        Use `rotate_secret` or `enable_rotation` from `boto3`:

        ```python theme={null}
        import boto3

        secrets_client = boto3.client("secretsmanager", region_name="YOUR_REGION")

        secret_arn = "arn:aws:secretsmanager:REGION:ACCOUNT_ID:secret:my-db-secret-XXXX"
        lambda_arn = "arn:aws:lambda:REGION:ACCOUNT_ID:function:your-rotation-lambda"

        response = secrets_client.rotate_secret(
            SecretId=secret_arn,
            RotationLambdaARN=lambda_arn,
            RotationRules={
                "AutomaticallyAfterDays": 30  # e.g. every 30 days
            }
        )

        print(response)
        ```

        If the Lambda is already associated and you just want to turn rotation on/update schedule:

        ```python theme={null}
        secrets_client.enable_rotation(
            SecretId=secret_arn,
            RotationLambdaARN=lambda_arn,
            RotationRules={
                "AutomaticallyAfterDays": 30
            }
        )
        ```

        ***

        ## 5. Verify Rotation Status

        ```python theme={null}
        resp = secrets_client.describe_secret(SecretId=secret_arn)
        print("RotationEnabled:", resp["RotationEnabled"])
        print("RotationRules:", resp.get("RotationRules"))
        print("RotationLambdaARN:", resp.get("RotationLambdaARN"))
        ```

        ***

        This remediates the misconfiguration by programmatically enabling secret rotation for a KMS-encrypted secret in AWS using Python; you only need to fill in the target-specific rotation logic in the Lambda (`setSecret` and `testSecret`).
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        resource "aws_kms_key" "EXAMPLE_KEY" {
          description             = "KMS key for XYZ purpose"
          deletion_window_in_days = 30
          key_usage               = "ENCRYPT_DECRYPT"
          customer_master_key_spec = "SYMMETRIC_DEFAULT"

          # Enable annual automatic rotation for this KMS key
          enable_key_rotation = true
        }
        ```

        Replace `EXAMPLE_KEY` with your key name and adjust description/usage/spec as needed.\
        This change does not force replacement of the KMS key; Terraform will update it in place.

        To verify, `terraform plan` should show an in-place update with `enable_key_rotation` changing from `false` (or `null`) to `true`.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
