Attempts at writing the Terraform code for AWS KMS - amazon-web-services

Goal :
I am trying to create the following things A terraform template to
create KMS keys This template should create the key and two IAM roles.
The roles would be one for admin functions and one that allows
encrypt/decrypt I have written the following code
Am I doing the correct thing to achieve my goal?
provider "aws"
{
access_key = "*****************"
secret_key = "4ZJaLh***********"
region = "us-east-1"
}
resource "aws_kms_key" "test_key" {
description = "KMS Test key"
}
resource "aws_kms_alias" "alias" {
name = "alias/test_key"
target_key_id = "${aws_kms_key.test_key.key_id}"
}
#IAM Role and Policy
resource "aws_iam_policy" "kms_user_policy" {
name = "KMS-User-Policy"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey",
"kms:ReEncryptTo",
"kms:DescribeKey",
"kms:ReEncryptFrom"
],
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role" "kms_user_role" {
name = "kms_user_role"
path = "/"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy_attachment" "test-attach" {
name = "test-attachment"
roles = ["${aws_iam_role.kms_user_role.name}"]
policy_arn = "${aws_iam_policy.kms_user_policy.arn}"
}

Related

AWS KMS and IAM association using terraform version 0.12

Hi AWS and Terraform experts, I was kinda generating the KMS and IAM association that was built manually by our former colleague, I'm getting an issue to completing the copy of kms policy stated below:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::12345678912345:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "ALSKDJFHGNVBCMXJDH0987"
},
"Action": "kms:Decrypt",
"Resource": "*"
}
]
}
This ALSKDJFHGNVBCMXJDH0987 is an IAM Role which was I believe transformed by AWS console (not yet sure why)
{
"Effect": "Allow",
"Principal": {
"AWS": "ALSKDJFHGNVBCMXJDH0987"
},
"Action": "kms:Decrypt",
"Resource": "*"
}
I'm getting this error using the created terraform script I made:
Error: MalformedPolicyDocumentException: Policy contains a statement with one or more invalid principals.
status code: 400, request id: alsknldkj2-assd-3333-0sdc-askdjaksdjn2
on main.tf line 84, in resource "aws_kms_key" "secrets":
84: resource "aws_kms_key" "secrets" {
Is there something wrong with the sequence? or I'm missing anything?. Attached here is the terraform code I used:
data "template_file" "my-lambda-policy" {
template = "${file("policy/lambda.json")}"
vars = {
SWAG = var.AWS-SWAG
STUDENT-BELONGS = var.STUDENT
STUDENT-TEACHER = var.TEACHER
ROOM = var.CLASSROOM
}
}
resource "aws_iam_policy" "my-lambda-pol" {
name = "my-lambda-policy"
policy = data.template_file.my-lambda-policy.rendered
}
data "template_file" "my-my-lambda-pol2" {
template = "${file("policy/lambda2.json")}"
}
resource "aws_iam_policy" "my-lambda-pol2" {
name = "my-my-lambda-pol2"
policy = data.template_file.my-my-lambda-pol2.rendered
}
data "template_file" "my-lambda-to-my-kms-policy" {
template = "${file("policy/kms-lambda.json")}"
vars = {
SWAG = var.AWS-SWAG
KMS_KEY_ID = aws_kms_key.mysecret.id
}
}
resource "aws_iam_policy" "lambda-to-kms" {
name = "my-lambda-to-my-kms-policy"
policy = data.template_file.my-lambda-to-my-kms-policy.rendered
}
resource "aws_iam_role" "the-lambda-role" {
name = "{STUD_CHAIR}-${STU_SEAG}-${STUDENT-BELONGS}-${STUDENT-TEACHER}"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "my-lambda-policy_attachment" {
policy_arn = aws_iam_policy.my-lambda-pol.arn
role = aws_iam_role.the-lambda-role.name
}
resource "aws_iam_role_policy_attachment" "my-lambda-pol2_attachment" {
policy_arn = aws_iam_policy.my-lambda-pol2.arn
role = aws_iam_role.the-lambda-role.name
}
resource "aws_iam_role_policy_attachment" "kms-attachment" {
depends_on = [aws_kms_key.mysecret]
policy_arn = aws_iam_policy.lambda-to-kms.arn
role = aws_iam_role.the-lambda-role.name
}
data "template_file" "my-kms-policy" {
template = "${file("policy/my-kms-policy.json")}"
vars = {
STUD_CHAIR= "${var.CHAIR}"
STU_SWAG = "${l{var.SWAG}}"
STUDENT-BELONGS = "${var.STUDENT}"
STUDENT-TEACHER = "${var.TEACHER}"
ROOM = "${var.CLASSROOM}"
}
}
resource "aws_kms_key" "mysecret" {
description = "KMS Key for ${var.STUDENT}-${var.TEACHER}-key-${var.CLASSROOM}"
policy = data.template_file.my-kms-policy.rendered
depends_on = [aws_iam_role.the-lambda-role]
}
resource "aws_kms_alias" "mysecret" {
name = "alias/${var.STUDENT}-${var.TEACHER}-key-${var.CLASSROOM}"
depends_on = [aws_iam_role.the-lambda-role]
target_key_id = aws_kms_key.mysecret.key_id
}
this is what inside of my-kms-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${ROOM}:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${ROOM}:role/${STUD_CHAIR}-${STU_SEAG}-${STUDENT-BELONGS}-${STUDENT-TEACHER}"
},
"Action": "kms:Decrypt",
"Resource": "*"
}
]
}
Workaround
A workaround is to run terraform apply twice.
Reason
When recreating an IAM role the policy referencing this role needs to be updated for reasons described here:
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user.html
If your Principal element contains the ARN for a specific IAM role or user, then that ARN is transformed to a unique principal ID when the policy is saved. This helps mitigate the risk of someone escalating their permissions by removing and recreating the role or user. You don't normally see this ID in the console because there is also a reverse transformation back to the ARN when the trust policy is displayed. However, if you delete the role or user, then the principal ID appears in the console because AWS can no longer map it back to an ARN. Therefore, if you delete and recreate a user or role referenced in a trust policy's Principal element, you must edit the role to replace the ARN.
Running Terraform the first time will recreate the IAM role and that way break the policy. Running it the second time will correct the policy, by adding the newly created reference to the IAM role.

Create ROLE with Terraform in AWS with SAML provider attached

I'm currently trying to automate AWS account provisioning, and one the steps is to create IAM ROLE, with Identity provider(for federated user access).
I searched, and checked Terraform documentation, but cannot find any information about creating such role, or attaching provider to a role.
I can create both just fine, but they are independent.
here is portion of the code:
resource "aws_iam_saml_provider" "default" {
name = "ADFS-TEST"
saml_metadata_document = "${file("../../FederationMetadata.xml")}"
}
resource "aws_iam_role" "role" {
name = "test-Admins"
}
figured out. here is full block
resource "aws_iam_saml_provider" "test" {
name = "ADFS-TEST"
saml_metadata_document = "${file("../../FederationMetadata.xml")}"
}
resource "aws_iam_role" "role" {
name = "ADFStest-Admins"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "${aws_iam_saml_provider.test.arn}"
},
"Action": "sts:AssumeRoleWithSAML",
"Condition": {
"StringEquals": {
"SAML:aud": "https://signin.aws.amazon.com/saml"
}
}
}
]
}
EOF
}
resource "aws_iam_role_policy" "admins" {
name = "Admin-Policy"
#description = "A test policy"
role = "${aws_iam_role.role.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
EOF
}
Thank you! It works for me.
I just change aws_iam_role_policy to use the aws_iam_role_policy_attachment:
resource "aws_iam_role_policy_attachment" "attach" {
role = "${aws_iam_role.role.name}"
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

Terraform: ECS service - InvalidParameterException

I am trying to provision an ECS cluster with terraform, everything seems to work well up until I am creating the ecs service:
resource "aws_ecs_service" "ecs-service" {
name = "ecs-service"
iam_role = "${aws_iam_role.ecs-service-role.name}"
cluster = "${aws_ecs_cluster.ecs-cluster.id}"
task_definition = "${aws_ecs_task_definition.my_cluster.family}"
desired_count = 1
load_balancer {
target_group_arn = "${aws_alb_target_group.ecs-target-group.arn}"
container_port = 80
container_name = "my_cluster"
}
}
and the IAM role is:
resource "aws_iam_role" "ecs-service-role" {
name = "ecs-service-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "ecs-service-role-attachment" {
role = "${aws_iam_role.ecs-service-role.name}"
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole"
}
I am getting the following error message:
aws_ecs_service.ecs-service: 1 error(s) occurred:
aws_ecs_service.ecs-service: InvalidParameterException: Unable to assume role and validate the specified targetGroupArn. Please verify
that the ECS service role being passed has the proper permissions.
In assume_role_policy, can you change the "Principal" line to as mentioned below: You are having ec2.amazonaws.com.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ecs.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}

Terraform: associate an aws_iam_role_policy to an aws_iam_role

I'm attempting to attach an aws_iam_role_policy to an aws_iam_role using Terraform variables: ${aws_iam_role.AutoTagMasterRole.id}
I'm using the TF docs found at: iam_role_policy.html
Terraform error message:
aws_iam_role_policy.AutoTagMasterPolicy: Resource
'aws_iam_role.AutoTagMasterRole' not found for variable
'aws_iam_role.AutoTagMasterRole.arn'
Here's my Terraform configuration:
resource "aws_iam_role_policy" "AutoTagMasterPolicy" {
name = "AutoTagMasterPolicy"
role = "${aws_iam_role.AutoTagMasterRole.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetBucketTagging",
"s3:PutBucketTagging",
"ec2:CreateTags",
"elasticloadbalancing:AddTags",
"autoscaling:CreateOrUpdateTags",
"rds:AddTagsToResource",
"elasticmapreduce:AddTags",
"datapipeline:AddTags"
],
"Resource": [
"*"
]
}
]
}
EOF
}
resource "aws_iam_role" "AutoTagMasterRole" {
name = "AutoTagMasterRole"
path = "/gorillastack/autotag/master/"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": { "${aws_iam_role.AutoTagExecutionRole.arn}" }
},
"Action": [
"sts:AssumeRole"
]
}
]
}
EOF
}
Can someone tell me what it is I've done incorrectly?
UPDATE I've been told this relates to my attempt at porting the cloudformation function to it's equivalent in terraform.
This is what cloudformation lists:
"Principal": {
"AWS" : { "Fn::GetAtt" : [ "AutoTagExecutionRole", "Arn" ] }
},
I am trying to find the equivalent in terraform. This is what I used, but it's throwing the error.
"Principal": {
"AWS": { "${aws_iam_role.AutoTagExecutionRole.arn}" }
}
The definition of Principal is wrong in aws_iam_role
Here is the sample for you.
resource "aws_iam_role" "test_role" {
name = "test_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
So your codes should be changed to
resource "aws_iam_role" "AutoTagMasterRole" {
name = "AutoTagMasterRole"
path = "/gorillastack/autotag/master/"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": [
"sts:AssumeRole"
]
}
]
}
EOF
}
Refer: terraform aws_iam_role
After troubleshooting realized I had incorrect syntax:
"Principal": {
"AWS": { "${aws_iam_role.AutoTagExecutionRole.arn}" }
},
Should be:
"Principal": {
"AWS": "${aws_iam_role.AutoTagExecutionRole.arn}"
},
The incorrect syntax (although not accurately reported by Terraform) caused the aws_iam_role to fail writing to the tf.state file which caused the error message reporting the failure to find the resources.

Terraform: Error creating IAM Role. MalformedPolicyDocument: Has prohibited field Resource

My TF code is giving me an error:
/*
* Policy: AmazonEC2ReadOnlyAccess
*/
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:Describe*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "elasticloadbalancing:Describe*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"cloudwatch:ListMetrics",
"cloudwatch:GetMetricStatistics",
"cloudwatch:Describe*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "autoscaling:Describe*",
"Resource": "*"
}
]
}
EOF
I copied and pasted the Policy from https://console.aws.amazon.com/iam/home?region=us-west-2#/policies/arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess$jsonEditor
* aws_iam_role.<role name>: Error creating IAM Role <role name>: MalformedPolicyDocument: Has prohibited field Resource
status code: 400, request id: <request id>
Not sure why it's saying Resource is prohibited.
Need to define assume_role_policy with sts:AssumeRole (Who can assume this role, ex: EC2 service).
Policy can be directly attached using aws_iam_role_policy_attachment instead of duplicating existing policy.
resource "aws_iam_role" "ec2_iam_role" {
name = "ec2_iam_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "ec2-read-only-policy-attachment" {
role = "${aws_iam_role.ec2_iam_role.name}"
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess"
}
I had faced similar issue when using role arn. When I tried using aws_iam_role_policy_attachment - I was getting error for role name having unsupported characters.
What worked for me for to create a aws_iam_role_policy as below:
resource "aws_iam_role_policy" "api-invoker" {
provider = <some provider>
role = aws_iam_role.api-invoker.id
policy = data.aws_iam_policy_document.execute-api.json
}
data "aws_iam_policy_document" "execute-api" {
statement {
sid = "all"
actions = [
"execute-api:*",
]
resources = [
"*"
]
}
}
I have faced the same issue while i am creating a policy to assume role from another AWS account. So, I have added another AWS account Id in the trusted entities then the problem is resolved.
#create i am user for account-1
resource "aws_iam_user" "user-1" {
name = "my-user"
tags = {
"Name" = "my-user"
}
}
# create policy for 2nd account
resource "aws_iam_policy" "prod_s3" {
provider = aws.aws02
name = "prod_s3"
description = "allow assuming prod_s3 role"
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = "sts:AssumeRole",
Resource = "arn:aws:iam::940883708906:user/my-user"
}]
})
}
# Attach the policy
resource "aws_iam_user_policy_attachment" "prod_s3" {
provider = aws.aws02
user = aws_iam_user.user-1.name
policy_arn = aws_iam_policy.prod_s3.arn
}
# create assume role
resource "aws_iam_role" "prod_list_s3" {
provider = aws.aws02
name = "role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = "sts:AssumeRole",
Principal = { "AWS" : "arn:aws:iam::${data.aws_caller_identity.utils.account_id}:root" }
}]
})
}
# output arn
output "role-arn" {
value = aws_iam_role.prod_list_s3.arn
}
# create caller identity
data "aws_caller_identity" "utils" {
provider = aws.aws02
}
# create s3 full access for 2nd account and attach the file
resource "aws_iam_policy" "s3_all" {
provider = aws.aws02
name = "s3_all"
description = "allows listing all s3 buckets"
policy = file("role_permissions_policy.json")
}
# inside the file
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
]
}
**strong text**
# Attach the assume role
resource "aws_iam_policy_attachment" "s3-all-att" {
name = "list s3 buckets policy to role"
roles = ["${aws_iam_role.prod_list_s3.name}"]
policy_arn = aws_iam_policy.s3_all.arn
provider = aws.aws02