I'm using my AWS KMS CMK to encrypt and AWS SecretsManager Secret, but my coworker can see the secret value!!
kms:Decrypt
.Retrieve 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"
}
}
}
]
}
Thanks so much to @JohnRotenstein for pointing me in the right direction, with his reply to my question, above!
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!!).
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!)
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 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": "*"
}
]
}