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.61k stars 9k forks source link

[Bug]: aws_lb_listener import returns invalid configuration, with both default_action.target_group_arn and default_action.forward.target_group.arn #37211

Open robbycuenot opened 2 months ago

robbycuenot commented 2 months ago

Terraform Core Version

1.7.5

AWS Provider Version

5.46.0

Affected Resource(s)

aws_lb_listener

Expected Behavior

When importing a aws_lb_listener resource with aws_lb_listener.example.default_action[0].forward.target_group.arn specified, the value aws_lb_listener.example.default_action[0].target_group_arn should not be included in the returned config, as only one of the two values may be specified.

Actual Behavior

Both values are returned in the plan, showing a change in the configuration when there should not be one.

Example Output:

  # aws_lb_listener.example will be updated in-place
  # (imported from "arn:aws:elasticloadbalancing:us-west-2:012345678901:listener/app/example-app/0123456789012345/0123456789012345")
  ~ resource "aws_lb_listener" "example" {
        arn               = "arn:aws:elasticloadbalancing:us-west-2:012345678901:listener/app/example-app/0123456789012345/0123456789012345"
        certificate_arn   = "arn:aws:acm:us-west-2:012345678901:certificate/01234567-0123-0123-0123-012345678901"
        id                = "arn:aws:elasticloadbalancing:us-west-2:012345678901:listener/app/example-app/0123456789012345/0123456789012345"
        load_balancer_arn = "arn:aws:elasticloadbalancing:us-west-2:012345678901:loadbalancer/app/example-app/0123456789012345"
        port              = 443
        protocol          = "HTTPS"
        ssl_policy        = "ELBSecurityPolicy-2016-08"
        tags              = {}
        tags_all          = {}

      ~ default_action {
            order            = 1
          - target_group_arn = "arn:aws:elasticloadbalancing:us-west-2:012345678901:targetgroup/example-app/0123456789012345" -> null
            type             = "forward"

            forward {
                stickiness {
                    duration = 3600
                    enabled  = false
                }
                target_group {
                    arn    = "arn:aws:elasticloadbalancing:us-west-2:012345678901:targetgroup/example-app/0123456789012345"
                    weight = 1
                }
            }
        }

        mutual_authentication {
            ignore_client_certificate_expiry = false
            mode                             = "off"
        }
    }

Relevant Error/Panic Output Snippet

Attempting to match the returned configuration results in the following error:

│ Error: Invalid Attribute Combination
│ Only one of "default_action[0].target_group_arn" or "default_action[0].forward" can be specified.

Terraform Configuration Files

resource "aws_lb_listener" "example" {
  load_balancer_arn = aws_lb.example.arn
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = aws_acm_certificate.example.arn

  default_action {
    order            = 1
    type             = "forward"
    forward {
      target_group {
        arn = aws_lb_target_group.example-app.arn
        weight = 1
      }
      stickiness {
        enabled = false
        duration = 3600
      }
    }
  }
}

import {
    to = aws_lb_listener.example
    id = "arn:aws:elasticloadbalancing:us-west-2:012345678901:listener/app/example-app/0123456789012345/0123456789012345"
}

Steps to Reproduce

Attempt to import an existing aws_lb_listener resource with aws_lb_listener.example.default_action[0].forward.target_group.arn specified

Debug Output

No response

Panic Output

No response

Important Factoids

No response

References

A similar bugfix was pushed in 5.36.0, per this closed issue: https://github.com/hashicorp/terraform-provider-aws/issues/35621

Would you like to implement a fix?

None

github-actions[bot] commented 2 months ago

Community Note

Voting for Prioritization

Volunteering to Work on This Issue

robbycuenot commented 2 months ago

Note: Import works successfully and does not show drift once the resource has been added to the state

YakDriver commented 1 month ago

@robbycuenot I am not able to reproduce this error with v5.50.0. Let me know if my process below misses something key to reproducing this. Otherwise, if we can't figure a way to reproduce it, we'll need to close this issue.

Step 1 - Create resources

resource "aws_lb_listener" "test" {
  load_balancer_arn = aws_lb.test.arn
  protocol          = "HTTP"
  port              = "80"

  default_action {
    order = 1
    type  = "forward"
    forward {
      target_group {
        arn    = aws_lb_target_group.test.arn
        weight = 1
      }
      stickiness {
        enabled  = false
        duration = 3600
      }
    }
  }
}

resource "aws_lb" "test" {
  name            = "tf-acc-test-007"
  internal        = true
  security_groups = [aws_security_group.test.id]
  subnets         = aws_subnet.test[*].id

  idle_timeout               = 30
  enable_deletion_protection = false

  tags = {
    Name = "tf-acc-test-007"
  }
}

resource "aws_lb_target_group" "test" {
  name     = "tf-acc-test-007"
  port     = 8080
  protocol = "HTTP"
  vpc_id   = aws_vpc.test.id

  health_check {
    path                = "/health"
    interval            = 60
    port                = 8081
    protocol            = "HTTP"
    timeout             = 3
    healthy_threshold   = 3
    unhealthy_threshold = 3
    matcher             = "200-299"
  }

  tags = {
    Name = "tf-acc-test-007"
  }
}

resource "aws_security_group" "test" {
  name        = "tf-acc-test-007"
  description = "Used for ALB Testing"
  vpc_id      = aws_vpc.test.id

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "tf-acc-test-007"
  }
}

resource "aws_vpc" "test" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "tf-acc-test-007"
  }
}

resource "aws_subnet" "test" {
  count = 2

  vpc_id            = aws_vpc.test.id
  availability_zone = data.aws_availability_zones.available.names[count.index]
  cidr_block        = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index)

  tags = {
    Name = "tf-acc-test-007"
  }
}

data "aws_availability_zones" "available" {
  exclude_zone_ids = ["usw2-az4", "usgw1-az2"]
  state            = "available"

  filter {
    name   = "opt-in-status"
    values = ["opt-in-not-required"]
  }
}
% terraform apply
...

Step 2 - Use CLI to set target_group_arn

At this point, on the AWS side, the Terraform config above set aws_lb_listener.test.default_action[0].forward.target_group.arn. On the AWS side, that also set aws_lb_listener.test.default_action[0].target_group_arn. To make double sure, we'll use the AWS CLI to set it.

When we run the command, the AWS CLI output confirms that, on the AWS side, both aws_lb_listener.test.default_action[0].forward.target_group.arn (i.e., Listeners[0].DefaultActions[0].ForwardConfig.TargetGroups[0].TargetGroupArn) and aws_lb_listener.test.default_action[0].target_group_arn (i.e., Listeners[0].DefaultActions[0].TargetGroupArn) are set.

% aws elbv2 modify-listener \
    --listener-arn arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf \
    --default-actions '[{"Type": "forward", "TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tf-acc-test-007/835ece0932270ee3"}]'
{
    "Listeners": [
        {
            "ListenerArn": "arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf",
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/tf-acc-test-007/4579d62c30fbe64b",
            "Port": 80,
            "Protocol": "HTTP",
            "DefaultActions": [
                {
                    "Type": "forward",
                    "TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tf-acc-test-007/835ece0932270ee3",
                    "ForwardConfig": {
                        "TargetGroups": [
                            {
                                "TargetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tf-acc-test-007/835ece0932270ee3",
                                "Weight": 1
                            }
                        ],
                        "TargetGroupStickinessConfig": {
                            "Enabled": false
                        }
                    }
                }
            ]
        }
    ]
}

Step 3 - Import Config

In a separate Terraform environment, we have import config for the listener created earlier:

resource "aws_lb_listener" "test" {
  load_balancer_arn = "arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/tf-acc-test-007/4579d62c30fbe64b"
  protocol          = "HTTP"
  port              = "80"

  default_action {
    order = 1
    type  = "forward"
    forward {
      target_group {
        arn    = "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tf-acc-test-007/835ece0932270ee3"
        weight = 1
      }
      stickiness {
        enabled  = false
        duration = 3600
      }
    }
  }
}

import {
    to = aws_lb_listener.test
    id = "arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf"
}

Step 4 - Import

Performing the import and an extra apply at the end, all behaves as expected:

% terraform apply
aws_lb_listener.test: Preparing import... [id=arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf]
aws_lb_listener.test: Refreshing state... [id=arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_lb_listener.test will be updated in-place
  # (imported from "arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf")
  ~ resource "aws_lb_listener" "test" {
        arn               = "arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf"
        id                = "arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf"
        load_balancer_arn = "arn:aws:elasticloadbalancing:us-west-2:123456789012:loadbalancer/app/tf-acc-test-007/4579d62c30fbe64b"
        port              = 80
        protocol          = "HTTP"
        ssl_policy        = null
        tags              = {}
        tags_all          = {}

      ~ default_action {
          ~ order            = 0 -> 1
          - target_group_arn = "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tf-acc-test-007/835ece0932270ee3" -> null
            type             = "forward"

          ~ forward {
              ~ stickiness {
                  ~ duration = 0 -> 3600
                    enabled  = false
                }
                target_group {
                    arn    = "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tf-acc-test-007/835ece0932270ee3"
                    weight = 1
                }
            }
        }
    }

Plan: 1 to import, 0 to add, 1 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_lb_listener.test: Importing... [id=arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf]
aws_lb_listener.test: Import complete [id=arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf]
aws_lb_listener.test: Modifying... [id=arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf]
aws_lb_listener.test: Modifications complete after 1s [id=arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf]

Apply complete! Resources: 1 imported, 0 added, 1 changed, 0 destroyed.
% terraform apply
aws_lb_listener.test: Refreshing state... [id=arn:aws:elasticloadbalancing:us-west-2:123456789012:listener/app/tf-acc-test-007/4579d62c30fbe64b/85fee0ebb03aefbf]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
joshgubler commented 3 weeks ago

This is still broken for us when trying to bump to aws provider 5.54.1. Here is the relevant config.

robbycuenot commented 3 weeks ago

@YakDriver I think I may have misstated the issue. When you attempt to import the config as you've shown in your example, terraform detects a change on the target group, when there should not be one:

 - target_group_arn = "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tf-acc-test-007/835ece0932270ee3" -> null

Applying this works and doesn't appear to break anything, but can be confusing. At the time, I was importing resources and did not want to cause any changes.

However, if you make the resource block match the config shown from the plan, the error is thrown:

│ Error: Invalid Attribute Combination
│ Only one of "default_action[0].target_group_arn" or "default_action[0].forward" can be specified.

In short, it seems that the data returned from the plan does not match what should be defined in the resource block.

Let me know if this makes sense or if I am missing something in the explanation. Thanks!