1
votes

I'm using my AWS KMS CMK to encrypt and AWS SecretsManager Secret, but my coworker can see the secret value!!

  • My policy on my KMS CMK says only I can do kms:Decrypt.
  • My coworker (who does not have those permissions on my CMK), is able to...
    • Open the AWS Console to SecretsManager >>>
    • Click Retrieve Secret Value >>>
    • And see my secret value!

Any idea why?

Technical Details:

I'm using AWS SAM CLI to deploy this.

Here's my AWS SAM template:

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31

Parameters:
  SecretValue:
    Type: String
  KmsCmkId: 
    Type: String

Resources:
  MySecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      SecretString:
        Ref: SecretValue
      KmsKeyId: !Ref KmsCmkId

I build and deploy it with this:

sam build ; sam deploy --guided --parameter-overrides SecretValue=ABC KmsCmkId=REDACTED

My Debugging To-Date:

  • I searched serverfault.com and essentially got no results. I searched Stack Overflow and found only one post, which seems to be related, but the problem is not articulated, and the solution is not what's going on in my case: AWS KMS CMK encrypt and decrypt with symmetric and asymmetric

  • I'm using a symmetric CMK because SecretsManager requires it. (SecretsManager does not allow use of asymmetric CMKs to encrypt secret values).

  • I confirmed that clicking the Retrieve Secret Value button in the AWS SecretsManager console indeed performs an API call with a secretsmanager:GetSecretValue.

  • AWS says secretsmanager:GetSecretValue should only work if the caller also has kms:Decrypt on the CMK that was used to encrypt the secret (which makes sense). (See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html)

  • I confirmed that my symmetric KMS CMK is indeed the CMK being used to encrypt the secret.

  • My coworker is NOT logged into AWS as the root account. He's logged in as his account. He happens to have a ton of permissions because he's an admin, but I see no reason why that should allow him to use my CMK.

  • If you're curious why my coworker has KMS actions for key admins, it's because he's our system admin.

  • The policy on my KMS CMK was auto-generated by the nice wizard you go through in the AWS Console when you create a CMK.

  • Note: Be careful not to confuse kms:Get* operations with secretsmanager:Get* operations.

  • Here's the policy on my KMS CMK:

{
    "Id": "key-consolepolicy-3",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::REDACTED:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow access for Key Administrators",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::REDACTED:user/MY_COWORKER"
                ]
            },
            "Action": [
                "kms:Create*",
                "kms:Describe*",
                "kms:Enable*",
                "kms:List*",
                "kms:Put*",
                "kms:Update*",
                "kms:Revoke*",
                "kms:Disable*",
                "kms:Get*",
                "kms:Delete*",
                "kms:TagResource",
                "kms:UntagResource",
                "kms:ScheduleKeyDeletion",
                "kms:CancelKeyDeletion"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::REDACTED:user/ME"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::REDACTED:user/ME"
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        }
    ]
}
1
You say "he's an Admin". Is it possible that your co-worker has * permissions on every service? For example, can they access other KMS keys? If so, then they have another policy that is granting them KMS permissions. You would probably need to add a Deny section to the KMS CMK to prevent other people from using it.John Rotenstein
It looks like this was the problem! Thank you @JohnRotenstein ! Based on your suggested, I posted an answer below.mountHouli

1 Answers

1
votes

Thanks so much to @JohnRotenstein for pointing me in the right direction, with his reply to my question, above!

Solution Background 1

As John asked, above when I say above that my coworker "is an admin" on our account, what I mean is that his IAM user account has AWS Managed Policy Administrator Access which gives "Full Access" to (as far as I know) everything or just about everything in AWS (including KMS!!).

Solution Background 2

Indeed, in my question above, my key policy (which is the default key policy) includes this statement:

{
    "Sid": "Enable IAM User Permissions",
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::REDACTED:root"
    },
    "Action": "kms:*",
    "Resource": "*"
},

And per @JohnRotenstein 's comments and these AWS docs, this policy statement allows IAM policies to access and use this key--if those policies specify the right permissions.

Thus (as far as I can tell), this would allow quite a number of folks (anyone who can edit IAM policies on my company's account) the ability to give themself a policy that allows them to do whatever they want with my KMS key! (which is not safe!)

I need to clamp this down. (solution below!)

Solution Background 3

In the "default KMS key policy" (which I posted in my question above), you'll see that key administrators can kms:Put*. Allows them to kms:PutKeyPolicy, which would allow them to change the policy to give themselves (or anyone) kms:Decrypt, which would allow them to decrypt my Secrets Manager secret and get the secret value!

I need to clamp this down as well...

The Solution

The key policy below:

  • Ensures only my Lambda function can (via the policy statement I give to the IAM role that executes the Lambda function) use an IAM policy to use this key, and they can only do kms:Decrypt

  • Allows only the key user (me) to do encryption and decryption operations (except the Lambda function, of course; see above)

  • Though key administrators can't use my key to encrypt or decrypt things (or kms:PutKeyPolicy), they can do all admin tasks, such as deleting the KMS key or its grants.

{
  "Id": "mount-houlis-secure-kms-key-policy",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Allow use of the key",
      "Effect": "Allow",
      "Principal": {
        "AWS": THE_ARN_OF_THE_IAM_USER_WHO_OWNS_THE_SECRET____WHICH_IS_ME
      },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:DescribeKey",
        "kms:GetKeyPolicy",
        "kms:PutKeyPolicy"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Admins",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          ARNS_OF_VARIOUS,
          KEY_ADMINISTRATORS,
          AND_ME
        ]
      },
      "Action": [
        "kms:CancelKeyDeletion",
        "kms:CreateAlias",
        "kms:DeleteAlias",
        "kms:DescribeKey",
        "kms:DisableKey",
        "kms:DisableKeyRotation",
        "kms:EnableKey",
        "kms:EnableKeyRotation",
        "kms:GetKeyPolicy",
        "kms:GetKeyRotationStatus",
        "kms:ListGrants",
        "kms:ListKeyPolicies",
        "kms:ListResourceTags",
        "kms:ListRetirableGrants",
        "kms:RetireGrant",
        "kms:RevokeGrant",
        "kms:ScheduleKeyDeletion",
        "kms:TagResource",
        "kms:UntagResource",
        "kms:UpdateAlias",
        "kms:UpdateKeyDescription"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Allow Lambda function to do Action secretsmanager:GetSecretValue",
      "Effect": "Allow",
      "Principal": {
        "AWS": ARN_OF_THE_ROLE_THAT_YOUR_LAMBDA_FUNCTION_EXECUTES_AS____SHOULD_BE_arn:aws:iam::ACCOUNT_NUMBER:role/your-lambda-function-role-name
      },
      "Action": "kms:Decrypt",
      "Resource": "*"
    }
  ]
}