SSL for SaaS application - haproxy

How can i use Lets encrypt cert manger with Ha-proxy loadbalancer?I need to implement custom domain feature service on my SaaS application.Everything working fine except the SSL. How can i implement?Using Haproxy as a Loadbalancer.

Here is a possible solution. The easier in my opinion. It uses Haproxy Community and Certbot client.
Install Certbot client on a separated server and develop a REST API to interact with the client. Here you will be able to integrate your application with Certbot to generate the certificates.
Create a directory on HAproxy server to store the certificates. Install NFS on the server and mount this directory on Certbot server. When generating certs with Certbot, deploy to this mount point.
Create a deployment script for Certbot so it reloads Haproxy service when a new cert is deployed.
Schedule a task on Certbot server so it runs a renewal process once a day.
If you don't like the Certbot client, you can develop a client yourself. I am developing one right now in Scala to integrate with my e-commerce platform, it's not that hard.

tried to define the steps. Reduced from a larger script , if you have an error please write here to fix this.
Prerequisites :
haproxy installed , for example here: ip is 200.200.200.200
domain dns aquiered and directed to haproxy , for example here: test.com
http is working , if this is working then the whole web chain is working
have letsencrypt installed and with account
possible to stop haproxy and have the site down
Steps:
clean up old folders in /etc/letsencrypt that are with test.com rm -rf *test.com*
stop haproxy
run command :
certbot certonly --standalone --preferred-challenges http --http-01-port 80 -d test.com
certbot certonly --standalone --preferred-challenges http --http-01-port 80 -d www.test.com
check if all ok
root#200.200.200.200:/etc/letsencrypt/renewal# cat www.test.com.conf
should be:
#renew_before_expiry = 30 days
version = 0.22.2
archive_dir = /etc/letsencrypt/archive/www.test.com
cert = /etc/letsencrypt/live/www.test.com/cert.pem
privkey = /etc/letsencrypt/live/www.test.com/privkey.pem
chain = /etc/letsencrypt/live/www.test.com/chain.pem
fullchain = /etc/letsencrypt/live/www.test.com/fullchain.pem
# Options used in the renewal process
[renewalparams]
http01_port = 80
installer = None
pref_challs = http-01,
account = YOUR_ACCOUNT
authenticator = standalone
create the folders /etc/letsencrypt/live/www.test.com and etc/letsencrypt/live/test.com
create the link files to the archive files
ln -s ../../archive/test.com/cert1.pem cert.pem
ln -s ../../archive/test.com/chain1.pem chain.pem
ln -s ../../archive/test.com/fullchain1.pem fullchain.pem
ln -s ../../archive/test.com/privkey1.pem privatekey.pem
copy the certificate to haproxy
cat fullchain.pem privatekey.pem > /etc/haproxy/ssl/test.com-fullchain.pem
the same for www
add in haproxy a ssl frontend
frontend test_com_ssl
bind *:443 ssl crt /etc/haproxy/ssl/ ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
default_backend test_com
the backend can be the same as for http frontend
restart haproxy , check if the certificate is active
To Check to see the expiry date of the certificate:
Type
openssl x509 -enddate -noout -in test.com-fullchain.pem
TO DO:
Not covered how to renew the script ,hope to do this in the future

Related

Encrypt & Decrypt data between Kubernetes API Server and Client

I have two kubernetes cluster setup with kubeadm and im using haproxy to redirect and load balance traffic to the different clusters. Now I want to redirect the requests to the respective api server of each cluster.
Therefore, I need to decrypt the ssl requests, read the "Host" HTTP-Header and encrypt the traffic again. My example haproxy config file looks like this:
frontend k8s-api-server
bind *:6443 ssl crt /root/k8s/ssl/apiserver.pem
mode http
default_backend k8s-prod-master-api-server
backend k8s-prod-master-api-server
mode http
option forwardfor
server master 10.0.0.2:6443 ssl ca-file /root/k8s/ssl/ca.crt
If I now access the api server via kubectl, I get the following errors:
kubectl get pods
error: the server doesn't have a resource type "pods"
kubectl get nodes
error: the server doesn't have a resource type "nodes"
I think im using the wrong certificates for decryption and encryption.
Do I need to use the apiserver.crt , apiserver.key and ca.crt files in the directory /etc/kubernetes/pki ?
Your setup probably entails authenticating with your Kubernetes API server via client certificates; when your HAProxy reinitiates the connection it is not doing so with the client key and certificate on your local machine, and it's likely making an unauthenticated request. As such, it probably doesn't have permission to know about the pod and node resources.
An alternative is to proxy at L4 by reading the SNI header and forwarding traffic that way. This way, you don't need to read any HTTP headers, and thus you don't need to decrypt and re-encrypt the traffic. This is possible to do with HAProxy.

How to authenticate https client certificates using Dancer/Starman or Mojolicious/Daemon?

I am trying to perform Authentication using HTTPS client certificates using perl Dancer framework.
I would like to accept requests sent with/without certificate and do validation on the certificate CN to proceed with the valid response
(https://medium.com/#sevcsik/authentication-using-https-client-certificates-3c9d270e8326, the link shows how to do it in node.js, need something very similar for perl Dancer/Starman/Plackup)
I have setup ssl using Dancer/Plackup, but have not found a way to get details about the peer certificate to perform validation in Dancer framework
I would like to achieve the following:
If the request is sent
without certificate => 401
with certificate but client has self-signed (CN doesn't match with server cert CN) => 401
with certificate but client cert has been signed using server cert (CN matches server cert CN) => 200
In Dancer you can get the IO::Socket::SSL object with request->env->{'psgix.io'}, but that does not help you because you have no opportunity to configure it for client verification. IO::Socket::SSL::set_defaults does not run early enough, either.
This means it's best to set up Apache httpd or nginx to terminate TLS. Pass on the certificate info you need (e.g. client verification result) in environment variables to the Dancer application.
To anyone who is facing the issue, I solved it by the following steps:
(To create client and server certificates, I followed https://medium.com/#sevcsik/authentication-using-https-client-certificates-3c9d270e8326)
1) Use nginx (Setup guide:https://gist.github.com/netpoetica/5879685)
2) Create the nginx config
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /to/path/server_cert.pem; # server certificate
ssl_certificate_key /to/path/server_key.pem; # server key
ssl_client_certificate /to/path/server_cert.pem; # client CA => server certificate for self signed
ssl_verify_client on;
location / {
proxy_pass http://localhost:5000;
proxy_set_header SSL_CLIENT_CERT $ssl_client_cert; #ENTIRE CLIENT CERTIFICATE
proxy_set_header SSL_CLIENT_S_DN $ssl_client_s_dn; #SUBJECT DN
proxy_set_header SSL_CLIENT_I_DN $ssl_client_i_dn; #ISSUER DN
}
}
More details regarding ssl can be shared using the attributes mentioned on http://nginx.org/en/docs/http/ngx_http_ssl_module.html#variables
3) Dancer application
get '/' => sub {
info to_dumper(request->headers);
content_type 'text/xml';
return "OK";
};
4) Start the dancer application using plackup (or starman/your preferred choice)
carton exec plackup -R /bin,/lib bin/app.psgi
5) Send the request to the server
curl -v https://localhost/ --key client_key.pem --cert client_cert.pem --cacert server_cert.pem
6) You should observe client certificate details in the plackup logs

how to get a client key and client root cert for connecting to CockroachDB from Java client

I have deployed a CockroachDB single instance cluster in my Kubernetes cluster on DO following this link https://www.cockroachlabs.com/docs/stable/orchestrate-a-local-cluster-with-kubernetes.html.
I followed this link to generate a server.crt file from https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster using the command:
kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
| base64 --decode > server.crt
Not sure that gets me a client cert.
The following is my output for the command:
kubectl get csr
NAME AGE REQUESTOR CONDITION
default.client.root 44m system:serviceaccount:default:my-release-cockroachdb Approved,Issued
I need to connect to CockroachDB using my Java client. How do I generate a client cert and key so I can access CockroachDB from Java?
Thanks
There are multiple concerns here:
the certificate you are requesting from the k8s PKI will not have any of the fields required
the key format will not work for java clients
Let's address them one at a time:
Requesting a client certificate from the kubernetes PKI
A client certificate for user with CockroachDB must the subject's Common Name set to the username. eg: CN=root. This must also be properly configured to allow Client Authentication in the key usage.
In the kubernetes docs, we include an example to bring up a client within the same kubernetes cluster. The config for secure clients includes an init container that requests a client certificate and makes it available to the main job.
If your client is running in Kubernetes, I recommend adapting that config for your own client.
Key format for java clients
Java clients expect keys in PKCS#8 format, whereas the certificates output by both your command and the request-cert tool both output PEM encoded keys.
You can convert the key using openssl:
openssl pkcs8 -topk8 -inform PEM -outform DER -in client.myuser.key -out client.myuser.pk8
You can find more details on the CockroachDB Build a Java app page.

setting up haproxy to listen to ssl

I followed the instructions at https://www.digitalocean.com/community/tutorials/how-to-implement-ssl-termination-with-haproxy-on-ubuntu-14-04 to setup haproxy to listen to ssl.
However when i try to hit any request through https it doesn't seem to be working, i basically get a ERR_CONNECTION_REFUSED.
I started haproxy by outputting all the operations into nohup. I tried looking into nohup and i dont seem to be getting any info there when i hit the request.
Basically this is the config that i added:
frontend https
bind *:443 ssl crt /etc/ssl/private/{domainname.com}.pem
reqadd X-Forwarded-Proto:\ https
default_backend default
While generating the certificate i have the same domainname.com as well.
Is there any other way to find out why it doesnt seem to work.
You can use "openssl" to verify the certificate response:
echo | openssl s_client -showcerts -connect yourdomain:443
or try "curl":
curl -v -o /dev/null https://yourdomain
check if your haproxy logging is enabled and correct, e.g.:
global
log 127.0.0.1 local0
defaults
log global

How to apply a csr certi on HAproxy?

I got some certificates from my CA , as follows
1. something.csr
2. something.zip --> contains 2 .cert files.
I am using HAProxy and want apply them. The Haproxy already uses .pem certificate, so how do i convert/combine the above mentioned certs to get one single .pem file?
Concat the following into a single PEM file ordered by:
Private Key
Your domain's cert
Intermediate certs
Root cert
Concatenate something.csr & something.key to something.pem, this is how HAproxy understands certificate.
Add below backend to haproxy.cfg
frontend https-port443
bind *:443 ssl crt /path/to/something.pem
mode http