I have set up a basic API using AWS API Gateway and I would like to link my endpoints to a service I have running on an EC2 instance (using the "HTTP Proxy" integration type). I have read that in order to lock down my EC2 server from only accepting traffic from the API Gateway, I basically have one of two options:
Stick the EC2 instance behind VPC and use Lambda functions (instead of HTTP proxy) that have VPC permissions to act as a "pass through" for the API requests
Create a Client Certificate within API Gateway, make my backend requests using that cert, and verify the cert on the EC2 instance.
I would like to employ a variation of #2 and instead of verifying the cert on the EC2 service instance itself, I would like to instead do that verification on another instance running Haproxy. I have set up a second EC2 instance with Haproxy and have that pointed at my other instance as the backend. I have locked down my service instance so it will only take requests from the Haproxy instance. That is all working. What I have been struggling to figure out is how to verify the AWS Gateway Client Certificate (that I have generated) on the Haproxy machine. I have done tons of googling and there is surprisingly zero information on how to do this exact thing. A couple questions:
Everything I have read seems to suggest that I need to generate SSL server certs on my Haproxy machine and use those in the config. Do I have to do this, or can I verify the AWS client cert without generating any additional certs?
The reading I have done suggests I would need to generate a CA and then use that CA to generate both the server and client certs. If I do in fact need to generate server certs (on the Haproxy machine), how can I generate them if I don't have access to the CA that amazon used to create the gateway client cert? I only have access to the client cert itself, from what I can tell.
Any help here?
SOLUTION UPDATE
First, I had to upgrade my version of HAproxy to v1.5.14 so I could get the SSL capabilities
I originally attempted to generate an official cert with letsencrypt. While I was able to get the API gateway working with this cert, I was not able to generate a letsencrypt cert on the HAproxy machine that the API gateway would accept. The issue surfaced as an "Internal server error" response from the API gateway and as "General SSLEngine problem" in the detailed CloudWatch logs.
I then purchased a wildcard certificate from Gandi, and tried this on the HAproxy machine, but initially ran into the exact same problem. However, I was able to determine that the structure of my SSL cert was not what the API gateway wanted. I googled and found the Gandi chain here:
https://www.gandi.net/static/CAs/GandiStandardSSLCA2.pem
Then I structured my SSL file as follows:
-----BEGIN PRIVATE KEY-----
# private key I generated locally...
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
# cert from gandi...
-----END CERTIFICATE-----
# two certs from file in the above link
I saved out this new PEM file (as haproxy.pem) and used it in my HAproxy frontend bind statement, like so:
bind :443 ssl crt haproxy.pem verify required ca-file api-gw-cert.pem
The api-gw-cert.pem in the above bind statement is a file that contains a client cert that I generated in the API gateway console. Now, the HAproxy machine properly blocks any traffic coming from anywhere but the gateway.
The reading I have done suggests I would need to generate a CA and then use that CA to generate both the server and client certs.
That's one way to do it, but it is not applicable in this case.
Your HAProxy needs to be configured with a working SSL certificate signed by a trusted CA -- not the one that signed the client certificate, and not one you create. It needs to be a certificate signed by a public, trusted CA whose root certificates are in the trust store of the back-end systems at API Gateway... which should be essentially the same as what your web browser trusts, but may be a subset.
Just as your web browser will not speak SSL to a server sporting a self-signed certificate without throwing a warning that you have to bypass, the back-end of API Gateway won't negotiate with an untrusted certificate (and there's no bypass).
Suffice it to say, you need to get API Gateway talking to your HAProxy over TLS before trying to get it to use a client cert, because otherwise you are introducing too many unknowns. Note also that you can't use an Amazon Certificate Manager cert for this, because those certs only work with CloudFront and ELB, neither of which will support client certs directly.
Once the HAProxy is working with API Gateway, you need then to configure it to authenticate the client.
You need ssl and verify required in your bind statement, but you can't verify an SSL client cert without something to verify it against.
I only have access to the client cert itself, from what I can tell.
And that's all you need.
bind ... ssl ... verify required ca-file /etc/haproxy/api-gw-cert.pem.
SSL certs are essentially a trust hierarchy. The trust at the top of the tree is explicit. Normally, the CA is explicitly trusted and anything it has signed is implicitly trusted. The CA "vouches for" the certificates it signs... and for certificates it signs with the CA attribute set, which can also sign certificates under them, extending that implicit trust.
In this case, though, you simply put the client certificate in as the CA file, and then the client certificate "vouches for"... itself. A client presenting the identical certificate is trusted, and anybody else is disconnected. Having just the certificate is not enough for a client to talk to your proxy, of course -- the client also needs the matching private key, which API Gateway has.
So, consider this two separate requirements. Get API Gateway talking to your proxy over TLS first... and after that, authenticating against the client certificate is actually the easier part.
I think you are mixing up server certs and client certs. In this instance API Gateway is the client, and HAProxy is the server. You want HAProxy to verify the client cert sent by API Gateway. API Gateway will generate the certificate for you, you just need to configure HAProxy to verify that certificate is present in every request it processes.
I'm guessing you might be looking at this tutorial where they are telling you to generate the client cert, and then configure HAProxy to verify that cert. The "generate the cert" part of that tutorial can be skipped since API Gateway is generating the cert for you.
You just need to click the "Generate" button in API Gateway, then copy/paste the contents of the certificate it presents you and save that as a .pem file on the HAProxy server. Now I'm not a big HAProxy user, but I think taking the example from that tutorial your HAProxy config would look something like:
bind 192.168.10.1:443 ssl crt ./server.pem verify required
Related
I'm looking to serve HTTPS downloads which are authenticated in both directions using mTLS, the requests and responses being signed with certificates issued by a private CA. The purpose of this is securing OTA updates of an embedded device (I need to identify and authorize both ends before downloading a FW image and PKI + mTLS is a very workable solution). A human being with a browser will never interact with this.
Google Cloud Functions terminate TLS by serving a public Google-issued HTTPS certificate. I can't seem to figure out how to make GCF serve HTTPS using a custom certificate (or to authorize incoming HTTPS requests only if the client certificate is signed by my private CA). Is that even possible? If yes, can anyone point me down the right document or example?
Client certificates are not supported.
I have set up Mutual TLS authentication for my API Gateway.
I then placed my client certificate in the truststore. The file contains the client certificate, intermediate and root certificates (private CA).
When accessing the API Gateway with a browser (Chrome on Windows), browser asks me to provide client certificate. I select the same certificate as I have placed in the trust store.
API Gateway reports the following in the browser:
{"message":"Invalid client certificate chain. More than one client certificate passed"}
UPDATE: I have also tried placing only intermediate and root certs in the trust store. Same error.
UPDATE 2: The same error is also reported when accessing the API with C# code (WebClient) loading the cert from Windows cert store or from disc (pfx file).
If your trust store doesn't contain all the intermediate CA certs, then the client has to send a multi-cert chain. The TLS handshake will work fine, but somewhere there is an explicit check that disallows multi-cert chains. The status code is 400, not 403(!), and you get the "More than one client certificate passed" error.
However, if you're willing to put all the intermediate CA in the API gateway trust store, then the server should not ask the client to send intermediate certs. The client should only send one cert in this case, and API gateway should work.
So something is going wrong when API gateway matches the initial client cert against the trust store, and it's not finding the intermediate. I would check these things:
Make sure you use a specific version ID with the S3 link to the trust store. Otherwise it's hard to tell which version it's actually using, because the API gateway will not automatically pick up a new version as soon as you add one to S3. Maybe you're not using the trust store you think you are.
Your trust store should only include CA certs -- the root cert and intermediates. You said you put the client cert in there, so maybe that's causing an issue. Try taking it out.
SSL newbie here, using haproxy 1.8, having a situation when I have 2 aws API Gateways pointing to the same proxy server and 2 clients certificates generated by api gateway itself assigned one to each gateways.
Now I have a haproxy server that I'm trying to configure in a way to only allow access from these 2 api gateways.
When I do it for api gateway only, meaning I only set the ca-file to a file containing 1 client certificate, it works just fine as expected but I don't know how to set both client certificates to be allowed.
so I have these files setup:
haproxy.pem which contains
server cert issued by go daddy
private key
go daddy certs
api-gw.pem first client cert which was copied from api gateway
api-gw2.pem second client cert which was copied from api gateway
client-certs.crt which is a concatenated version of api-gw.pem and api-gw2.pem
when I bind ssl like below for client cert, it works just fine:
bind :443 ssl crt /etc/haproxy/haproxy.pem verify required ca-file /etc/haproxy/api-gw.pem
or
bind :443 ssl crt /etc/haproxy/haproxy.pem verify required ca-file /etc/haproxy/api-gw2.pem
for each of the bindings above only the correct api gateway can access the proxy and the other one can't.
but when I do as below to allow both access the proxy server, it only allows the first client cert even though the file contains both:
bind :443 ssl crt /etc/haproxy/haproxy.pem verify required ca-file /etc/haproxy/client-certs.pem
As my knowledge is limited when it comes to certificates and ssl, I'm not sure if it would work to put multiple client certificates into one file but from what I've read in internet, it's suggested that way... I still don't know why wouldn't it work though.
EDIT
I Michael suggested, I put both client certs together using the
cat api-gw.pem api-gw2.pem > api-gw-combo.pem
and the combo file looks like:
-----BEGIN CERTIFICATE-----
.....cert content for api-gw
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
.....cert content for api-gw2
-----END CERTIFICATE-----
but same as my initial file client-certs.crt, haproxy still accepts the first cert only.
Your config (about two client CA certificates in one file for SSL client authorization) for me is working fine:
bind 1.2.3.4:443 ssl crt /etc/haproxy/ssl/my-domain.pem ca-file /etc/haproxy/ssl/my_client_CA_bundle.crt verify required
But maybe it is working due for specific situation:
HaProxy 2.2.X,
in my_client_CA_bundle.crt file we have two Root CA for client verification,
but both our CA for client verification are created using the same private key (maybe this is important difference from your problem?).
This config was used for a smooth transition to the new client's CA when the old one runs out.
I have deployed node js app to ec2 instance of single instance type through elasticbeanstalk. After this I deployed my app through amazon api gateway. My EC2 instance is public. I want to restrict it in such a way that it only accepts request from amazon api gateway.
To do this I am following this https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-client-side-ssl-authentication.html
I generated a client side certificate through api gateway but I don't know how to use or install this certificate on EC2 instance so that EC2 instance accepts requests only from aws api gateway. I am using Node js server in my application.
Please help.
The API Gateway client certificate feature does not use ACM certificates.
For client certificates, API Gateway generates its own, self-signed certificates and makes the PEM-encoded public key of the client certificate available to you for configuring you web server. API Gateway keeps the certificate's private key and uses it when making requests to your web server. By design, there is no way to export the private key from API Gateway so you can be certain that the caller is API Gateway as no one else can get the private key.
To get the PEM-encoded public key of the client certificate, call get-client-certificate as documented here
Note that you must also configure you web server with a server certificate signed by a certificate authority which API Gateway trusts. Don't confuse this with the certificate used for a custom domain name. Those are used for TLS termination of incoming requests to your API. The server certificate I'm talking about for this use case is just used on your backend web server so API Gateway can call it via TLS.
It is recommended that you obtain, deploy, configure, and test with your server certificate before you enable the client certificate in API Gateway. Once, you have your server certificate working with API Gateway, then enable the client side certificate and modify your web server to require it.
This article describes how to configure both server side and client side certificates with Node.js.
I need to secure communication between my application and my Web Service.
I own both the application and the Web Service, and I was wondering if it is possible to use HTTPS to do so.
I don't need a certificate to prove to myself who I really am (!), so I don't want to buy an SSL certificate from a Certificate Authority. I just need to make sure no one can intercept the data I pass as WebMethod parameters; Can I create a free certificate and use that to secure communication?
One other thing: I don't want to be forced to get a dedicated, public IP address for my Web Service since it is hosted on a shared Web server.
Definitely it's doable, but hinges on a few conditions.
Create your own self signed certificate. The lack of a certificate authority won't matter in your case because your app is your own consumer.
The host must allow you to configure your IIS site with an SSL cert. Hopefully the tools they provide are good enough.
The shared IP that your web site has currently cannot have more than one certificate bound to it. You're now at the mercy of your host to not move your site to a different IP. It may or may not have an SSL cert on another site at that time. Basically - the first one wins. An IP cannot have more than one cert-secured website.
There are many articles out there showing how to create and install a self signed certificate in IIS. What you need to remember is that this certificate will not be valid as it is not delivered by a certificate authority. Once you set a certificate on the server side you need to indicate to the client to accept the invalid certificate by using the ServerCertificateValidationCallback property:
ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => true;
You can't use a SSL certificate (self signed or otherwise) without a dedicated IP address. Unless your shared hosting provider provides a shared SSL certificate on your IP, you will need to purchase a dedicated IP.
If you want to go through the trouble of doing it, you can use a self-signed certificate and have a tertiary server (or use the IIS server that is self-signing) to be your own certificate authority. This would allow you to generate your own certificate for free, then since you have control over the servers, you could just add your CA server as a trusted and intermediary root certificate authority.
Creating Certificate Authorities and self-signed SSL certificates