hashicorp / terraform-provider-awscc

Terraform AWS Cloud Control provider
https://registry.terraform.io/providers/hashicorp/awscc/latest/docs
Mozilla Public License 2.0
248 stars 113 forks source link

awscc_iam_role : drift with no changes when policy document is aws datasource #1893

Open quixoticmonk opened 1 month ago

quixoticmonk commented 1 month ago

Community Note

Terraform CLI and Terraform AWS Cloud Control Provider Version

Terraform v1.9.0
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v5.58.0
+ provider registry.terraform.io/hashicorp/awscc v1.6.0

Affected Resource(s)

Terraform Configuration Files

Baseline configuation:

resource "awscc_iam_role" "example" {
  role_name                   = "sample_iam_role"
  description                 = "This is a sample IAM role"
  assume_role_policy_document = data.aws_iam_policy_document.instance_assume_role_policy.json
  path                        = "/"
  policies = [{
    policy_document = data.aws_iam_policy_document.sample_inline_1.json
    policy_name     = "fist_inline_policy"
    }]

}
data "aws_iam_policy_document" "instance_assume_role_policy" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

data "aws_iam_policy_document" "sample_inline_1" {
  statement {
    sid       = "AccessS3"
    actions   = ["s3:ListAllMyBuckets", "s3:ListBucket", "s3:HeadBucket"]
    resources = ["*"]
  }
}

Debug Output

2024-07-19T18:34:24.219-0400 [WARN]  Provider "registry.terraform.io/hashicorp/awscc" produced an unexpected new value for awscc_iam_role.example during refresh.
      - .policies[0].policy_document: was cty.StringVal("{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"AccessS3\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"s3:ListBucket\",\n        \"s3:ListAllMyBuckets\",\n        \"s3:HeadBucket\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}"), but now cty.StringVal("{\"Statement\":[{\"Action\":[\"s3:ListBucket\",\"s3:ListAllMyBuckets\",\"s3:HeadBucket\"],\"Effect\":\"Allow\",\"Resource\":\"*\",\"Sid\":\"AccessS3\"}],\"Version\":\"2012-10-17\"}")
      - .assume_role_policy_document: was cty.StringVal("{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": \"sts:AssumeRole\",\n      \"Principal\": {\n        \"Service\": \"ec2.amazonaws.com\"\n      }\n    }\n  ]\n}"), but now cty.StringVal("{\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}")

2024-07-19T18:34:24.240-0400 [DEBUG] provider.terraform-provider-awscc_v1.6.0_x5: 
Detected value change between proposed new state and prior state: 
tf_rpc=PlanResourceChange @caller=github.com/hashicorp/terraform-plugin-framework@v1.10.0/internal/fwserver/server_planresourcechange.go:208 tf_attribute_path=policies tf_req_id=0fe025bd-3e94-5bd3-aaed-c0eb1a1c34df 
tf_resource_type=awscc_iam_role @module=sdk.framework tf_provider_addr=registry.terraform.io/hashicorp/awscc timestamp=2024-07-19T18:34:24.240-0400

2024-07-19T18:34:24.240-0400 [DEBUG] provider.terraform-provider-awscc_v1.6.0_x5: 
Detected value change between proposed new state and prior state: 
tf_resource_type=awscc_iam_role @caller=github.com/hashicorp/terraform-plugin-framework@v1.10.0/internal/fwserver/server_planresourcechange.go:208 @module=sdk.framework tf_attribute_path=assume_role_policy_document 
tf_rpc=PlanResourceChange tf_provider_addr=registry.terraform.io/hashicorp/awscc tf_req_id=0fe025bd-3e94-5bd3-aaed-c0eb1a1c34df timestamp=2024-07-19T18:34:24.240-0400

Panic Output

Expected Behavior

Terraform apply should maintain the idempotency.

Actual Behavior

With no changes, provider is identifying change and shows a drift


Terraform will perform the following actions:

  # awscc_iam_role.example will be updated in-place
  ~ resource "awscc_iam_role" "example" {
      ~ assume_role_policy_document = jsonencode( # whitespace changes
            {
                Statement = [
                    {
                        Action    = "sts:AssumeRole"
                        Effect    = "Allow"
                        Principal = {
                            Service = "ec2.amazonaws.com"
                        }
                    },
                ]
                Version   = "2012-10-17"
            }
        )
        id                          = "sample_iam_role"
      + managed_policy_arns         = (known after apply)
      + permissions_boundary        = (known after apply)
      ~ policies                    = [
          ~ {
              ~ policy_document = jsonencode( # whitespace changes
                    {
                        Statement = [
                            {
                                Action   = [
                                    "s3:ListBucket",
                                    "s3:ListAllMyBuckets",
                                    "s3:HeadBucket",
                                ]
                                Effect   = "Allow"
                                Resource = "*"
                                Sid      = "AccessS3"
                            },
                        ]
                        Version   = "2012-10-17"
                    }
                )
                # (1 unchanged attribute hidden)
            },
        ]
      + tags                        = (known after apply)
        # (6 unchanged attributes hidden)
    }

Steps to Reproduce

  1. terraform apply
  2. terraform apply

Important Factoids

References

quixoticmonk commented 1 month ago

Could be related to https://github.com/hashicorp/terraform-provider-awscc/issues/509

quixoticmonk commented 1 month ago

Based on the input from #509 you could fix this with the configuration below.

resource "awscc_iam_role" "example" {
  role_name                   = "sample_iam_role"
  description                 = "This is a sample IAM role"
  assume_role_policy_document = jsonencode(jsondecode(data.aws_iam_policy_document.instance_assume_role_policy.json))
  path                        = "/"
  policies = [{
    policy_document = jsonencode(jsondecode(data.aws_iam_policy_document.sample_inline_1.json))
    policy_name     = "fist_inline_policy"
    }]

}
data "aws_iam_policy_document" "instance_assume_role_policy" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

data "aws_iam_policy_document" "sample_inline_1" {
  statement {
    sid       = "AccessS3"
    actions   = ["s3:ListAllMyBuckets", "s3:ListBucket", "s3:HeadBucket"]
    resources = ["*"]
  }
}