ฉันมีปัญหาในการบังคับใช้ HTTPS กับไซต์ที่ฉันปรับใช้ผ่าน AWS Elastic Beanstalk

เป็นแอปพลิเคชันส่วนหน้าที่ใช้ EmberJS ฉันวนเวียนอยู่ในแวดวงมาหลายวันแล้วและพยายามหาวิธีเปลี่ยนเส้นทางการรับส่งข้อมูล http เป็น https ฉันใช้ Amazon Linux AMI บนเครื่อง EC2 ของฉัน

ฉันได้ข้อสรุปแล้ว (ยังไม่แน่ใจว่าถูกต้องหรือไม่) ว่าไม่อยู่ใน Elastic Beanstalk ที่ฉันบังคับ HTTPS ฉันอนุญาตทั้ง HTTP และ HTTPS ผ่าน Elastic Beanstalk Load Balancer และกำลังพยายามเปลี่ยนเส้นทางบนเซิร์ฟเวอร์

นี่คือที่ที่ฉันประสบปัญหา ฉันพบคำตอบมากมายเกี่ยวกับกฎการเขียนใหม่โดยmod_rewriteที่ไม่อิงตามX-Forwarded-ProtoHeader แต่ไฟล์นั้นไม่มีอยู่ในเครื่อง EC2 ของฉันตามการค้นหา

ฉันได้ลองสร้างไฟล์ปรับแต่งภายใน.ebextensionsไดเร็กทอรีแล้ว แต่ก็ไม่ได้ผลเช่นกัน

สิ่งสำคัญที่ฉันพยายามทำคือให้ผู้ใช้นำทางไปยัง https เมื่อพยายามกดที่อยู่ http คำแนะนำหรือข้อเสนอแนะใด ๆ ที่ชื่นชมมาก ขอบคุณ!

แก้ไข: ฉันใช้ 64 บิต Debian jessie v1.4.1 ที่ใช้ Python 3.4 (กำหนดค่าล่วงหน้า - นักเทียบท่า)

answer

ฉันคิดว่าคุณต้องระบุสภาพแวดล้อม Elastic Beanstalk ที่คุณใช้ (ดู: Supported Platforms ) เนื่องจากสภาพแวดล้อมที่แตกต่างกันมีการกำหนดค่าต่างกัน

โดยทั่วไป คุณต้องปรับแต่ง:

  • ตัวโหลดบาลานซ์แบบยืดหยุ่น :
    • ฟังบนพอร์ต 80 และพร็อกซีไปยังพอร์ตอินสแตนซ์ EC2 80
    • ฟังบนพอร์ต 443 และพร็อกซีไปยังพอร์ตอินสแตนซ์ EC2 443
  • EC2 เว็บเซิร์ฟเวอร์/พร็อกซี :
    • ฟังบนพอร์ต 80 และตอบสนองด้วยการเปลี่ยนเส้นทางไปยัง HTTPS
    • ฟังที่พอร์ต 443 และให้บริการตามคำขอ

ในการปรับแต่ง คุณสามารถใช้ CLI หรือ.ebextensions.

คุณสามารถตรวจสอบการเปิดใช้งาน HTTPS และใช้ HTTP เปลี่ยนเส้นทางบน AWS ยืดหยุ่นฝักถั่ว จะบอกวิธีกำหนดค่า Elastic Beanstalk Single Docker Container ให้บริการ HTTPS และ HTTP (เปลี่ยนเส้นทางเป็น HTTPS) คุณสามารถปรับการกำหนดค่าตามที่คุณต้องการ

นอกจากนี้ยังสามารถทำได้ค่อนข้างง่าย โดยไม่ต้องสัมผัสตัวโหลดบาลานซ์ โดยใช้X-Forwarded-Protoส่วนหัวที่กำหนดโดย ELB นี่คือสิ่งที่ฉันทำ:

files:
  "/etc/nginx/sites-available/elasticbeanstalk-nginx-docker-proxy.conf":
    mode: "00644"
    owner: root
    group: root
    content: |
      map $http_upgrade $connection_upgrade {
        default        "upgrade";
        ""            "";
      }

      server {
        listen 80;

        gzip on;
        gzip_comp_level 4;
        gzip_types text/html text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

        access_log    /var/log/nginx/access.log;

        location / {
          proxy_pass            http://docker;
          proxy_http_version    1.1;

          proxy_set_header      Connection      $connection_upgrade;
          proxy_set_header      Upgrade         $http_upgrade;
          proxy_set_header      Host            $host;
          proxy_set_header      X-Real-IP       $remote_addr;
          proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        if ($http_x_forwarded_proto = 'http') {
          return 301 https://$host$request_uri;
        }
      }

Elastic Beanstalk ไม่รองรับพอร์ตหลายพอร์ตจาก Single Docker Container ดังนั้นคุณต้องจัดการสิ่งนี้ที่ระดับพร็อกซีตามที่แนะนำ อย่างไรก็ตาม อินสแตนซ์ EC2 ของคุณไม่จำเป็นต้องทราบเกี่ยวกับใบรับรองของคุณ เนื่องจากคุณสามารถยุติการเชื่อมต่อ SSL ที่โหลดบาลานเซอร์ได้

ใน.ebextensionsไดเร็กทอรีของคุณให้สร้างการกำหนดค่าสำหรับพร็อกซี nginx ที่มีการกำหนดค่าเซิร์ฟเวอร์สองรายการ หนึ่งพร็อกซี่http://docker(การกำหนดค่าเริ่มต้น พอร์ต 80) และอีกอันที่เปลี่ยนเส้นทางไปยัง https (ฉันเลือกพอร์ต 8080)

.ebextensions/01-nginx-proxy.config:

files:
  "/etc/nginx/sites-available/000-default.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      map $http_upgrade $connection_upgrade {
          default        "upgrade";
          ""            "";
      }

      server {
          listen 80;

          gzip on;
          gzip_comp_level 4;
          gzip_types text/html text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

          access_log    /var/log/nginx/access.log;

          location / {
              proxy_pass            http://docker;
              proxy_http_version    1.1;

              proxy_set_header    Connection            $connection_upgrade;
              proxy_set_header    Upgrade                $http_upgrade;
              proxy_set_header    Host                $host;
              proxy_set_header    X-Real-IP            $remote_addr;
              proxy_set_header    X-Forwarded-For        $proxy_add_x_forwarded_for;
          }
      }

      server {
          listen 8080;

          location / {
              return 301 https://$host$request_uri;
          }
      }

commands:
   00_enable_site:
    command: 'rm -f /etc/nginx/sites-enabled/* && ln -s /etc/nginx/sites-available/000-default.conf /etc/nginx/sites-enabled/000-default.conf'

สร้างการกำหนดค่าที่สองสำหรับตัวจัดสรรภาระงาน EB และกลุ่มความปลอดภัยที่ตั้งค่าดังนี้:

  • อินสแตนซ์ EC2 :
    • อนุญาตการรับส่งข้อมูลบนพอร์ต 80/8080 จากตัวโหลดบาลานซ์
    • อนุญาตการรับส่งข้อมูลบนพอร์ต 22 จากทุกที่ (สำหรับการเข้าถึง ssh ไม่จำเป็น)
  • โหลดบาลานเซอร์ :
    • ส่งต่อพอร์ต 443 HTTPS ไปยังพอร์ต 80 HTTP
    • ส่งต่อพอร์ต 80 HTTP ไปยังพอร์ต 8080 HTTP

.ebextensions/02-load-balancer.config:

"Resources" : {
  "AWSEBSecurityGroup": {
    "Type" : "AWS::EC2::SecurityGroup",
    "Properties" : {
      "GroupDescription" : "Instance security group (22/80/8080 in)",
      "SecurityGroupIngress" : [ {
          "IpProtocol" : "tcp",
          "FromPort" : "80",
          "ToPort" : "80",
          "SourceSecurityGroupId" : { "Ref" : "AWSEBLoadBalancerSecurityGroup" }
        }, {
          "IpProtocol" : "tcp",
          "FromPort" : "8080",
          "ToPort" : "8080",
          "SourceSecurityGroupId" : { "Ref" : "AWSEBLoadBalancerSecurityGroup" }
        }, {
          "IpProtocol" : "tcp",
          "FromPort" : "22",
          "ToPort" : "22",
          "CidrIp" : "0.0.0.0/0"
        } ]
    }
  },
  "AWSEBLoadBalancerSecurityGroup": {
    "Type" : "AWS::EC2::SecurityGroup",
    "Properties" : {
      "GroupDescription" : "Load balancer security group (80/443 in, 80/8080 out)",
      "VpcId" : "<vpc_id>",
      "SecurityGroupIngress" : [ {
          "IpProtocol" : "tcp",
          "FromPort" : "80",
          "ToPort" : "80",
          "CidrIp" : "0.0.0.0/0"
        }, {
          "IpProtocol" : "tcp",
          "FromPort" : "443",
          "ToPort" : "443",
          "CidrIp" : "0.0.0.0/0"
        } ],
      "SecurityGroupEgress": [ {
          "IpProtocol" : "tcp",
          "FromPort" : "80",
          "ToPort" : "80",
          "CidrIp" : "0.0.0.0/0"
        }, {
          "IpProtocol" : "tcp",
          "FromPort" : "8080",
          "ToPort" : "8080",
          "CidrIp" : "0.0.0.0/0"
        } ]
    }
  },
  "AWSEBLoadBalancer" : {
    "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
    "Properties" : {
      "Listeners" : [ {
          "LoadBalancerPort" : "80",
          "InstancePort" : "8080",
          "Protocol" : "HTTP"
        }, {
          "LoadBalancerPort" : "443",
          "InstancePort" : "80",
          "Protocol" : "HTTPS",
          "SSLCertificateId" : "arn:aws:iam::<certificate_id>:<certificate_path>"
        } ]
    }
  }
}

(หมายเหตุ: อย่าลืมแทนที่ SSLCertificateId และ VpcId ด้วยค่าของคุณ)

การรับส่งข้อมูลบนพอร์ต 80 ของตัวโหลดบาลานซ์ (HTTP) จะไปถึงพอร์ต 8080 บนอินสแตนซ์ EC2 ซึ่งจะเปลี่ยนเส้นทางไปยัง HTTPS การรับส่งข้อมูลบนพอร์ต 443 บนโหลดบาลานเซอร์ (HTTPS) จะถูกให้บริการโดยพอร์ต 80 บนอินสแตนซ์ EC2 ซึ่งเป็นพร็อกซีนักเทียบท่า

ฉันใช้ Terraform เพื่อเปิดใช้งาน HTTP เป็น HTTPS เปลี่ยนเส้นทางบน ElasticBeanstalk

ฉันเพิ่งเพิ่มกฎ Listener เพิ่มเติม

data "aws_alb_listener" "http" { //Get ARN of Listener on Port-80
  load_balancer_arn = aws_elastic_beanstalk_environment.myapp.load_balancers[0]
  port              = 80
}


resource "aws_alb_listener_rule" "redirect_http_to_https" {
  listener_arn = data.aws_alb_listener.http.arn
  action {
    type = "redirect"
    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
  condition {
    host_header {
      values = ["*.*"]
    }
  }
}