How to set up HTTPS on Amazon EC2 with Elastic Load Balancer - amazon-web-services

I have requested a certificate in Amazon Certificate Manager. Now it has status 'issued'.
In EC2 console I have created Load Balancer. There are 2 listeners: HTTP and HTTPS. I tried Application Load Balancer and Classic Load Balancer, but I can't connect to my site via HTTPS.
My nginx config:
server {
listen 80;
#listen 443 ssl;
rewrite ^(.*) https://$host$1 permanent;
server_name site.com www.site.com;
root /home/ubuntu/www/site.com/wordpress;
index index.php;
client_max_body_size 20m;
gzip on;
gzip_disable "msie6";
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
location ~* ^/(\.htaccess|xmlrpc\.php)$ {
return 404;
}
location ~ /\. {
deny all;
}
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
set $is_https 'off';
if ($http_x_forwarded_proto ~ 'https') {
set $is_https 'on';
}
proxy_set_header HTTPS $is_https;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://app_server;
break;
}
#try_files $uri $uri/ /index.php?$args; # permalinks
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}
How can I import the certificate manually? Or there is a way to set up HTTPS connection with the Amazon certificate?

If you have an ACM cert, you can just select that certificate from the ELB Listener for HTTPS/443 and you don't need to bother setting up the SSL config in your nginx instance. Just have it respond on port 80.
You just need both HTTP/80 and HTTPS/443 in the ELB to HTTP port 80 on the instance (This sample is using the Classic ELB)
If the Cert is in ACM you should see it in the dropdown once when you select "Change" under SSL Certificate.
Now you just need to make sure your ELB security group is set up to allow Ingress from 80/443 and Egress from 80. And you need to make sure your instance allows Ingress from the ELB Security Group.

Depending on your ELB setup and port mapping, the $https variable won't always work when your instance is behind an AWS ELB (h/t #Michael - sqlbot). You should use HTTP_X_FORWARDED_PROTO header instead and move your rewrite rule inside the IF statement that checks for the HTTP_X_FORWARDED_PROTO header:
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if ($http_x_forwarded_proto != "https") {
rewrite ^(.*)$ https://$server_name$1 permanent;
}
.
.
.
}
Note on Security Groups
Also, you need to ensure that your load balancer can communicate with registered targets on both the listener port and the health check port. For more info:
Security Groups for Your Application Load Balancer
Security Groups for Your Classic Load Balancer

Related

AWS Application Load Balancer - https not working properly

I have a web application developed with React JS, for server side rendering, I am using NodeJS. Following is the overall architecture -
Deployed React JS app on EC2 - Ubuntu 18.04 with Nginx
Obtained SSL from AWS ACM
Attached ALB to EC2 instance, added 2 listeners - PORT 80, PORT 443 (Forwarding request to target group on PORT 80)
Added A record on Godaddy with EC2 elastic IP, added CNAME record www pointing to ALB
Following is my nginx config file -
server {
server_name mydomain.ai;
return 301 https://www.mydomain.ai$request_uri;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
#server_name www.mydomain.ai;
if ($host !~ ^www\.) {
rewrite ^ https://$host$request_uri permanent;
}
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location /error {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8000;
}
location /aws/ {
try_files $uri $uri/ /aws/aws.html;
}
}
server {
listen *:443 default_server;
server_name mydomain.ai www.mydomain.ai;
if ($host !~ ^www\.) {
rewrite ^ https://$host$request_uri permanent;
}
location / {
proxy_hide_header 'Access-Control-Allow-Origin';
add_header 'Access-Control-Allow-Origin' "*" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
proxy_pass https://localhost:8000;
proxy_http_version 1.1;
}
}
When I type https://mydomain.ai it throws "ERR_SSL_PROTOCOL_ERROR", however following cases are working fine -
mydomain.ai //redirected to https://www.mydomain.ai
http://mydomain.ai //redirected to https://www.mydomain.ai
http://www.mydomain.ai //redirected to https://www.mydomain.ai
Can anyone please help me?
I think you forgot to attach the procured certificate to ALB.
It can be done from AWS console by following the steps mentioned:
https://aws.amazon.com/premiumsupport/knowledge-center/associate-acm-certificate-alb-nlb/

Can't acces to AWS Kibana VPC-Based with nginx using Cognito

I use Elasticsearch VPC-based, for connect to kibana I use nginx reverse proxy.
I'm followed this : https://aws.amazon.com/premiumsupport/knowledge-center/kibana-outside-vpc-nginx-elasticsearch/?nc1=h_ls.
When I try to access to https://ec2-x-x-x-x.region-x.compute.amazonaws.com (EC2 instance containts nginx ).
I have a redirect to https://ec2-x-x-x-x.region-x.compute.amazonaws.com/login?response_type=code&client_id=xxxx... instead https://auth.website.com/login?response_type=code&client_id=xxxx... (auth.website.com is Cognito host)
Then I have an 502 bad gateway.
My nginx config :
server {
listen 443;
server_name $host;
rewrite ^/$ https://$host/_plugin/kibana redirect;
ssl_certificate /etc/nginx/cert.crt;
ssl_certificate_key /etc/nginx/cert.key;
ssl on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
location /_plugin/kibana {
# Forward requests to Kibana
proxy_pass https://vpc-domain-xxxxx.region.es.amazonaws.com/_plugin/kibana;
# Handle redirects to Amazon Cognito
proxy_redirect https://auth.exmample.com https://$host;
# Update cookie domain and path
proxy_cookie_domain vpc-domain-xxxxx.region.es.amazonaws.com $host;
proxy_cookie_path / /_plugin/kibana/;
# Response buffer settings
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
location ~ \/(log|sign|error|fav|forgot|change|saml|oauth2) {
# Forward requests to Cognito
proxy_pass https://auth.exmample.com;
# Handle redirects to Kibana
proxy_redirect https://vpc-domain-xxxxx.region.es.amazonaws.com https://$host;
# Update cookie domain
proxy_cookie_domain auth.exmample.com $host;
}
}
Thank you
Relaunch the page with browser Developer Tools enabled and "Network" tab is selected. You might able to start the investigation on the cause from here.
access to your EC2 instance, then check the nginx log which located at /var/log/nginx/ directory (for linux based distribution).
Check the security group of your EC2 instance.

Elasticbeanstalk - Force HTTPs on Docker container with Nginx

I have a single-container Docker running a React environment on Elasticbeanstalk with Nginx. I pointed a subdomain to the ELB URL, and want to force a HTTPS redirection if you visit the subdomain (i.e. you type subdomain.domain.com and it should redirect you to HTTPS).
Now, if I visit the default ELB URL (something.eu-central-1.elasticbeanstalk.com), it will be redirected to HTTPS. But I want my custom domain (which is parked somewhere else but points to something.eu-centralblabla with a CNAME) to be forced to use HTTPS as well, but it doesn't happen. It allows regular HTTP requests.
I've tried several guides and followed AWS documentation, but I cannot seem to force it to redirect to HTTPS on my custom subdomain.
These are my files:
/.ebextensions folder
http-instance.config
files:
/etc/nginx/conf.d/https.conf:
mode: "000644"
owner: root
group: root
content: |
# HTTPS Server
server {
listen 443;
server_name localhost;
ssl on;
ssl_certificate /etc/pki/tls/certs/server.crt;
ssl_certificate_key /etc/pki/tls/certs/server.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://docker;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
#SSL CRT and KEY below
https-instance-single.config
Resources:
sslSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
IpProtocol: tcp
ToPort: 443
FromPort: 443
CidrIp: 0.0.0.0/0
/nginx folder
default.conf
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html?/$request_uri;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
error_page 500 504 /500.html;
error_page 502 /502.html;
error_page 503 /503.html;
client_max_body_size 4G;
keepalive_timeout 10;
location ~ ^/(favicon|static)/ {
gzip_static on;
expires max;
add_header Cache-Control public;
# add_header Last-Modified "";
# add_header ETag "";
open_file_cache max=1000 inactive=500s;
open_file_cache_valid 600s;
open_file_cache_errors on;
break;
}
}
What am I doing wrong? Thanks for your help!
You should be able to manage this in your nginx config by adding this within the server context:
set $redirect_to_https 0;
if ($http_x_forwarded_proto != 'https') {
set $redirect_to_https 1;
}
if ($redirect_to_https = 1) {
rewrite ^ https://$host$request_uri? permanent;
}
Or something to that effect.
Route all http traffic to https:
server {
listen 80;
return 301 https://$host$request_uri;
}
Then hangle the proxy stuff in the 443 block

Api Gateway connection with Elastic Beanstalk (client-side SSL Certificate)

I'm trying to connect Api Gateway with my api in Elastic Beanstalk. I want my api only accesible by Api Gateway and for this I use client-side SSL certificate authorization in backend (like this aws publication Link:http://docs.aws.amazon.com/es_es/apigateway/latest/developerguide/getting-started-client-side-ssl-authentication.html). So my arquitecture is like this:
API GATEWAY->ELASTIC LOAD BALANCER->EC2 (ELASTIC BEANSTALK)
My EC2 machine have NGINX and Ruby.
The connections work like this:
API GATEWAY -> (80 PORT) -> ELASTIC LOAD BALANCER -> (443 PORT) -> NGINX -> RUBY
I am doing the client auth in NGINX.
When I access the Elastic Load Balancer using a browser, it shows 400 Bad Request - NGINX error: No required SSL certificate was sent (this is correct because I'm not sending the certificate). But when I access using Api Gateway and sending the client certificate I get the same error (I don't understand why).
When I configure the SSL connection in NGINX, I'm using SSL certificates signed by me (maybe this is the problem?)
Other posible cause for my problem is the port configuration in Elastic Load Balancer (in the picture). I have Backend Authentication: Disabled. Is this a problem?
Pictura Port Config ELB
My nginx configuration is:
upstream my_app {
server unix:///var/run/puma/my_app.sock;
}
log_format healthd '$msec"$uri"'
'$status"$request_time"$upstream_response_time"'
'$http_x_forwarded_for';
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name localhost;
root /usr/share/nginx/html;
ssl on;
ssl_certificate /etc/nginx/ssl/dev.crt;
ssl_certificate_key /etc/nginx/ssl/dev.key;
ssl_trusted_certificate /etc/nginx/ssl/api-gateway.pem;
ssl_client_certificate /etc/nginx/ssl/api-gateway.pem;
ssl_verify_client on;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
ssl_prefer_server_ciphers on;
if ($ssl_client_verify = FAILED) {
return 495;
}
if ($ssl_client_verify = NONE) {
return 402;
}
if ($ssl_client_verify != SUCCESS) {
return 403;
}
try_files $uri/index.html $uri #my_app;
location #my_app {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header Client-IP $remote_addr;
proxy_pass http://my_app;
proxy_set_header X-Client-Verify $ssl_client_verify;
}
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://my_app; # match the name of upstream directive which is defined above
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header gonzalo1 $ssl_client_verify;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
Amazon API Gateway does not support self-signed certificates for integration endpoints. Have you tried using a certificate from Amazon Certificate Manager or Let's Encrypt?

https to http redirect not working in nginx configuration using rewrite

To distribute load and implement security in our application we have taken elastic Load Balancer from amazon and SSL is configured on it.Now the redirection from http to https is not working in nginx configuration on server or instances which is attached on ELB.
Here is following nginx configuration:-
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name new.example.com;
access_log /var/log/nginx/domain-access.log;
location / {
proxy_read_timeout 90;
proxy_connect_timeout 90;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:8000;
}
}
Firstly the server is not supporting https URLs then I add some proxy settings in configuration but now issue is that redirection is not working i have used the following commands in ngnix configuration to redirect http to https :-
#version 1
server{
return 301 https://$server_name$request_uri;
}
#version 2
server {
rewrite ^(.*) https://$host$1 permanent;
}
Application deployed on server is build using django framework.
When I've done something similar, then I've set up the ELB HTTPS to redirect to HTTP port 80 on the node. I've then set up a second nginx vhost on the node, e.g. on port 81, which directs to return 301 https://$server_name$request_uri; and set up the ELB http listener to redirect to that port (where $server_name obviously points to the domain CNAME of the ELB)
I then make sure that the instances behind the ELB cannot be accessed from outside my VPC using security groups.
If you are using Django, you can use it to do the redirection, this give a lot of flexibilty like enabling HTTPS redirects only on production server or choose which urls to redirect from:
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
# Redirect to HTTPS in production
SECURE_SSL_REDIRECT = not DEBUG
# Disable redirection on this urls
SECURE_REDIRECT_EXEMPT = [
'^legacy/api/',
]