Am trying to write a terraform module for attaching bucket policy to a AWS S3 bucket. Here is the code:
data "aws_iam_policy_document" "make_objects_public" {
# if policy_name == <this-policy-name>, then generate policy
count = "${var.policy_name == "make_objects_public" ? 1 : 0}"
statement {
...
}
}
resource "aws_s3_bucket_policy" "bucket_policy" {
# if policy_name != "", then add the generated policy
count = "${var.policy_name != "" ? 1 : 0}"
bucket = "${var.bucket_name}"
policy = "${data.aws_iam_policy_document.<policy-name-goes-here>.json}"
}
I want to interpolate the policy_name
variable while fetching the policy generated by aws_iam_policy_document
. I tried few things but sadly they didn't work. Is this possible in terraform ?
I tried out these hacks:
policy = "${data.aws_iam_policy_document."${var.policy_name}".json}"
policy = "${"${format("%s", "data.aws_iam_policy_document.${var.policy_name}.json")}"}"
policy = "${format("%s", "$${data.aws_iam_policy_document.${var.policy_name}.json}")}"
Thanks.
Embedded within strings in Terraform, whether you're using the Terraform syntax or JSON syntax, you can interpolate other values. These interpolations are wrapped in ${} , such as ${var. foo} . The interpolation syntax is powerful and allows you to reference variables, attributes of resources, call functions, etc.
Variable Provides predefined values as variables on our IAC. Used by resource for provisioning. Data Source: Fetch values from our infra/provider and and provides data for our resource to provision infra/resource.
What are Terraform data sources? Data sources in Terraform are used to get information about resources external to Terraform, and use them to set up your Terraform resources. For example, a list of IP addresses a cloud provider exposes.
Terraform reads data resources during the planning phase when possible, but announces in the plan when it must defer reading resources until the apply phase to preserve the order of operations.
Dynamic resource names are not supported because Terraform must construct the dependency graph before it begins dealing with interpolations, and thus these relationships must be explicit.
A recommended approach for this sort of setup is to break the system down into small modules, which can then be used together by a calling module to produce the desired result without duplicating all of the details.
In this particular situation, you could for example split each policy out into its own re-usable module, and then write one more re-usable module that creates an S3 bucket and associates a given policy with it. Then a calling configuration may selectively instantiate one policy module appropriate to its needs along with the general S3 bucket module, to create the desired result:
module "policy" {
# policy-specific module; only contains the policy data source
source = "../policies/make_objects_public"
# (any other arguments the policy needs...)
}
module "s3_bucket" {
# S3 bucket module creates a bucket and attaches a policy to it
source = "../s3_bucket" # general resource for S3 buckets with attached policies
name = "example"
policy = "${module.policy.policy_json}" # an output from the policy module above
}
As well as avoiding the need for dynamic resource selection, this also increases flexibility by decoupling policy generation from the S3 bucket creation, and in principle allowing a calling module with unusual needs to skip instantiating a policy module altogether and just use aws_iam_policy_document
directly.
The above pattern is somewhat analogous to the dependency injection technique, where the system is split into small components (modules, in this case) and then the root config "wires up" these components in a manner appropriate for a specific use-case. This approach has very similar advantages and disadvantages as the general technique.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With