Plumbing for API Gateway to Beanstalk with SSL - amazon-web-services

I am looking to host an API which I can control customer access to using API Keys, Usage Plans, and Cognito. This is my first time trying to bootstrap DNS+SSL and I can't figure out the basic plumbing to get SSL working when I connect API gateway to my beanstalk environment.
I've got example.com purchased on namecheap. I've got namecheap DNS set up to forward the api subdomain to AWS DNS via an NS record. I've got an API gateway with a custom domain name of api.example.com mapped to an API with a production stage. I've then got route 53 set up to point api.example.com to that API gateway stage. I can curl api.example.com and because I have a cognito user pool authenticator, I see Unauthorized as the response.
What I'm stuck on is how to connect this to my elastic beanstalk environment. My current attempt involves turning the API Gateway into a "HTTP Proxy", and tweaking the endpoint url. Except I'm not sure what to put there, or how to configure what I put there because the Test button in API GW often throws an error.
I'm currently trying to use the domain name of the load balancer in front of beanstalk: https://load-balancer-in-front-of-beanstalk-endpoint.com/{proxy}. I've tried a few configs on that load balancer, but I'm not sure what cert to give it because when I try api.example.com,
it fails with "Host name dualstack.awseb.foo.elb.amazonaws.com does not match the cert provided by peer(api.example.com)".
Some other questions mentioned setting an alias for api.example.com to point to the load balancer's ip... except for me it already points to the API GW, so I think I've gone wrong somewhere. Could use some pointers.

Related

API gateway calling my elastic beanstalk environment using HTTPS

I'm trying to figure out how I can call my elastic beanstalk environment with HTTPS. Ultimately I want to be able to use API gateway to forward HTTPS requests to it*.
In the elastic beanstalk console I went and configured the load balancer to use my website's SSL cert (mywebsite.com), on port 443 and with an instance port of 80 (whatever that means - I was following https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https-elb.html).
Before wiring up API gateway, I first tried calling my elastic beanstalk endpoint. Changing http:// to https://, using postman I got
Error: Hostname/IP does not match certificate's altnames: Host:
myService-prod.eba-p3t3saxf.ap-southeast-1.elasticbeanstalk.com. is
not in the cert's altnames: DNS:*.mywebsite.com
No dice. I then thought maybe if the request originated from my website's domain it might work. So I tried configuring API gateway, but I just get back a 500 Internal server error. (note if I change the endpoint URL inside API gateway from https to http all is good).
So what do I need to do? I tried reading this https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https.html, but got only as far as I described above. I feel like I do need a certificate, but when I tried using Amazon's certificate manager to generate a certificate for myService-prod.eba-p3t3saxf.ap-southeast-1.elasticbeanstalk.com, I can't validate it (fails both email and DNS certification). I think I don't fully understand what I need to do/see the big pictures. Can someone help me out, ideally with specific instructions.
*Actually, that is a question in itself. If my API gateway endpoint is HTTPS, is it safe for API gateway to then call my elastic beanstalk environment with just HTTP, as we're already inside AWS?
Thanks
I tried using Amazon's certificate manager to generate a certificate for myService-prod.eba-p3t3saxf.ap-southeast-1.elasticbeanstalk.com
You can't generated SSL certificate for this domain. This is AWS owned and manged domain. To get proper valid SSL certificate you have to have your own domain which you control.
From your post its not clear if you actually have a domain mywebsite.com or not. If not, and you want to keep yourself within AWS, you can use Route53 to buy a domain which you want. But any domain provider will be fine. Once you have your own custom domain, you can setup hosted zone in R53 for it, and point it to your EB's load balancer.
Having the domain setup, you can use AWS ACM to issue a valid, public free SSL certificate for your domain and deploy it on the load balancer.
In your API gateway you would use your EB domain for HTTP integrations, not AWS EB default domain.

AWS Elastic Beanstalk - SSL Certificate added but still HTTPS Error: SSL_ERROR_BAD_CERT_DOMAIN

I bought a domain named studileih.de, then I deployed my Angular frontend on firebase: https://studileih-ceb70.web.app/ and redirected from my domain studileih.de to the firebase URL.
Then I deployed my Spring Boot backend to AWS Elastic Beanstalk on: http://studileih1.eu-central-1.elasticbeanstalk.com/
-> Problem: Since the frontend on firebase used https and the backend on AWS used http I got a Mixed content error. The frontend wasn't able to load any of the backend data.
So I tried to solve this by creating a SSL certificate for my backend in the AWS Certificate Manager (ACM) and adding this to my Elasting Beanstalk Load Balancer. This worked and I could now at least make a connection from my frontend to my backend.
But now I get this error whenever a request to my backend gets sent:
When I click on "Accept the Risk and Continue" once, it works fine and all my backend data gets loaded. But I can't ask my users to do that.
(You can try this out by following: https://studileih1.eu-central-1.elasticbeanstalk.com/products and clicking "Advanced" -> "Accept the Risk and Continue" (if you dare ^^)
after you've done that, click on studileih.de and it will now load with the backend data.)
I know the problem exists because when creating the SSL certificate, I entered studileih.de as the domain that the certificate is for. I think I have to create a SSL certificate for studileih1.eu-central-1.elasticbeanstalk.com instead.
But when I try to create a SSL certificate for studileih1.eu-central-1.elasticbeanstalk.com:
I get this error from ACM:
How do I create a SSL Certificate for the Elastic Beanstalk URL?
p.s. I also tried to issue a certificate for my firebase URL https://studileih-ceb70.web.app/ but this one already uses Https by default. Also I couldnt find out how to DNS/Email validate the ACM request in the firebase console. But I think I need a certificate for the Elastic Beanstalk backend at studileih1.eu-central-1.elasticbeanstalk.com, not for the firebase frontend, right?
p.p.s. I don't really need to use https, so a solution would be to make firebase use http instead of https, but I couldn't find anything on how to do that.
UPDATE:
I added a subdomain called api.studileih.de (the immediate access is blocked by spring security, as you're not logged in to my site, but you can test it with api.studileih.de/products, because this API is accessibly without login). Then I redirected that subdomain to my AWS Load Balancer as suggested by Mark B by adding a CNAME to the subdomain:
(it's not possible to change to english there, sorry)
this is my Load Balancer:
I tried to put the DNS-Name as A-Record into my subdomain, but it was only possible to enter a IP4 adress there, so I entered it as CNAME instead. I also tried to find out the IP Adress of the Load Balancer, but Load Balancer don't have a static IP Adress.
This approach with the subdomain and the CNAME unfortunately didn't work, so I'm still looking for a solution...
(Here's the menu for setting a A-Record. You can only enter IP Adresses there:)
I know the problem exists because when creating the SSL certificate, I
entered studileih.de as the domain that the certificate is for. I
think I have to create a SSL certificate for
studileih1.eu-central-1.elasticbeanstalk.com instead.
You can only create an SSL certificate for a domain you own. You need to point a subdoomain of studileih.de, like api.studileih.de, at the Elastic Beanstalk load balancer, and then attach an SSL certificate to that load balancer that matches that subdomain.

Hosting React page on S3 and making REST api calls to server on Elastic Beanstalk

Background
I am trying to deploy a dummy application with React frontend and Django backend interacting via REST api. I have done the following:
Use a S3 bucket to host static website and deploy my react code to it
Put Cloudfront for S3 bucket - set up certificate and changed my domain name (from GoDaddy) to link to this address
Kicked off Elastic Beanstalk environment following the python environment tutorial of AWS
Set up Postgres RDS and linked the Django server with it
So now I can do the following
Access my frontend using https via my domain name (https://www.example.com)
Access django admin site using the path of elastic beanstalk and update items
i.e. each component is up and running
Problem
I am having trouble with:
Making a secure REST API call from the static page to Elastic Beanstalk environment. Before I set up certificates I could easily make REST API calls.
The guides I can find usually involve putting a domain name for Elastic Beanstalk, which I imagine does not apply to my case (or does it?)
I tried to follow this faq and updated configuration in load balancer that accepts 443 https and redirects to 80 http. But I am using same certificate as from CloudFront, which does not sound right to me.
Would appreciate help with
how to solve the above ssl connection issue
or is there a better architecture for what I'm trying to achieve here?
According to Request a certificate in ACM for Elastic Beanstalk backend, it sounds like I have to use a subdomain and request a certificate for that subdomain, and use Cloud 53 to direct requests to that subdomain to Elastic Beanstalk environment. Would that be the case?
Thank you in advance!
By default EB url will HTTP only. To use HTTPS you need to deploy SSL certificate on your ALB.
In order to do that you need a custom domain, because you can only associated an SSL certificates with domains that you control. Thus, normally you would get a domain (you seem to already have one from godaday). So in this case you can setup a subdomain (e.g. api.my-domian.com) on godady. Then you can use AWS ACM to register a free public SSL certificate for api.my-domian.com.
Once the certificate is verified, using either DNS (easier) or email technique, you deploy it on your ALB using HTTPs listener. Obviously you will need to point api.my-domian.com to the EB's https url. You can also redirect on your ALB http traffic from port 80 to 443 to always use https.
Then in your front-end application you only use https://api.my-domian.com, not the original EB url.
There can be also CORS issues alongside this, so have to be vary of them as well.

Route53 for AWS Elastic Search Domain gives certificate error

I have create a AWS elastic search domain in Virginia and got a Endpoint url.
Now I wanted to configure the Route53 behavior around it, so that a caller can use the same url, even though there is some change in elastic search or in case of a disaster recovery.
So,
Virginia Route 53 -- 1 Points to -- Virgina Elastic Search Domain URL
Oregon Route 53 -- 2 Points to -- Oregon Elastic Search Domain URL
Main Route 53 -- 3 Points to -- Route 53 1 or 2
I have already create these and also created and uploaded SSL certificate with correct SAN entries. But when I execute,
curl https://mainroute53/health
curl https://virginiaroute53/health
curl https://oregonroute53/health
I am getting this error,
curl: (51) Unable to communicate securely with peer: requested domain name does not match the server's certificate.
But when I am calling the Elastic Search URL directly its working. So I understand this is a issue with the way I am using the certificate. Any help appreciated.
Your Elastic Search endpoint will always return the Elastic Search SSL certificate.
So when you create a Route 53 "alias" for it, you may be connecting to it via your custom DNS entry, but Elastic Search will still use the Elastic Search SSL certificate.
Since the DNS endpoint you're using does not match the SSL certificate, you get that error.
You could use the --insecure curl flag to have it not check the SSL certificate, however, there are risks of doing that.
You can probably work around this by setting up a proxy server in front of the Elasticsearch domain, although it's kind of silly since there appears to also be an ELB inside the Elasticsearch domain. Ah well.
The domain Amazon ES creates for you includes the nodes in the Elasticsearch cluster and resources from several AWS services. When Amazon ES creates your domain, it launches instances into a service-controlled VPC. Those instances are fronted by Elastic Load Balancing (ELB), and the endpoint for the load balancer is published through Route 53. Requests to the domain pass through the ELB load balancer, which routes them to the domain’s EC2 instances.
https://aws.amazon.com/blogs/database/set-access-control-for-amazon-elasticsearch-service/
One way you can access Elasticsearch using your custom domain name is to use an API Gateway as an HTPP proxy. But then you have to deal with the authentication part since the Cognito cookies for ES will be pointing to the original domain (*.es.amazonaws.com).
In my experience this is doable and you should be able to use API Gateway (plus Custom Domain Names and Route 53) to achieve what you want (having a custom domain name over ES). It's just that it requires some Cognito knowledge and most likely, some coding (to handle the cookie problem).
You can use the http endpoint instead of the https one
i.e
curl **http**://mainroute53/health
This works around the fact that AWS does not allow providing custom domain certificate in its managed Elastic service
We had the same issue, wanted to be redirected to Kibana with a more friendlier DNS name and we used the solution with S3 bucket and the redirection as described here.
The steps:
Create a S3 bucket with any name.
In the bucket properties, enable “Static Website hosting”.
In the Static WebSite hosting properties, select the option to “Redirect Requests”.
In the target domain set the Kibana URL that is given from your elasticsearch domain: i.e. https://vpc-es-randomstring.us-east-1.es.amazonaws.com/_plugin/kibana/
Set Protocol to https
Then follow the steps from Step 5 on the guide above

How to enable HTTPS on AWS Elastic Load Balancer?

I am attempting to add HTTPS to my AWS Elastic Load Balancer.
I obtained a certificate through AWS Certificate Manager:
I have enabled HTTPS on the load balancer:
I made sure the security group for the load balancer accepts 0.0.0.0/0 on 443:
When going to my domain on HTTP, it works.
However, when trying to load my domain with HTTPS, it does not work ("ERR_CONNECTION_TIMED_OUT")
EDIT and UPDATE:
It is the API that I am attempting to get HTTPS working for, not necessarily the domain. The domain serve's a static file (angular web app) from S3, and it is angular that is calling the load balancer (to transfer the request to an EC2 instance) for DB data.
When angular calls the api directly via the load balancer domain name over HTTP, the request responds as expected.
When angular makes the same api call over HTTPS, I get the following error:
You enabled HTTPS for your domain name, not the ELB domain which Amazon owns. You can only create SSL certificates for domains that you own. You can't enable SSL for "mydomain.com" and then excpect that to somehow work on a completely different domain. You need to change your AngularJS code to reference the API by your custom domain name which you have created an SSL certificate for. You need to point the domain to the ELB and install the SSL certificate for the domain on the ELB.
Mark B provided the almost full solution.
As my javascript code is calling the elastic load balancer (ELB) via it's DNS name provided by AWS, I can't obtain an SSL certificate for the domain I don't own.
As Mark B pointed out, I need to point my javascript code to the domain I do own, and have an SSL cert for.
So I can create a sub domain (e.g. api.mydomain.com) of the domain I own that then points to the ELB.
An A Record (e.g domain pointing to an IP) looks like it could fit the need.
However, an A Record can't point to the ELB because it's IP could change.
The missing step was to use AWS Route 53 to point the A Record to an alias (Route 53 allows you to do this) that represented my AWS Elastic Load Balancer.