Reputation: 108
I am trying to create some service users with specific roles. I don't want to hardcode the policy documents for my service role.
Example:
service-1 required read access to -EC2 instance, Cloudwatch logs and write access to s3 bucket.
Service-2 needs SNS, SQS, and DynamoDB.
Provider=AWS
Any help will be much appreciated.
How do I create a new policy on runtime and attach it to a role without hardcoding the policy_document JSON in code resource?
Upvotes: 3
Views: 1176
Reputation: 21716
Terraform modules have variables for the parts that vary. Things that don't need to vary should be hardcoded as a best practice.
Otherwise you will be creating modules that do nothing and take code as input.
Any sufficiently complicated [dynamic Terraform module] contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of [Terraform itself]..
remix of Greenspun's tenth rule
data "aws_iam_policy_document" "assume_role_policy" {
statement {
sid = "AllowAssumeRole"
effect = "Allow"
actions = [
"sts:AssumeRole",
]
resources = var.trusted_arns
}
}
You can grant access to a set of AWS buckets as a variable like this:
statement {
sid = "AllowS3Access"
effect = "Allow"
actions = [
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:GetObject",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload",
]
resources = var.allowed_read_only_s3_bucket_arns
}
If you are bent on making dynamic policies you can do this:
data "aws_iam_policy_document" "meta_policy" {
dynamic "statement" {
for_each = var.statements
content {
sid = each.key
effect = each.value.effect
actions = each.value.actions
resources = each.value.resources
}
}
}
Would be used with a variable like this:
variable "statements" {
description = "I didn't want to use resources, so I made meta-Terraform"
type = map(object(
{
sid = string
effect = string
actions = list(string)
resources = list(string)
}
))
}
Someone looking at such a module would have no way of knowing what it needs and would be relying purely on input variables. Maybe this is suitable for your use case, but I recommend against it.
Your colleagues, including your future self will thank you if you embrace hardcoding things that don't actually change.
Upvotes: 1
Reputation: 976
Apart from your question, there is a great document to read about HCL Language. https://github.com/hashicorp/hcl
Now as far as I understand your question, it seems that you want to create a permission module and be able to pass it service-name and permission. That specific method will allow you to reuse the IAM role creation code. I suggest you read https://www.terraform.io/docs/configuration/modules.html.
You can create a Module like IAM Permission and do something like
resource "aws_iam_policy" "policy" {
name = "${var.service_name}"
description = "${var.service_name} access policy"
policy = templatefile("${path.module}/ddb_role.tpl", {
role = var.role
})
}
resource "aws_iam_role" "role" {
name = "role_${var.env}"
assume_role_policy = "${file("assumerolelambdapolicy.json")}"
}
resource "aws_iam_role_policy_attachment" "policy_attachment" {
role = "${aws_iam_role.role.name}"
policy_arn = "${aws_iam_policy.policy.arn}"
}
Template file:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ${role},
"Resource": "*"
}
]
}
var.tf you could store a list of permissions
variable "role" {
type = list
default = [
"sqs:*",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"ec2:Describe*",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSubnets",
"ec2:DescribeVpcs",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface"
]
}
This is something you should be able to override using tfvar file. Try this and let me know.
Upvotes: 1