hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.8k stars 9.15k forks source link

[Bug]: Value Conversion Error with `aws_iam_role_policy_attachments_exclusive` and `null` values for `policy_arns` #39786

Open matthewbarreiro opened 9 hours ago

matthewbarreiro commented 9 hours ago

Terraform Core Version

1.9.8

AWS Provider Version

v5.72.0

Affected Resource(s)

aws_iam_role_policy_attachments_exclusive

Expected Behavior

If the policy_arns field should support null values (e.g. for use-cases such as this), then:

Otherwise:

Actual Behavior

I get a Value Conversion Error on terraform apply.

Relevant Error/Panic Output Snippet

│ Error: Value Conversion Error
│ 
│   with aws_iam_role_policy_attachments_exclusive.broken_example,
│   on main.tf line 55, in resource "aws_iam_role_policy_attachments_exclusive" "broken_example":
│   55: resource "aws_iam_role_policy_attachments_exclusive" "broken_example" {
│ 
│ An unexpected error was encountered trying to build a value. This is always an error in the provider. Please report the following to the provider developer:
│ 
│ Received null value, however the target type cannot handle null values. Use the corresponding `types` package type, a pointer type or a custom type that handles null values.
│ 
│ Path: [Value(<null>)]
│ Target Type: string
│ Suggested `types` Type: basetypes.StringValue
│ Suggested Pointer Type: *string

Terraform Configuration Files

terraform {
  required_version = ">= 1.3.6"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.72.0"
    }
  }
}

locals {
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

variable "attach_specific_policy" {
  type    = bool
  default = false
}

resource "aws_iam_role" "working" {
  name               = "RoleToDemonstrateSuccess"
  assume_role_policy = local.assume_role_policy
}

resource "aws_iam_role" "broken" {
  name               = "RoleToDemonstrateFail"
  assume_role_policy = local.assume_role_policy
}

resource "aws_iam_role_policy_attachments_exclusive" "working_example" {
  role_name = aws_iam_role.working.name
  policy_arns = flatten([
    [
      "arn:aws:iam::aws:policy/AmazonS3FullAccess",
      "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",
    ],
    var.attach_specific_policy == true ? ["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"] : [],
  ])
}

resource "aws_iam_role_policy_attachments_exclusive" "broken_example" {
  role_name = aws_iam_role.broken.name
  policy_arns = [
    "arn:aws:iam::aws:policy/AmazonS3FullAccess",
    "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",
    var.attach_specific_policy == true ? "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" : null,
  ]
}

Steps to Reproduce

Run terraform init && terraform apply

Debug Output

Full debug output: debug_output.md

Output with Debug Logging Disabled:

 ➜ ☁ sbx01 bugreport git:(main) ✗ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching ">= 5.72.0"...
- Installing hashicorp/aws v5.72.1...
- Installed hashicorp/aws v5.72.1 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

 ➜ ☁ sbx01 bugreport git:(main) ✗ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_iam_role.broken will be created
  + resource "aws_iam_role" "broken" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ec2.amazonaws.com"
                        }
                      + Sid       = ""
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "RoleToDemonstrateFail"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = (known after apply)
      + unique_id             = (known after apply)
    }

  # aws_iam_role.working will be created
  + resource "aws_iam_role" "working" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ec2.amazonaws.com"
                        }
                      + Sid       = ""
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "RoleToDemonstrateSuccess"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = (known after apply)
      + unique_id             = (known after apply)
    }

  # aws_iam_role_policy_attachments_exclusive.broken_example will be created
  + resource "aws_iam_role_policy_attachments_exclusive" "broken_example" {
      + policy_arns = [
          + "arn:aws:iam::aws:policy/AmazonS3FullAccess",
          + "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",
          + null,
        ]
      + role_name   = "RoleToDemonstrateFail"
    }

  # aws_iam_role_policy_attachments_exclusive.working_example will be created
  + resource "aws_iam_role_policy_attachments_exclusive" "working_example" {
      + policy_arns = [
          + "arn:aws:iam::aws:policy/AmazonS3FullAccess",
          + "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",
        ]
      + role_name   = "RoleToDemonstrateSuccess"
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_iam_role.broken: Creating...
aws_iam_role.working: Creating...
aws_iam_role.broken: Creation complete after 0s [id=RoleToDemonstrateFail]
aws_iam_role_policy_attachments_exclusive.broken_example: Creating...
aws_iam_role.working: Creation complete after 0s [id=RoleToDemonstrateSuccess]
aws_iam_role_policy_attachments_exclusive.working_example: Creating...
aws_iam_role_policy_attachments_exclusive.working_example: Creation complete after 1s
╷
│ Error: Value Conversion Error
│ 
│   with aws_iam_role_policy_attachments_exclusive.broken_example,
│   on main.tf line 53, in resource "aws_iam_role_policy_attachments_exclusive" "broken_example":
│   53: resource "aws_iam_role_policy_attachments_exclusive" "broken_example" {
│ 
│ An unexpected error was encountered trying to build a value. This is always an error in the provider. Please report the following to the provider developer:
│ 
│ Received null value, however the target type cannot handle null values. Use the corresponding `types` package type, a pointer type or a custom type that handles null values.
│ 
│ Path: [Value(<null>)]
│ Target Type: string
│ Suggested `types` Type: basetypes.StringValue
│ Suggested Pointer Type: *string
╵

Panic Output

No response

Important Factoids

It's possible this isn't supposed to work like this at all, though I still feel like the value conversion error should be handled regardless.

Side note: using "" instead of null for the right side of the conditional does not work either.

 var.attach_specific_policy == true ? "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" : "",

However the AWS SDK returns an error for this case:

│ Error: creating AWS IAM (Identity & Access Management) Role Policy Attachments Exclusive ("RoleToDemonstrateFail01"): attaching IAM Policy () to IAM Role (RoleToDemonstrateFail01): operation error IAM: AttachRolePolicy, https response error StatusCode: 400, RequestID: <removed>, api error ValidationError: 1 validation error detected: Value '' at 'policyArn' failed to satisfy constraint: Member must have length greater than or equal to 20

References

No response

Would you like to implement a fix?

None

github-actions[bot] commented 9 hours ago

Community Note

Voting for Prioritization

Volunteering to Work on This Issue