I'm importing roles which already have been created in AWS console and unfortunately the names are strange. So in order to use those roles I am trying like this
I've two IAM roles as follows
data "aws_iam_role" "reithera-rtcov201" {
name = "exomcloudrosareitherartcov-YRX1M2GJKD6H"
}
data "aws_iam_role" "dompe-rlx0120" {
name = "exomcloudrosadomperlx0120p-1SCGY0RG5JXFF"
}
In this file I have 2 variables as follows:
sponsor = ["reithera", "dompe"]
study = ["rtcov201", "rlx0120"]
I'm trying in the following way, but terraform doesn't allow to use $.
data.aws_iam_role.${var.sponsor}-${var.study}.arn
Do you know any solution for this.
Its not possible. You can dynamically create references to resources.
Instead of two separate data sources you should create one:
variable "iam_roles"
default = ["exomcloudrosareitherartcov-YRX1M2GJKD6H", "exomcloudrosadomperlx0120p-1SCGY0RG5JXFF"]
}
and then
data "aws_iam_role" "role" {
for_each = toset(var.iam_roles)
name = each.key
}
and you can refer to them using role name:
data.aws_iam_role["exomcloudrosareitherartcov-YRX1M2GJKD6H"].arn
Related
This is the terraform shown in the docs:
resource "aws_sagemaker_project" "example" {
project_name = "example"
service_catalog_provisioning_details {
product_id = aws_servicecatalog_product.example.id
}
}
I created a service catalog product with id: "prod-xxxxxxxxxxxxx".
When I substitute the service catalog product id into the above template,
to get the following:
resource "aws_sagemaker_project" "example" {
project_name = "example"
service_catalog_provisioning_details {
product_id = aws_servicecatalog_product.prod-xxxxxxxxxxxxx
}
}
I run terraform plan, but the following error occurs:
A managed resource "aws_servicecatalog_product" "prod-xxxxxxxxxxxxx" has not been declared in the root module.
What do I need to do to fix this error?
Since the documentation is lacking a bit of clarity, in order to have this work as in the example, you would first have to create the Service Catalog product in Terraform as well, e.g.:
resource "aws_servicecatalog_product" "example" {
name = "example"
owner = [aws_security_group.example.id] # <---- This would need to be created first
type = aws_subnet.main.id # <---- This would need to be created first
provisioning_artifact_parameters {
template_url = "https://s3.amazonaws.com/cf-templates-ozkq9d3hgiq2-us-east-1/temp1.json"
}
tags = {
foo = "bar"
}
}
You can reference it then in the SageMaker project the same way as in the example:
resource "aws_sagemaker_project" "example" {
project_name = "example"
service_catalog_provisioning_details {
product_id = aws_servicecatalog_product.example.id
}
}
Each of the resources that gets created has a set of attributes that can be accessed as needed by other resources, data sources or outputs. In order to understand how this works, I strongly suggest reading the documentation about referencing values [1]. Since you already created the Service Catalog product, the only thing you need to do is provide the string value for the product ID:
resource "aws_sagemaker_project" "example" {
project_name = "example"
service_catalog_provisioning_details {
product_id = "prod-xxxxxxxxxxxxx"
}
}
When I can't understand what value is expected by an argument (e.g., product_id in this case), I usually read the docs and look for examples like in [2]. Note: That example is CloudFormation, but it can help you understand what type of a value is expected (e.g., string, number, bool).
You could also import the created Service Catalog product into Terraform so you can manage it with IaC [3]. You should understand all the implications of terraform import though before trying it [4].
[1] https://www.terraform.io/language/expressions/references
[2] https://docs.amazonaws.cn/en_us/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-project.html#aws-resource-sagemaker-project--examples--SageMaker_Project_Example
[3] https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_product#import
[4] https://www.terraform.io/cli/commands/import
Instead of having to update this value manually each time, can I read this value directly into my terraform.tfvars file?
monitoring_role_arn = "arn:aws:iam::account:role/value"
you can use locals
Define in *.tf file
locals {
monitoring_role_arn = "arn:aws:iam::account:role/value"
}
in variables file you can refer as below
your_var = local.monitoring_role_arn
Role lookup option
Alternatively use the IAM Role lookup by the name given to the targeted role.
Ref: Data Source: aws_iam_role
To looup the resource by role name:
data "aws_iam_role" "monitoring_role_arn" {
name = "an_example_role_name" // This is the name of the role that appear in the AWS IAM Console
}
To get the ARN use the following line:
data.aws_iam_role.monitoring_role_arn.arn
I have used terraform scripts to create resources in GCP. The scripts are working fine. But my question is - how do I create multiple storage buckets using a single script.
I have two files for creating the storage bucket-
main.tf which has the terraform code to create the buckets .
variables.tf which has the actual variables like storage bucket name, project_id, etc, which looks like this:
variable "storage_class" { default = "STANDARD" }
variable "name" { default = "internal-demo-bucket-1"}
variable "location" { default = "asia-southeast1" }
How can I provide more than one bucket name in the variable name? I tried to provide multiple names in an array but the build failed.
I don't know all your requirements, however suppose you need to create a few buckets with different names, while all other bucket characteristics are constant for every bucket in the set under discussion.
I would create a variable, i.e. bucket_name_set in a variables.tf file:
variable "bucket_name_set" {
description = "A set of GCS bucket names..."
type = list(string)
}
Then, in the terraform.tfvars file, I would provide unique names for the buckets:
bucket_name_set = [
"some-bucket-name-001",
"some-bucket-name-002",
"some-bucket-name-003",
]
Now, for example, in the main.tf file I can describe the resources:
resource "google_storage_bucket" "my_bucket_set" {
project = "some project id should be here"
for_each = toset(var.bucket_name_set)
name = each.value # note: each.key and each.value are the same for a set
location = "some region should be here"
storage_class = "STANDARD"
force_destroy = true
uniform_bucket_level_access = true
}
Terraform description is here: The for_each Meta-Argument
Terraform description for the GCS bucket is here: google_storage_bucket
Terraform description for input variables is here: Input Variables
Have you considered using terraform provided modules ? It becomes very easy if you use gcs module for bucket creation. It has an option to specify how many buckets you need to create and even the subfolders. I am including the module below for your reference
https://registry.terraform.io/modules/terraform-google-modules/cloud-storage/google/latest
I want access to my AWS Account ID in terraform. I am able to get at it with aws_caller_identity per the documentation. How do I then use the variable I created? In the below case I am trying to use it in an S3 bucket name:
data "aws_caller_identity" "current" {}
output "account_id" {
value = data.aws_caller_identity.current.account_id
}
resource "aws_s3_bucket" "test-bucket" {
bucket = "test-bucket-${account_id}"
}
Trying to use the account_id variable in this way gives me the error A reference to a resource type must be followed by at least one attribute access, specifying the resource name. I expect I'm not calling it correctly?
If you have a
data "aws_caller_identity" "current" {}
then you need to define a local for that value:
locals {
account_id = data.aws_caller_identity.current.account_id
}
and then use it like
output "account_id" {
value = local.account_id
}
resource "aws_s3_bucket" "test-bucket" {
bucket = "test-bucket-${local.account_id}"
}
Terraform resolves the locals based on their dependencies so you can create locals that depend on other locals, on resources, on data blocks, etc.
Any time you create a datasource in terraform , it will export some attributes related to that datasource so that you can reference it somewhere else in your configuration and interpolate it with various ways.
In your case, you are already referencing the value of your account id in output block
So that same way, you can construct the string for the bucket name as follows.
resource "aws_s3_bucket" "test-bucket" {
bucket = "test-bucket-${data.aws_caller_identity.current.account_id}"
}
I would highly recommend you go through the terrraform syntax which can help you better understand the resource, datasource and expressions
https://www.terraform.io/docs/language/expressions/references.html
I'm currently trying to use TF 0.12 to create AWS Organizations accounts. Right now I have a map of accounts with applicable info, here is an example where "Services" is the account name:
accountMap = {
...
Services = {
OU = ["Development", "Production"]
},
...
}
OU refers to the org units the account should be a part of. I'm currently already using for_each to loop through this map of account names, but I'm stuck on how to use the OUs as a suffix, so the org account name would become "Services-Development" and "Services-Production". I have tried similar to the following:
resource "aws_organizations_account" "main" {
for_each = var.ouMap
name = "${each.key}-${var.accountMap["${each.value[*]}"]}"
...
}
However, "name" requires a string and I get an error since I am providing a list of the OUs, but I may want one account to belong to several OUs or just a single OU. So, how can I either convert the list to a string one at a time, while in the same for_each iteration (but for my differing OUs)?
I'm open to other suggestions on best practice to map AWS Org accounts to multiple OUs as I'm still rather new to Terraform.
A local value can be computed using nested for loop in terraform v0.12.
The local value can later be used in resources. This example treats a null resource.
accountMap = {
Services = {
OU = ["Development", "Production"]
}
}
locals {
organization_account = flatten(
[for k, v in var.accountMap: [for v2 in v.OU: "${k}-${v2}"]]
)
}
resource "null_resource" "foo" {
count = length(local.organization_account)
provisioner "local-exec" {
command = "echo ${local.organization_account[count.index]}"
}
}
output "organization_account" {
value = local.organization_account
}