Terrafom 0.12.6 map variable with count interpolation - amazon-web-services

I am trying to attach a list of policy ARN that I've been created as a map list. Please see below:
variables.tf:
variable "arns_map" { type = "map"
default = {
default = [
"default"
]
bakery = [
"arn:aws:iam::aws:policy/AmazonECS_FullAccess",
"arn:aws:iam::aws:policy/AmazonS3FullAccess",
"arn:aws:iam::aws:policy/AmazonSNSFullAccess"
]
lambda = [
"arn:aws:iam::aws:policy/AWSLambdaFullAccess"
]
media-server = [
"arn:aws:iam::aws:policy/AmazonSQSFullAccess",
"arn:aws:iam::aws:policy/AmazonS3FullAccess",
"arn:aws:iam::aws:policy/AmazonElasticTranscoder_FullAccess",
"arn:aws:iam::aws:policy/AmazonECS_FullAccess",
"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
]
recognition = [
"arn:aws:iam::aws:policy/AmazonESFullAccess",
"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",
"arn:aws:iam::aws:policy/AmazonS3FullAccess",
"arn:aws:iam::aws:policy/AmazonECS_FullAccess"
]
frontends = [
"arn:aws:iam::aws:policy/CloudFrontFullAccess"
]
elasticbeanstalk = [
"arn:aws:iam::aws:policy/AWSElasticBeanstalkFullAccess"
]
docker = [
"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess"
]
media = [
"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",
"arn:aws:iam::aws:policy/AmazonSQSFullAccess",
"arn:aws:iam::aws:policy/AmazonS3FullAccess",
"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
] } }
My resources are these ones:
main.tf
resource "aws_iam_role" "tenant_roles" {
count = length(var.role_names)
name = element(var.role_names, count.index)
description = "Dedicated role for tenants"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "${var.kops_nodes_role_arn}"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
tags = {
Managedby = "terraform"
}
}
resource "aws_iam_role_policy_attachment" "tenant_policies" {
count = length(values(var.arns_map))
role = join(",", keys(var.arns_map))
# policy_arn = element(var.role_names, count.index)
policy_arn = join(",", values(var.arns_map))
depends_on = [
aws_iam_role.tenant_roles,
]
}
I am getting the following error:
Error: Invalid function argument
on ../../_platform_modules/roles/main.tf line 38, in resource "aws_iam_role_policy_attachment" "tenant_policies":
38: policy_arn = join(",", values(var.arns_map))
|----------------
| var.arns_map is map of list of string with 9 elements
Invalid value for "lists" parameter: incorrect list element type: string
required.
Error: Invalid function argument
on ../../_platform_modules/roles/main.tf line 38, in resource "aws_iam_role_policy_attachment" "tenant_policies":
38: policy_arn = join(",", values(var.arns_map))
|----------------
| var.arns_map is map of list of string with 9 elements
Invalid value for "lists" parameter: incorrect list element type: string
required.
I am using terraform 0.12.6 to manage AWS resources.
Any idea on how to do that?
Thanks in advance

That's because aws_iam_role_policy_attachment requires stringified arn's from aws_iam_policy resource as described in the example and you are trying to provide a list(string).
I have limited experience with AWS IAM and I'm not sure about role parameter, but looks like you want to iterate over map. Like this:
resource "aws_iam_role_policy_attachment" "tenant_policies" {
count = length(keys(var.arns_map))
role = element(keys(var.arns_map), count.index)
policy_arn = join(",", var.arns_map[element(keys(var.arns_maps), count.index))]
}
Also you can use local variables with it:
locals {
arns_keys = keys(var.arns_map)
arns_values = [for k in keys(var.arns_map) : join(",", var.arns_map[k])]
}
resource "aws_iam_role_policy_attachment" "tenant_policies" {
count = length(local.arns_keys)
role = join(",", local.arns_keys)
policy_arn = element(local.arns_values, count.index)
}

Related

Terraform use each.value.policy_name in data to retrieve specific policy dynamically

I want to create IAM Role and Policies automatically and attach policies to the role respectively:
variables.tf
variable "roles" {
type = map(object({
role_name = string
role_description = string
policies = map(object({ policy_name = string, policy_description = string }))
})
)}
terraform.tfvars
roles = {
"aws-config-role-1" = {
role_name = "aws-config-s3"
role_description = "Custom AWSConfig Service Role for the Recorder to record s3 only"
policies = {
"s3" = {
policy_name = "s3",
policy_description = "Custom policy for AWSConfigRecorder Service Role to allow record only S3 resources"
},
"policy" = {
policy_name = "policy",
policy_description = "Custom policy for AWSConfigRecorder Service Role"
}
}
policy_description = "S3 Policy to get list of all s3 buckets in the account"
}
"aws-config-role-2" = {
role_name = "aws-config-ebs"
role_description = "Custom AWSConfig Service Role for the Recorder to allow record only ec2 ebs resources"
policies = {
"ebs" = {
policy_name = "ebs",
policy_description = "Custom policy for AWSConfigRecorder Service Role to record ebs volumes"
}
}
policy_description = "EBS Policy to get list of all ec2 ebs volumes in the account"
}
}
Each role can have different amount of policies, in my example aws-config-role-1 has 2 policies(s3 and policy) and aws-config-role-2 has only 1 policy(ebs)
Now I need to use locals and flatten function so each role has a list of policies respectively
locals.tf
locals {
policies = flatten([
for role_key, role in var.roles : [
for policy_key, policy in role.policies : {
role_key = role_key
role_name = role.role_name
role_description = role.role_description
policy_key = policy_key
policy_name = policy.policy_name
policy_description = policy.policy_description
}
]
])
}
in terraform console:
> local.policies
[
{
"policy_description" = "Custom policy for AWSConfigRecorder Service Role"
"policy_key" = "policy"
"policy_name" = "policy"
"role_description" = "Custom AWSConfig Service Role for the Recorder to record s3 only"
"role_key" = "aws-config-role-1"
"role_name" = "aws-config-s3"
},
{
"policy_description" = "Custom policy for AWSConfigRecorder"
"policy_key" = "s3"
"policy_name" = "s3"
"role_description" = "Custom AWSConfig Role for s3"
"role_key" = "aws-config-role-1"
"role_name" = "aws-config-s3"
},
{
"policy_description" = "Custom policy for AWSConfigRecorder"
"policy_key" = "ebs"
"policy_name" = "ebs"
"role_description" = "Custom AWSConfig Role for ebs"
"role_key" = "aws-config-role-2"
"role_name" = "aws-config-ebs"
},
]
Creating roles and policies
roles.tf
resource "aws_iam_role" "this" {
for_each = var.roles
name = "${var.project}-${var.env}-${each.value["role_name"]}-role"
path = "/${var.project}/${var.module_name}/"
description = each.value["role_description"]
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "config.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
POLICY
}
then I create policies
resource "aws_iam_policy" "this" {
for_each = {
for policy in local.policies : "${policy.role_key}.${policy.policy_name}" => policy
}
name = "${var.project}-${var.env}-${each.value.policy_name}-Policy"
policy = "data.aws_iam_policy_document.${each.value.policy_name}.json"
path = "/${var.project}/${var.module_name}/"
description = each.value.policy_description
}
and data.tf where all policies defined
data "aws_iam_policy_document" "s3" {
statement {
sid = "GetListS3"
effect = "Allow"
actions = [
"s3:GetAccelerateConfiguration",
"s3:GetAccessPoint",
"s3:GetAccessPointPolicy",
"s3:GetAccessPointPolicyStatus",
"s3:GetAccountPublicAccessBlock",
"s3:GetBucketAcl",
"s3:GetBucketCORS",
"s3:GetBucketLocation",
"s3:GetBucketLogging",
"s3:GetBucketNotification",
"s3:GetBucketObjectLockConfiguration",
"s3:GetBucketPolicy",
"s3:GetBucketPublicAccessBlock",
"s3:GetBucketRequestPayment",
"s3:GetBucketTagging",
"s3:GetBucketVersioning",
"s3:GetBucketWebsite",
"s3:GetEncryptionConfiguration",
"s3:GetLifecycleConfiguration",
"s3:GetReplicationConfiguration",
"s3:ListAccessPoints",
"s3:ListAllMyBuckets",
"s3:ListBucket"
]
resources = [
"arn:aws:s3:::*"
]
}
}
data "aws_iam_policy_document" "ebs" {
statement {
sid = "ListEBSVolumes"
effect = "Allow"
actions = [
"ec2:Describe*",
"ec2:GetEbsEncryptionByDefault"
]
resources = ["*"]
}
}
data "aws_iam_policy_document" "policy" {
statement {
sid = "Pol"
effect = "Allow"
actions = ["ec2:Describe*"]
resources = ["*"]
}
}
but when I run terraform plan
in aws_iam_policy.this policy field transformed into string instead of data value and I get an error
│ Error: "policy" contains an invalid JSON policy
│
│ with aws_iam_policy.this["aws-config-role-1.policy"],
│ on roles.tf line 31, in resource "aws_iam_policy" "this":
│ 31: policy = "data.aws_iam_policy_document.${each.value.policy_name}.json"
Basically if I look inside policy it contains string
policy =data.aws_iam_policy_document.s3.json insted of actual data
Is there a way around this? Please advice.
You can't dynamically create references to data sources in the following way:
policy = "data.aws_iam_policy_document.${each.value.policy_name}.json"
This will result in your policy being literal string, e.g. "data.aws_iam_policy_document.s3.json", not its outcome the way you may think it should work.
You have to fully refactor your design, probably using for_each with your aws_iam_policy_document and dynamic blocks.

Fix "User: anonymous is not authorized to perform"

I struggle to have an AWS Lambda function to connect to an AWS ElasticSearch cluster.
I have an AWS Lambda function defined as the following:
resource "aws_lambda_function" "fun1" {
function_name = "fun1"
role = aws_iam_role.ia0.arn
vpc_config {
security_group_ids = local.security_group_ids
subnet_ids = local.subnet_ids
}
environment {
variables = {
ELASTICSEARCH_ENDPOINT = "https://${aws_elasticsearch_domain.es.endpoint}"
}
}
}
resource "aws_iam_role" "ia0" {
name = "lambda-exec-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "lambda_logs" {
role = aws_iam_role.ia0.id
policy_arn = aws_iam_policy.lambda_logging.arn
}
data "aws_iam_policy" "AWSLambdaBasicExecutionRole" {
arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
resource "aws_iam_role_policy_attachment" "AWSLambdaBasicExecutionRole" {
role = aws_iam_role.ia0.id
policy_arn = data.aws_iam_policy.AWSLambdaBasicExecutionRole.arn
}
data "aws_iam_policy" "AWSLambdaVPCAccessExecutionRole" {
arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}
resource "aws_iam_role_policy_attachment" "AWSLambdaVPCAccessExecutionRole" {
role = aws_iam_role.ia0.id
policy_arn = data.aws_iam_policy.AWSLambdaVPCAccessExecutionRole.arn
}
My VPC is defined like that:
locals {
security_group_ids = [aws_security_group.sg0.id]
subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id]
}
resource "aws_vpc" "vpc0" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}
resource "aws_subnet" "private_a" {
vpc_id = aws_vpc.vpc0.id
cidr_block = cidrsubnet(aws_vpc.vpc0.cidr_block, 2, 1)
availability_zone = "eu-west-3a"
}
resource "aws_subnet" "private_b" {
vpc_id = aws_vpc.vpc0.id
cidr_block = cidrsubnet(aws_vpc.vpc0.cidr_block, 2, 2)
availability_zone = "eu-west-3b"
}
resource "aws_security_group" "sg0" {
vpc_id = aws_vpc.vpc0.id
}
Finally my cluster looks like that:
resource "aws_elasticsearch_domain" "es" {
domain_name = "es"
elasticsearch_version = "7.9"
cluster_config {
instance_count = 2
zone_awareness_enabled = true
instance_type = "t2.small.elasticsearch"
}
domain_endpoint_options {
enforce_https = true
tls_security_policy = "Policy-Min-TLS-1-2-2019-07"
}
ebs_options {
ebs_enabled = true
volume_size = 10
}
vpc_options {
security_group_ids = local.security_group_ids
subnet_ids = local.subnet_ids
}
}
resource "aws_iam_role_policy" "rp0" {
name = "rp0"
role = aws_iam_role.ia0.id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"es:*"
],
"Resource": [
"${aws_elasticsearch_domain.es.arn}",
"${aws_elasticsearch_domain.es.arn}/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"${aws_subnet.private_a.cidr_block}",
"${aws_subnet.private_b.cidr_block}"
]
}
}
},
{
"Effect": "Allow",
"Action": [
"ec2:DescribeVpcs",
"ec2:DescribeVpcAttribute",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups",
"ec2:DescribeNetworkInterfaces",
"ec2:CreateNetworkInterface",
"ec2:CreateNetworkInterfacePermission",
"ec2:DeleteNetworkInterface"
],
"Resource": [
"*"
]
}
]
}
EOF
}
Despite of that I still get this answer
Response
{ responseStatus = Status {statusCode = 403, statusMessage = "Forbidden"}
, responseVersion = HTTP/1.1
, responseHeaders =
[("Date","xxx")
,("Content-Type","application/json")
,("Content-Length","72")
,("Connection","keep-alive")
,("x-amzn-RequestId","xxx")
,("Access-Control-Allow-Origin","*")
]
, responseBody = "{\"Message\":\"User: anonymous is not authorized to perform: es:ESHttpPut\"}\"
, responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose
}"
According to AWS documentation using CIDR should be sufficient, but in practice, something is missing.
Thanks in advance for your help.
you need to sign the request before making a http call to tell Elastic search from who is initiating the request. I don't know which programming language you are using, here is what we can do in NodeJs
For simple http call
let request = new (AWS as any).HttpRequest(endpoint, 'us-east-1');
let credentials = new AWS.EnvironmentCredentials('AWS');
let signers = new (AWS as any).Signers.V4(request, 'es');
signers.addAuthorization(credentials, new Date());
if you are using a package like #elastic/elasticsearch, you can combine http-aws-es to create a client which creates a signature , might look something like
let options = {
hosts: [ yourHost ],
connectionClass: require('http-aws-es'),
awsConfig: new AWS.Config({ region: 'us-east-1', credentials: new AWS.EnvironmentCredentials('AWS') })
};
client = require('elasticsearch').Client(options);

Terraform malformed policy

I'm working on importing kms into terraform, I have imported these resources, but when i try to run a terraform plan its rearranging the arn's and hence the last arn has a comma. Thus my terraform apply is failing.
Is there anyway I can avoid this rearranging? I think in this case i should be using a data block instead of adding the policy directly. But i'm not sure how to pass the data block ..
Looks like i can't use a data block, Is there any way i can to avoid the rearranging on arn in Principal block?
I'm using terraform 0.12.20
policy.json.tpl
{
"Version": "2012-10-17",
"Id": "key-policy-1",
"Statement": [{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": ${allowed_resources}
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": ${allowed_resources}
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
}
]
}
main.tf
resource "aws_kms_key" "key" {
description = ""
tags = local.common_tags
policy = templatefile("${path.module}/policy.json.tpl", {
allowed_resources = var.allowed_resources
})
}
variables.tf
variable "allowed_resources" {
description = "list of all principal resources"
type = list(string)
default = [
"arn:aws:iam::xxxxxxxxxxxx:user/a",
"arn:aws:iam::xxxxxxxxxxxxx:user/b",
"arn:aws:iam::xxxxxxxxxx:user/c",
"arn:aws:iam::xxxxxxxxxx:role/abc
]
}
Error
10:53:19 Error: MalformedPolicyDocumentException: Policy contains a statement with one or more invalid principals.
10:53:19
10:53:19 on main.tf line 8, in resource "kms_key" "key":
10:53:19 8: resource "aws_kms_key" "key" {
Terraform plan:
Terraform will perform the following actions:
# aws_kms_key.amp_key will be updated in-place
~ resource "aws_kms_key" "amp_key" {
arn = "arn:aws:kms:us-east-1:xxxx:key/xxx-xxx-xxx-xx-xxxxxxxx"
customer_master_key_spec = "SYMMETRIC_DEFAULT"
enable_key_rotation = false
id = "xxx-xxx-xxx-xx-xxxxxxxx"
is_enabled = true
key_id = "xxx-xxx-xxx-xx-xxxxxxxx"
key_usage = "ENCRYPT_DECRYPT"
~ policy = jsonencode(
~ {
Id = "key-policy-1"
~ Statement = [
{
Action = "kms:*"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::xxxxxxxx:root"
}
Resource = "*"
Sid = "Enable IAM User Permissions"
},
~ {
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey",
]
Effect = "Allow"
~ Principal = {
~ AWS = [
+ "arn:aws:iam::xxxxxx:user/c",
+ "arn:aws:iam::xxxxxx:user/a",
- "arn:aws:iam::xxxxxx:role/abc",
- "arn:aws:iam::xxxxxx:user/a",
- "arn:aws:iam::xxxxxx:user/c",
"arn:aws:iam::xxxxxx:user/b",
+ "arn:aws:iam::xxxxxx:role/abc",
]
}
]
Version = "2012-10-17"
}
)
When i tried to use data block
data "template_file" "temp_file" {
template = "${file("${path.module}/amp_key_policy.json.tpl")}"
vars = {
allowed_resources = "${var.allowed_resources}" //tried without quotes
}
}
resource "aws_kms_key" "amp_key" {
description = ""
tags = local.common_tags
policy = data.template_file.temp_file.rendered
}
Error: Incorrect attribute value type
on main.tf line 10, in data "template_file" "temp_file":
10: vars = {
11: allowed_resources = "${var.allowed_resources}"
12: }
Inappropriate value for attribute "vars": element "allowed_resources": string
required.
Updated:
i tried using aws_iam_policy_document.
data "aws_iam_policy_document" "amp_key_doc" {
for_each = toset(var.allowed_resources)
statement {
sid = "Enable IAM User Permissions"
effect = "Allow"
principals {
identifiers = ["arn:aws:iam::xxxxx:root"]
type = "AWS"
}
actions = ["kms:*"]
resources = ["*"]
}
statement {
sid = "Allow access for Key Administrators"
effect = "Allow"
principals {
identifiers = ["arn:aws:iam::xxxx:user/a"]
type = "AWS"
}
actions = [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"]
resources = ["*"]
}
statement {
sid = "Allow use of the key"
effect = "Allow"
principals {
identifiers = [var.allowed_resources]
type = "AWS"
}
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
resources = ["*"]
}
statement {
sid = "Allow attachment of persistent resources"
effect = "Allow"
principals {
identifiers = [var.allowed_resources]
type = "AWS"
}
actions = [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
]
resources = ["*"]
condition {
test = "Bool"
values = ["true"]
variable = "kms:GrantIsForAWSResource"
}
}
}
resource "aws_kms_key" "key" {
description = ""
tags = local.common_tags
policy = data.aws_iam_policy_document.key_doc.json
Got an error , How do we pass the entire chunk of allowed_resources?
Error: Incorrect attribute value type
on data.tf line 43, in data "aws_iam_policy_document" "key_doc":
43: identifiers = [var.allowed_resources]
Inappropriate value for attribute "identifiers": element 0: string required.
Error: Incorrect attribute value type
on data.tf line 60, in data "aws_iam_policy_document" "key_doc":
60: identifiers = [var.allowed_resources]
Inappropriate value for attribute "identifiers": element 0: string required.
The error comes down to values of vars only supporting primitive types as stated in the documentation
Variables for interpolation within the template. Note that variables must all be primitives. Direct references to lists or maps will cause a validation error.
If you create your policy as a iam_policy_document you can use the json attribute of the resource to pass into your aws_kms_key resource.

invalid ARN error on terraform when creating eks cluster

**resource "aws_iam_role" "eks_role" {
name = "eks_role"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "eks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "AmazonEKSClusterPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
role = "aws_iam_role.eks_role.name"
}
resource "aws_iam_role_policy_attachment" "AmazonEKSServicePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSServicePolicy"
role = "aws_iam_role.eks_role.name"
}
resource "aws_eks_cluster" "t3_eks" {
name = "t3_eks"
role_arn = "aws_iam_role.eks_role.arn"
vpc_config {
security_group_ids = var.sg
subnet_ids = var.subnets
endpoint_private_access = false
endpoint_public_access = true
}
depends_on = [
aws_iam_role_policy_attachment.AmazonEKSClusterPolicy,
aws_iam_role_policy_attachment.AmazonEKSServicePolicy,
]
}**
Error message
Error: "role_arn" (aws_iam_role.eks_role.arn) is an invalid ARN: arn: invalid prefix
on EKS\main.tf line 30, in resource "aws_eks_cluster" "t3_eks":
30: resource "aws_eks_cluster" "t3_eks" {
Please could someone guide as to what could be wrong?
Quotes are important with terraform. In 0.12 the quoted string "aws_iam_role.eks_role.arn" is just a string. In order for it to be interpolated as an actual variable, you need to remove the quotes:
resource "aws_eks_cluster" "t3_eks" {
name = "t3_eks"
role_arn = aws_iam_role.eks_role.arn
It is also possible to interpolate a variable inside of a string, which is required for terraform 0.11 or older:
resource "aws_eks_cluster" "t3_eks" {
name = "t3_eks"
role_arn = "${aws_iam_role.eks_role.arn}"

Inappropriate value for attribute "bucket_arn": string required while creating AWS firehose resource in terraform

I am trying to learn terraform here but I am facing some issue while creating AWS resource.
I am trying to create AWS firehose delivery stream but I am getting error in when I try to generate the plan.
I am trying to pass the role and s3 buck I created to firehose resource but getting error.
thanks in advance.
terraform {
required_version = ">=0.12.0"
}
provider "aws" {
version = "~> 2.0"
region = "ap-south-1"
}
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "bucket1" {
bucket = "${data.aws_caller_identity.current.account_id}-kinesis-firehose-bucket1"
}
resource "aws_iam_role" "firehose_role" {
name = "firehose_test_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "firehose.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_kinesis_firehose_delivery_stream" "test_stream" {
name = "big-data-cert-delivery-stream"
destination = "s3"
s3_configuration {
role_arn = "${aws_iam_role.firehose_role}"
bucket_arn = "${aws_s3_bucket.bucket1}"
}
}
Error: Incorrect attribute value type
on kinesis-stream.tf line 41, in resource "aws_kinesis_firehose_delivery_stream" "test_stream":
41: role_arn = "${aws_iam_role.firehose_role}"
|----------------
| aws_iam_role.firehose_role is object with 13 attributes
Inappropriate value for attribute "role_arn": string required.
Error: Incorrect attribute value type
on kinesis-stream.tf line 42, in resource "aws_kinesis_firehose_delivery_stream" "test_stream":
42: bucket_arn = "${aws_s3_bucket.bucket1}"
|----------------
| aws_s3_bucket.bucket1 is object with 25 attributes
Inappropriate value for attribute "bucket_arn": string required.
adding .arn at the end of resource( iam role, s3 bucket) works.
required_version = ">=0.12.0"
}
provider "aws" {
version = "~> 2.0"
region = "ap-south-1"
}
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "bucket1" {
bucket = "${data.aws_caller_identity.current.account_id}-kinesis-firehose-bucket1"
}
resource "aws_iam_role" "firehose_role" {
name = "firehose_test_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "firehose.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_kinesis_firehose_delivery_stream" "test_stream" {
name = "big-data-cert-delivery-stream"
destination = "s3"
s3_configuration {
role_arn = aws_iam_role.firehose_role.arn
bucket_arn = aws_s3_bucket.bucket1.arn
}
}