amazon-web-servicesterraformamazon-kmsaws-ssm

AWS Terraform: How to give `kms:Decrypt` to an instance profile that can read from the SSM param store?


I am attempting to create an instance profile that allows EC2 instances to perform retrieval of SSM Param Store keys as well as decrypt them via their associated KMS key.

I have created the profile so far with only SSM Parameter read permissions, but not permission to decrypt. See below:

main.tf

# main.tf

provider "aws" {
  region = var.aws_config.region
}

# Create an IAM role
resource "aws_iam_role" "ssm_read_role" {
  name = var.iam_ssm_read_config.role_name
  assume_role_policy = file("iam/ec2_ssm_read_role_assume_policy.json")
}

# Attach AmazonSSMReadOnlyAccess policy to the IAM role
resource "aws_iam_role_policy_attachment" "ssm_policy_attachment" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess"
  role       = aws_iam_role.ssm_read_role.name
}

# Create a EC2 profile of for assuming the role
resource "aws_iam_instance_profile" "ssm_read_profile" {
  name = var.iam_ssm_read_config.profile_name
  role = aws_iam_role.ssm_read_role.name
}

output "iam_role_arn" {
  value = aws_iam_role.ssm_read_role.arn
}

output "iam_role_name" {
  value = aws_iam_role.ssm_read_role.name
}

output "iam_profile_name" {
  value = aws_iam_instance_profile.ssm_read_profile.name
}

iam/ec2_ssm_read_role_assume_policy.json


{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Principal": {
      "Service": "ec2.amazonaws.com"
    }
  }
}

Now I am attempting to use a python client to generate a configuration file using the param store, and I get this error:

botocore.exceptions.ClientError: An error occurred (AccessDeniedException) when calling the GetParameters operation: User: arn:aws:sts::983867311419:assumed-role/ssm_read_role/i-095049df3e5cs1947 is not authorized to perform: kms:Decrypt on resource: arn:aws:kms:us-west-1:983867311419:key/f460e94d-5655-4297-89ae-feha7s81jar8 because no identity-based policy allows the kms:Decrypt action (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: a25d9846-448a-422e-bdb6-5f12af368790; Proxy: null)

It seems I am missing the ability to decrypt with this profile. I have attempted adding it to the policy statement but receive errors because it is not an STS policy type. I also attempted creating another aws_iam_role_policy_attachment using an isolated custom policy for kms:Decrypt but this failed with:

│ Error: Unsupported attribute
│
│   on main.tf line 44, in resource "aws_iam_role_policy_attachment" "kms_decrypt_policy_attachment":
│   44:   policy_arn = aws_iam_role_policy.kms_decrypt_policy.arn
│
│ This object has no argument, nested block, or exported attribute named "arn".

What's the correct method to allow an instance profile to both retrieve and decrypt from the param store?


Solution

  • The managed policy that you are using does not allow the kms:Decrypt action. To fix this, you can add an inline policy to your role:

    resource "aws_iam_role" "ssm_read_role" {
      name = var.iam_ssm_read_config.role_name
      assume_role_policy = file("iam/ec2_ssm_read_role_assume_policy.json")
      inline_policy {
        name = "kms_decrypt_policy"
    
        policy = jsonencode({
          Version = "2012-10-17"
          Statement = [
            {
              Action   = ["kms:Decrypt"]
              Effect   = "Allow"
              Resource = "*"
            },
          ]
        })
      }
    }