Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redirect http to https #98

Closed
atifsyedali opened this issue Nov 15, 2019 · 17 comments · Fixed by #218
Closed

Redirect http to https #98

atifsyedali opened this issue Nov 15, 2019 · 17 comments · Fixed by #218

Comments

@atifsyedali
Copy link

If I set http_listener_enabled="true" and loadbalancer_certificate_arn=someArn and loadbalancer_ssl_policy=whatever, then I can get the load balancer to add a HTTPS listener and a HTTP listener.

But how can I make the HTTP listener create a forwarding rule to HTTPS?

@atifsyedali
Copy link
Author

Looks like it can't be done currently with the EB provided load balancer settings, because defining the listener rule requires that you point to the "process", which is the target group. But that will point back to our app (see https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-elbv2-listenerrule).

Currently, I just do this...

app.use((req, res, next) => {
  if (req.headers["x-forwarded-proto"] === "https") return next();
  return res.redirect(301, `https://${path.join(req.hostname, req.url)}`);
});

@Gowiem
Copy link
Member

Gowiem commented Nov 18, 2019

@atifsyedali I'm looking to do the same... I'd be happy to do the update, but I'm unsure how we can configure this easily.

I've found this, which I think is the path forward, but providing that to the Beanstalk configuration settings through Terraform is throwing me off.

@aknysh Do you have a suggestion on that front?

@svenlito
Copy link

svenlito commented Mar 18, 2020

Pardon my ignorance, I haven't actually tried this.

I would think that you can achieve this using the data resource, grab the LB arn and attach a listener on port 80 that adds a redirect rule, or just adds a rule to the existing listener.

https://www.terraform.io/docs/providers/aws/r/lb_listener.html#redirect-action

@richardARPANET
Copy link

@svenlito That doesn't work for me

resource "aws_lb_listener" "http" {
  load_balancer_arn = "${element(aws_elastic_beanstalk_environment.default.load_balancers, 0)}"
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

gives

Error: Error creating LB Listener: ValidationError: 'awseb-e-p-AWSEBLoa-1E9JXK93ULR1I' must be in ARN format
    status code: 400, request id: d38933a0-c1e3-43fc-ac22-10659beb86b6

@svenlito
Copy link

svenlito commented Apr 5, 2020

I meant to say data https://www.terraform.io/docs/providers/aws/d/lb.html it exposes a name and arn

@richardARPANET
Copy link

@svenlito Is that manually specified arn? (seems strange to do in terraform, although I'm inexperienced). Would you be willing to provide an example?

@svenlito
Copy link

svenlito commented Apr 5, 2020

I believe something like this could work.

data "aws_lb" "selected" {
  name = aws_elastic_beanstalk_environment.default.load_balancers[0].name
}

resource "aws_lb_listener" "http" {
  load_balancer_arn = data.aws_lb.selected.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

@richardARPANET
Copy link

richardARPANET commented Apr 5, 2020

@svenlito Sadly not :/

Error: Unsupported attribute

  on ../modules/elasticbeanstalk/environment/main.tf line 599, in data "aws_lb" "selected":
 599:   name = aws_elasstic_beanstalk_environment.default.load_balancers[0].name

Looks like aws_elasstic_beanstalk_environment.default.load_balancers is a list of strings (e.g. 'awseb-e-y-AWSEBLoa-13OYOII07HIP0').

I'm using Terraform v0.12.24, tried with v0.12.20 also, same result.


edit:

If i even hardcode the name of the load balancer (taken from AWS Web UI) it doesn't even work, very frustrating:

data "aws_lb" "selected" {
  name = "awseb-e-y-AWSEBLoa-13OYOII07HIP0"
}

resource "aws_lb_listener" "http" {
  load_balancer_arn = data.aws_lb.selected.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}
Error: Error retrieving LB: LoadBalancerNotFound: Load balancers '[awseb-e-y-AWSEBLoa-13OYOII07HIP0]' not found
        status code: 400, request id: 6c2c1070-181c-4da9-b0b6-5098de25ca99

  on ../modules/elasticbeanstalk/environment/main.tf line 598, in data "aws_lb" "selected":
 598: data "aws_lb" "selected" {

edit2:

I've decided to handle this inside the application instead.

@boomshadow
Copy link

You can do this by turning off the HTTP listener in the beanstalk settings, and then making a new aws_lb_listener resource that manages the HTTP listener outside of the beanstalk module. This works successfully for me.

Be sure to turn off the HTTP listener in the module:

http_listener_enabled        = false

Then make a new resource like so:

resource "aws_lb_listener" "https_redirect" {
  load_balancer_arn = module.elastic_beanstalk_environment_my_app.load_balancers[0]
  port              = 80
  protocol          = "HTTP"

  default_action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

@theFong
Copy link

theFong commented May 24, 2020

I was not able to get @boomshadow's solution to work out of the box since the elastic load balancer's security group did not expose port 80 due to http_listener_enabled = false however I may be missing something.

My work around was to add a security group rule to the alb's security group in addition to the lb_listener.

resource "aws_lb_listener" "https_redirect" {
  load_balancer_arn = module.elastic_beanstalk_environment_my_app.load_balancers[0]
  port              = 80
  protocol          = "HTTP"

  default_action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

data "aws_lb" "eb_lb" {
  arn = module.elastic_beanstalk_environment.load_balancers[0]
}

resource "aws_security_group_rule" "allow_80" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = tolist(data.aws_lb.eb_lb.security_groups)[0]
}

@yashshanker
Copy link

You don't need to disable deafult_listener for the elastic beanstalk environment, neither do you need to create a new listener.
All you need to do is to create a new rule for the HTTP:80 listener as your redirection rule with /* path_pattern condition.

data "aws_lb_listener" "http_listener" {
  load_balancer_arn = aws_elastic_beanstalk_environment.my_eb_environment.load_balancers[0]
  port              = 80
}

resource "aws_lb_listener_rule" "redirect_http_to_https" {
  listener_arn = data.aws_lb_listener.http_listener.arn
  priority = 1
  action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }

  condition {
    path_pattern {
      values = ["/*"]
    }
  }
}

This did the job for me.

@richardARPANET
Copy link

@yashshanker When I use that I get the following:

module.server.data.aws_lb_listener.http_listener: Refreshing state...

Error: ValidationError: 'awseb-e-3-AWSEBLoa-1FX7TBJYYFKFY' is not a valid load balancer ARN
        status code: 400, request id: 877716a0-cf39-4422-b803-985325cdd88b

Exact terraform:

data "aws_lb_listener" "http_listener" {
  load_balancer_arn = aws_elastic_beanstalk_environment.default.load_balancers[0]
  port              = 80
}

resource "aws_lb_listener_rule" "redirect_http_to_https" {
  listener_arn = data.aws_lb_listener.http_listener.arn
  priority = 1
  action {
    type = "redirect"

    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }

  condition {
    path_pattern {
      values = ["/*"]
    }
  }
}

(My environment name is default)

@shanidoc
Copy link

this doesn't make sense, when I output data.aws_lb_listener.http_listener.arn, I am getting the load balancer arn and not the listener arn

@mndomingues
Copy link

I have the same result as richardARPANET

@n10000k
Copy link

n10000k commented Mar 22, 2021

@richardARPANET @shanidoc @mndomingues You need to use the v2 application load balancer example (official aws provider) setup:

resource "aws_elastic_beanstalk_environment" "main" {
  name = var.environment
  application = aws_elastic_beanstalk_application.main.name
  solution_stack_name = data.aws_elastic_beanstalk_solution_stack.multi_container_docker.name

  setting {
    namespace = "aws:ec2:vpc"
    name = "VPCId"
    value = var.vpc_id
    resource = ""
  }

  setting {
    namespace = "aws:ec2:vpc"
    name = "Subnets"
    value = join(", ", [var.private_a_subnet_id, var.private_b_subnet_id])
    resource = ""
  }

  setting {
    namespace = "aws:ec2:vpc"
    name = "ELBSubnets"
    value = join(", ", [var.public_a_subnet_id, var.public_b_subnet_id])
    resource = ""
  }

  setting {
    namespace = "aws:autoscaling:launchconfiguration"
    name = "IamInstanceProfile"
    value = "${var.application_name}-service-elasticbeanstalk-instance-${var.environment}"
  }

  setting {
    namespace = "aws:autoscaling:launchconfiguration"
    name = "InstanceType"
    value = var.instance_type
  }

  setting {
    namespace = "aws:elasticbeanstalk:environment"
    name = "LoadBalancerType"
    value = "application"
  }

  setting {
    namespace = "aws:elasticbeanstalk:healthreporting:system"
    name = "SystemType"
    value = "enhanced"
  }

  setting {
    namespace = "aws:elbv2:listener:443"
    name = "ListenerEnabled"
    value = var.acm_eu_west_2.arn == "" ? "false" : "true"
  }

  setting {
    namespace = "aws:elbv2:listener:443"
    name = "Protocol"
    value = "HTTPS"
  }

  setting {
    namespace = "aws:elbv2:listener:443"
    name = "SSLCertificateArns"
    value = var.acm_eu_west_2.arn
  }
}

data "aws_lb_listener" "http_listener" {
  load_balancer_arn = aws_elastic_beanstalk_environment.main.load_balancers[0]
  port = 80
}

resource "aws_lb_listener_rule" "redirect_http_to_https" {
  listener_arn = data.aws_lb_listener.http_listener.arn
  priority = 1

  action {
    type = "redirect"

    redirect {
      port = "443"
      protocol = "HTTPS"
      status_code = "HTTP_301"
    }
  }

  condition {
    path_pattern {
      values = ["/*"]
    }
  }
}

@preetpuri
Copy link

preetpuri commented May 19, 2021

This is what worked for me

  • Add load balancer security Group to allow traffic on port 80
  • Add listener to elastic beanstalk load balancer to listen on port 80
resource "aws_elastic_beanstalk_environment" "eb_environment" {
  name                = local.beanstalk_environment_name
  application         = aws_elastic_beanstalk_application.eb_application.id
  
  ************************ All other settings Start ************************


  #================================================New  ALB Setting to add SG=======================================
  setting {
      namespace = "aws:elbv2:loadbalancer"
      name = "SecurityGroups"
      value = aws_security_group.manage_port80_sg.id
  }


  ************************ All other settings End **************************

  lifecycle {
    	create_before_destroy = true
  }

  tags = local.tags
}



resource "aws_security_group" "manage_port80_sg" {
  name        = "${local.beanstalk_environment_name}-http-sg"
  description = "Allow inbound traffic on port 80 for 443 redirect to work"
  vpc_id = var.vpc_id

  ingress {
   description      = "HTTP Redirect HTTPS"
   from_port        = 80
   to_port          = 80
   protocol         = "tcp"
   cidr_blocks      = ["0.0.0.0/0"]
 }
  tags = module.common_tags.tags
}

data "aws_lb_listener" "http_listener" {
  load_balancer_arn = element(tolist(aws_elastic_beanstalk_environment.eb_environment.load_balancers), 0)
  port = 80
  depends_on = [aws_elastic_beanstalk_environment.eb_environment]
}

resource "aws_lb_listener_rule" "redirect_http_to_https" {
  listener_arn = data.aws_lb_listener.http_listener.arn
  priority = 1
  action {
    type = "redirect"

    redirect {
      port = "443"
      protocol = "HTTPS"
      status_code = "HTTP_301"
    }
  }
  condition {
    path_pattern {
      values = ["/*"]
    }
  }
}

@paulderkanns
Copy link

hope I am right here.
Cant get my redirect to work using following config:
resource "aws_lb" "app" {
name = "${random_pet.app.id}-lb"
internal = false
load_balancer_type = "application"
subnets = module.vpc.public_subnets
security_groups = [module.lb_security_group.this_security_group_id]

#access_logs {

bucket = "wshimport"

enabled = true

#}

tags = {
Name = "EXTERNAL-ELB"
}
}

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

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.ec2.arn
}
}

resource "aws_lb_listener_rule" "redirect_http_to_https" {
listener_arn = aws_lb_listener.external_lb_http.arn
priority = 1
action {
type = "redirect"

redirect {
  port = "443"
  protocol = "HTTPS"
  status_code = "HTTP_301"
}

}
condition {
path_pattern {
values = ["/*"]
}
}
}

resource "aws_lb_listener" "external_lb_https" {
load_balancer_arn = aws_lb.app.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = aws_acm_certificate_validation.www.certificate_arn

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.ec2.arn
}
}

Any idea?

joe-niland pushed a commit that referenced this issue Feb 14, 2023
* Add flag to redirect HTTP to HTTPS

* Rename variables and add support for shared load balancers

* Modify existing examples

* Update variables description

* Fix redirect host default value

* Replace custom status code with a flag

* Fix format

* Fix bad reference to aws_elastic_beanstalk_environment

* Refactor datasources

* Change status_code variable type

* Fix load_balancer_arn reference

* Fix load_balancer_arn

* Add loadbalancer_redirect_http_to_https to complete example

* Add missing period at the end of the validation error message

* Update README.md and docs/terraform.md

* Bump required_version

* Update docs/terraform.md

* Update README file

* Change AWS provider constraint

* Change AWS version constraint inside the README.md file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet