Robert Swift
Robert Swift

Reputation: 333

CloudFormation refusing to create AWS::KMS::Key with least privilege

Endeavouring to apply the principle of least privilege to a CMK I'm creating, the goal is to create a CloudFormation template that can be used via StackSets to the entire organisation. As a result, I want a key that can be used (kms:Encrypt, kms:Decrypt etc.) for general encryption tasks in the account, but that cannot be modified by principals in the account (specifically kms:PutKeyPolicy but not only).

I have a working policy lifted from a hand crafted key. The CloudFormation template works fine, the StackSet initiates the resource creation.

But only when I don't restrict the account principal with any conditions, which removes the least privilege principle. The CreateKey and PutKeyPolicy API calls both have an option BypassPolicyLockoutSafetyCheck for those of us idiotic enough to think they know better! Except CloudFormation doesn't expose that for AWS::KMS::Key :(

So unless I basically leave the key policy wide open, I get the following error in the Stack:

Resource handler returned message: "The new key policy will not allow you to update the key policy in the future. (Service: Kms, Status Code: 400, Request ID: xxxx, Extended Request ID: null)" (RequestToken: xxxx, HandlerErrorCode: InvalidRequest)

I've tried a variety of options for the principal, with the Condition removed (as below) the key is created, with it in no joy.

- Sid: AllowUpdatesByCloudFormation
          Effect: Allow
          Principal:
            AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
          Action:
          - kms:Describe*
          - kms:List*
          - kms:PutKeyPolicy
          - kms:CreateAlias
          - kms:UpdateAlias
          - kms:UpdateKeyDescription
          - kms:EnableKey
          - kms:DisableKey
          - kms:EnableKeyRotation
          - kms:DisableKeyRotation
          - kms:GetKey*
          - kms:DeleteAlias
          - kms:TagResource
          - kms:UntagResource
          - kms:ScheduleKeyDeletion
          - kms:CancelKeyDeletion
          Resource: '*'
          # Condition:
          #   StringEquals:
          #     "aws:PrincipalAccount": !Sub ${AWS::AccountId}
          #     "kms:ViaService": !Sub "cloudformation.${AWS::Region}.amazonaws.com"

I've tried with different principal settings, including AWS: "*" and a few different Service options, and different settings on the Condition. I've tried with and without the region in the service name. I must be missing something, but I've lost a few hours scratching my head over this one.

Web searches, AWS forum searches have turned up nothing, so I'm hoping the good bhurgers of StackOverflow can guide me - and future me's searching for the same help :)

It doesn't seem possible to link to the table section on the AWS KMS API page for the condition keys on CreateKey or PutKeyPolicy but I don't think I've missed a trick with those?

Thanks in advance - Robert.

Upvotes: 1

Views: 8397

Answers (1)

not-a-coderp
not-a-coderp

Reputation: 31

Try giving the root user all kms permissions - (kms:*) The principle of least privilege still applies when giving root all access.

That will enable IAM User permissions.

Add additional policies to each role or user or user group. Add a policy for key administration. Add a policy for usage. That is where you can fine tune your access.

Try working with this key policy and tweak it. This is a key I use for RDS encryption in a cfn stack. (Yes! I know that policies should be applied to user groups, not users directly for best practices... but this is inside a sandbox environment I have access to from 'aCloud guru')

  KeyPolicy:
    Id: key-consolepolicy-3
    Version: "2012-10-17"
    Statement:
      - Sid: Enable IAM User Permissions
        Effect: Allow
        Principal:
          AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
        Action: kms:*
        Resource: '*'
      - Sid: Allow access for Key Administrators
        Effect: Allow
        Principal:
          AWS:
            - !Sub "arn:aws:iam::${AWS::AccountId}:role/admin"
            - !Sub "arn:aws:iam::${AWS::AccountId}:user/cloud_user"
        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: !Sub "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS"
        Action:
          - kms:Encrypt
          - kms:Decrypt
          - kms:ReEncrypt*
          - kms:GenerateDataKey*
          - kms:DescribeKey
        Resource: '*'
      - Sid: Allow attachment of persistent resources
        Effect: Allow
        Principal:
          AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS"
        Action:
          - kms:CreateGrant
          - kms:ListGrants
          - kms:RevokeGrant
        Resource: '*'
        Condition:
          Bool:
            kms:GrantIsForAWSResource: "true"

Upvotes: 3

Related Questions