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.84k stars 9.19k forks source link

[Bug]: unnecessary S3 permission from elasticbeanstalk #32977

Open kzw opened 1 year ago

kzw commented 1 year ago

Terraform Core Version

1.5.5

AWS Provider Version

5.10.0

Affected Resource(s)

When running terraform plan in our ci/cd pipeline which has been restricted with minimum set of permission, we get an error of the following form

reading Elastic Beanstalk Environment (e-awcub2x7yr) configuration settings: InvalidParameterValue: Access Denied: S3Bucket=elasticbeanstalk-env-resources-us-east-1, S3Key=eb_patching_resources/instance_patch_extension.linux (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: K9PX0S111K24ZX6A; Proxy: null)

This object eb_patching_resources/instance_patch_extension.linux is publicly retrievable with http protocol and the bucket elasticbeanstalk-env-resources-us-east-1 belongs to AWS not to any AWS customers.

I had to add s3 GetObject permission to ci/cd pipeline to get around this permission problem.

Please use http protocol to get this object not s3 api. It's possible that this is the problem with the AWS SDK you are using.

Expected Behavior

No error without any s3 GetObject to the public bucket elasticbeanstalk-env-resources-us-east-1

Actual Behavior

Error as described above

Relevant Error/Panic Output Snippet

No response

Terraform Configuration Files

resource "aws_elastic_beanstalk_application" "this" {
  for_each    = toset(local.apps)
  name        = each.key
  description = "${each.key} app"
}

resource "aws_elastic_beanstalk_environment" "this" {
  for_each            = toset(local.apps)
  name                = "${local.env}-${each.key}"
  application         = aws_elastic_beanstalk_application.this[each.key].name
  solution_stack_name = "64bit Amazon Linux 2023 v4.0.3 running Python 3.9"
  dynamic "setting" {
    for_each = local.settings
    iterator = each
    content {
      namespace = each.value.ns
      name      = each.value.name
      value     = each.value.value
    }
  }
}

data "aws_region" "this" {}

locals {
  vpc_id  = "vpc-<redacted>"
  subnets = ["subnet-<redacted>"]
  acm     = "arn:aws:acm:us-east-1:<redacted>:certificate/<redacted>"

  env       = "sandbox"
  apps      = ["sandbox-app"]
  env_names = [for a in local.apps : "${local.env}-${a}"]
  settings = [
    {
      ns    = "aws:autoscaling:asg"
      name  = "MinSize"
      value = "1"
    },
    {
      ns    = "aws:autoscaling:asg"
      name  = "MaxSize"
      value = "1"
    },
    {
      ns    = "aws:autoscaling:launchconfiguration"
      name  = "InstanceType"
      value = "t3.micro"
    },
    {
      ns    = "aws:ec2:vpc"
      name  = "AssociatePublicIpAddress"
      value = "true"
    },
    {
      ns    = "aws:ec2:vpc"
      name  = "ELBScheme"
      value = "internet facing"
    },
    {
      ns    = "aws:elasticbeanstalk:environment"
      name  = "LoadBalancerType"
      value = "application"
    },
    {
      ns    = "aws:elasticbeanstalk:environment:process:default"
      name  = "MatcherHTTPCode"
      value = "200"
    },
    {
      ns    = "aws:elasticbeanstalk:healthreporting:system"
      name  = "SystemType"
      value = "enhanced"
    },
    {
      ns    = "aws:ec2:vpc"
      name  = "VPCId"
      value = local.vpc_id
    },
    {
      ns    = "aws:ec2:vpc"
      name  = "Subnets"
      value = join(",", sort(local.subnets))
    },
    {
      ns    = "aws:autoscaling:launchconfiguration"
      name  = "IamInstanceProfile"
      value = aws_iam_instance_profile.this.name
    },
    {
      ns    = "aws:autoscaling:launchconfiguration"
      name  = "EC2KeyName"
      value = "foo"
    },
    {
      ns    = "aws:elbv2:listener:443"
      name  = "ListenerEnabled"
      value = "true"
    },
    {
      ns    = "aws:elbv2:listener:443"
      name  = "Protocol"
      value = "HTTPS"
    },
    {
      ns    = "aws:elbv2:listener:443"
      name  = "SSLCertificateArns"
      value = local.acm
    }
  ]
}
data "aws_iam_policy_document" "trust" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }

    actions = ["sts:AssumeRole"]
  }
}

resource "aws_iam_role" "this" {
  name               = "${local.env}-app-server"
  path               = "/"
  assume_role_policy = data.aws_iam_policy_document.trust.json
}

resource "aws_iam_instance_profile" "this" {
  name = "${local.env}-app-server"
  role = aws_iam_role.this.name
}

Steps to Reproduce

terraform apply

Debug Output

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_elastic_beanstalk_environment.this["sandbox-app"]: Creating...
╷
│ Error: creating Elastic Beanstalk Environment (sandbox-sandbox-app): InvalidParameterValue: Access Denied: S3Bucket=elasticbeanstalk-env-resources-us-east-1, S3Key=eb_patching_resources/instance_patch_extension.linux (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: 4A3JEAF62JHR64ZZ; Proxy: null)
│   status code: 400, request id: f8d2066e-5635-4e9b-9f0c-01bfe41a07aa
│ 
│   with aws_elastic_beanstalk_environment.this["sandbox-app"],
│   on b.tf line 7, in resource "aws_elastic_beanstalk_environment" "this":
│    7: resource "aws_elastic_beanstalk_environment" "this" {

Panic Output

No response

Important Factoids

No response

References

No response

Would you like to implement a fix?

None

github-actions[bot] commented 1 year ago

Community Note

Voting for Prioritization

Volunteering to Work on This Issue

justinretzolk commented 1 year ago

Hey @kzw 👋 Thank you for taking the time to raise this! So that we have the necessary information in order to look into this, can you supply a sample Terraform configuration that can be used to reproduce this, and debug logs (redacted as needed)?

kzw commented 1 year ago

@justinretzolk I updated the original description. Please let me know if you need anything else

kzw commented 1 year ago

Similar problem with this public bucket elasticbeanstalk-platform-assets-<region>; it is retrieving the necessary object via s3:get instead of http get