Using SNI with Rackspace Cloud Load Balancer and adding upto 20 SSL Certificates on single LB

This is going to be a short and dirty documentation on how to add multiple SSL certificates to a Rackspace Load Balancer.

1. Authorise with rackspace auth api (Get a token with user and api key credentials)
x-auth-key is apikey and x-auth-user is the mycloud username

curl -D - -H "x-auth-user: myusername" -H "x-auth-key: 1c989d8f89dfd87f3df3dff3d6f7fgf" https://auth.api.rackspacecloud.com/v1.0


HTTP/1.1 204 No Content
Server: nginx
Date: Thu, 19 Nov 2015 15:41:38 GMT
Connection: keep-alive
X-Storage-Token: AAA98345kdfg893DFGDF43iudng39dfgjkdfgDFI$JUIDFJGDFJGDFGDJJHDFGJHIfdg34dfgkdfjgiodfgiodfDFGDdg323
X-Storage-Url: https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_1001001
X-NewRelic-App-Data: PxQGUF9aDwETVlhSBQUP
X-CDN-Management-Url: https://cdn3.clouddrive.com/v1/MossoCloudFS_1001001
X-Auth-Token: AAA98345kdfg893DFGDF43iudng39dfgjkdfgDFI$JUIDFJGDFJGDFGDJJHDFGJHIfdg34dfgkdfjgiodfgiodfDFGDdg323
vary: Accept, Accept-Encoding, X-Auth-Token, X-Auth-Key, X-Storage-User, X-Storage-Pass, X-Auth-User
Cache-Control: s-maxage=86319
Front-End-Https: on

Now you can copy and paste the X-Auth-Token. It is needed for the next step

2. Configure the JSON file to upload an additional certificate and private key via API for a domain hostname. Here I am configuring domain.com

file: lb.json

{
  "certificateMapping": {
     "hostName": "domain.com",
     "certificate": "-----BEGIN CERTIFICATE-----\nMIIC/TCCAeWgAwIBAgIJAOjRMYJKDeryMA0GCSqGSIb3DQEBBQUAMBUxEzARBgNV\nBAMMCmRvbWFpbi5jb20wHhcNMTUxMTE5MTQzMjE3WhcNMjUxMTE2MTQzMjE3WjAV\nMRMwEQYDVQQDDApkb21haW4uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAvHTjzWQchX+Gyl/No+ABR9R+F65rJmEPBEutjgWUynOir7ZYu5vmFol8\nhF054W5Xv3Ii4oYJjDJingOqQUBBxJD4jXx8H79y04JGXl8BBrG7azbRbowc4HoP\nRUiVTNaCPgYAGTreiRXmYKb/beotlGDvl0HQQLeDh4iq1X1E8R/lkFRHVAu0rEgC\nIeuJZ2L3Qu06A5yTCwdTJnZmviLmuDQtkfLDqTA8N67U8zjBgKGsj9t7GDSQ7zGp\n6JbTSJXqsXvd7XMLm2Ns2UelVUToxBTwgOIBn0XzZLCIOIlbIn0LHBk8oYEA4JDF\n1mXeqdsFOCtYvFcQBoUihiDjwDdTNQIDAQABo1AwTjAdBgNVHQ4EFgQU1wBZxNte\n9Q//UOl7ZMUvtsXghPEwHwYDVR0jBBgwFoAU1wBZxNte9Q//UOl7ZMUvtsXghPEw\nDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAUNM56u/cc56ESZY4gubX\nh0UQ8TjVbV2G4EkbBkNnm7RgNK48lFIxc55tshawhdN01JH5ZIgB1RvO1/lqouVs\nJrXwnPULBb4M5FcrjjBVu3bIvOjAUVDogOm7pKP/hJALM9CWMuZcXr5C+sYFczaB\nA7uDuMuQoTZBIGF1NyzfO7vmHT5QbEA/1ZYISWrVFNt8g2oxJY+jdgKacxVujWIs\nFpuiCCdvFVI05wCjj3C8BIN/EAcRIqe5gwr5oI+AtwK7fjK5K47/sREMI+W6Bj1w\nZEDz92S+dNtoSPJTBWiIQFLslTPiaDAu1EjJO1+YRXG7LANdxpQrogvDG1l9VpDW\nRg==\n-----END CERTIFICATE-----",
  "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAvHTjzWQchX+Gyl/No+ABR9R+F65rJmEPBEutjgWUynOir7ZY\nu5vmFol8hF054W5Xv3Ii4oYJjDJingOqQUBBxJD4jXx8H79y04JGXl8BBrG7azbR\nbowc4HoPRUiVTNaCPgYAGTreiRXmYKb/beotlGDvl0HQQLeDh4iq1X1E8R/lkFRH\nVAu0rEgCIeuJZ2L3Qu06A5yTCwdTJnZmviLmuDQtkfLDqTA8N67U8zjBgKGsj9t7\nGDSQ7zGp6JbTSJXqsXvd7XMLm2Ns2UelVUToxBTwgOIBn0XzZLCIOIlbIn0LHBk8\noYEA4JDF1mXeqdsFOCtYvFcQBoUihiDjwDdTNQIDAQABAoIBAQCSEJr7d0tv4P6s\n3gI5sIXtkXHFkwczcOi9sJYszICdRXDjdZZimpuD/j3HLaaN5gMWvDTzk2XVBrxO\nspKEDnSrEJ3Es6ZUyQMLkh5OSJ43/QtBNvSuFOTQy2oIjhBBxMSfo/DxnSIb6CBt\n6yFwpJ99MICioHzznAjSxId7/qKvq294emBGwpyP6JbCEtrM6rsnBO4J/uHUDLRj\nlU0zLFwFHNQnhnfIuxOoUZthyCSzZgUquC7C52qIPTZxqCydSi045pDoymn6pT43\n5YdafzWarmEqBGcyqDOyjOz01IEicrmFW7e2+DICIOTOvTSeFQtHbO4Rn2VE2V+x\nGNJY3DoFAoGBAORqB6gFlLUKBXdmP1VcEifjwcVtBaY9QwehbH8En6O0N1t5bKFx\nTBaShm2El+7UCeeSz9hx3vmV/4gn9amJnu6stOEUfjbfxe6mw8OtR13g5iSAI9TQ\nXesf1HoCrUsljzAPvBAKxWSQl9e6fYBxmB1IvFvd4n9uvoNWr/lOfbe3AoGBANM3\neddZYHBB0PhgiJ9aq7QkgqUSdv5JlBdtGdPDr3cpIx9QmXMtf+wc8vZ6CSvC3EIn\npADRt3QAIzxQLpXb3ADjBCwwsFCu27IXlVkvxD+yvqaLbAjB/LgbKqt5wR6YAarj\nDQzNzxhGvrCS+CvYSKospY6UK5+V0nuhuPVcuJRzAoGAAPHLTE+RmNoMwbyjgGfc\nD1wqvfVAc7qHH230c+YB/vxMyk0LPPOp++HpOmS0+CDaVaHOyDdYU7HiF58KrgPK\nq3P9X3zlNLbiK6V248VAqUu3x+jbvRKLgOBl0YdXThs+p1U5Utuoi0zpw9Oal0Bg\n/6YAWWTmfd5oXUSrf51qeasCgYEAgMahBZgbgTXPh6+rfKTWbQWZlbU1UYJgxQui\npIb5cwhkvpHwjNWf2cAorffnoYOzsK3kgw9Z72KqGPq1/G5Iq0293Idu6DJEBkf0\nqaTC3SdIr9fvbUOApmsBz/xyrwl0ctDtwvG0IxP27UceAfVjEEYaRly2YB0DcJdA\nYnA+pVsCgYEAoHfkw/ZPmB7r8LesF0+N93AErJ/IiPoCBFNKijVDplzLQbMeWyxL\njcnFdq8vQT0Os4qzRNCR5QbMcprJIh4LC96OIlGWz5NhKCWbGsKxA8N7YoWGYy9Z\nmRkVP6peBU2cGdXRWjCrxkKR+uJM9BCG0Ix3BOPy29nWaCEl+5wjBEc=\n-----END RSA PRIVATE KEY-----"
  }

3. Call API to add certificatemapping json lb hostname configuration file. This just allows example.com to have SSL on the Load Balancer.
(you can add up to 20 Domains). It’s lots cheaper and not as hard as I might have initially thought!!

curl -v -H "X-Auth-Token: $TOKEN" -d @lb.json -X POST -H "content-type: application/json"  https://lon.loadbalancers.api.rackspacecloud.com/v1.0/1001001/loadbalancers/157089/ssltermination/certificatemappings

It’s also possible to update the Load Balancer Certificates via the API, please see https://developer.rackspace.com/docs/cloud-load-balancers/v1/developer-guide/#update-certificate-mapping for more information

4. Confirm the certificate mappings are added (please note 1001011 is the customer DDI and 157090 is the Load Balancer ID).

curl -v -H "X-Auth-Token: $TOKEN" -X GET https://lon.loadbalancers.api.rackspacecloud.com/v1.0/1001011/loadbalancers/157090/ssltermination/certificatemappings


< HTTP/1.1 200 OK
< Content-Type: application/json
< Via: 1.1 Rackspace Cloud Load Balancer API v1.25.11 (Repose/2.11.0)
< Content-Length: 83
< Date: Thu, 19 Nov 2015 15:49:24 GMT
* Server Jetty(8.0.y.z-SNAPSHOT) is not blacklisted
< Server: Jetty(8.0.y.z-SNAPSHOT)
<
* Connection #0 to host lon.loadbalancers.api.rackspacecloud.com left intact
{"certificateMappings":[{"certificateMapping":{"id":999,"hostName":"domain.com"}}]}

You may note that the lb.json file has the certificate all on one line! how to do this? It's not that hard. Here is how I did it:

cat domain.com.cert | sed ':a;N;$!ba;s/\n/\\n/g'
cat domain.com.key  | sed ':a;N;$!ba;s/\n/\\n/g'
-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAvHTjzWQchX+Gyl/No+ABR9R+F65rJmEPBEutjgWUynOir7ZY\nu5vmFol8hF054W5Xv3Ii4oYJjDJingOqQUBBxJD4jXx8H79y04JGXl8BBrG7azbR\nbowc4HoPRUiVTNaCPgYAGTreiRXmYKb/beotlGDvl0HQQLeDh4iq1X1E8R/lkFRH\nVAu0rEgCIeuJZ2L3Qu06A5yTCwdTJnZmviLmuDQtkfLDqTA8N67U8zjBgKGsj9t7\nGDSQ7zGp6JbTSJXqsXvd7XMLm2Ns2UelVUToxBTwgOIBn0XzZLCIOIlbIn0LHBk8\noYEA4JDF1mXeqdsFOCtYvFcQBoUihiDjwDdTNQIDAQABAoIBAQCSEJr7d0tv4P6s\n3gI5sIXtkXHFkwczcOi9sJYszICdRXDjdZZimpuD/j3HLaaN5gMWvDTzk2XVBrxO\nspKEDnSrEJ3Es6ZUyQMLkh5OSJ43/QtBNvSuFOTQy2oIjhBBxMSfo/DxnSIb6CBt\n6yFwpJ99MICioHzznAjSxId7/qKvq294emBGwpyP6JbCEtrM6rsnBO4J/uHUDLRj\nlU0zLFwFHNQnhnfIuxOoUZthyCSzZgUquC7C52qIPTZxqCydSi045pDoymn6pT43\n5YdafzWarmEqBGcyqDOyjOz01IEicrmFW7e2+DICIOTOvTSeFQtHbO4Rn2VE2V+x\nGNJY3DoFAoGBAORqB6gFlLUKBXdmP1VcEifjwcVtBaY9QwehbH8En6O0N1t5bKFx\nTBaShm2El+7UCeeSz9hx3vmV/4gn9amJnu6stOEUfjbfxe6mw8OtR13g5iSAI9TQ\nXesf1HoCrUsljzAPvBAKxWSQl9e6fYBxmB1IvFvd4n9uvoNWr/lOfbe3AoGBANM3\neddZYHBB0PhgiJ9aq7QkgqUSdv5JlBdtGdPDr3cpIx9QmXMtf+wc8vZ6CSvC3EIn\npADRt3QAIzxQLpXb3ADjBCwwsFCu27IXlVkvxD+yvqaLbAjB/LgbKqt5wR6YAarj\nDQzNzxhGvrCS+CvYSKospY6UK5+V0nuhuPVcuJRzAoGAAPHLTE+RmNoMwbyjgGfc\nD1wqvfVAc7qHH230c+YB/vxMyk0LPPOp++HpOmS0+CDaVaHOyDdYU7HiF58KrgPK\nq3P9X3zlNLbiK6V248VAqUu3x+jbvRKLgOBl0YdXThs+p1U5Utuoi0zpw9Oal0Bg\n/6YAWWTmfd5oXUSrf51qeasCgYEAgMahBZgbgTXPh6+rfKTWbQWZlbU1UYJgxQui\npIb5cwhkvpHwjNWf2cAorffnoYOzsK3kgw9Z72KqGPq1/G5Iq0293Idu6DJEBkf0\nqaTC3SdIr9fvbUOApmsBz/xyrwl0ctDtwvG0IxP27UceAfVjEEYaRly2YB0DcJdA\nYnA+pVsCgYEAoHfkw/ZPmB7r8LesF0+N93AErJ/IiPoCBFNKijVDplzLQbMeWyxL\njcnFdq8vQT0Os4qzRNCR5QbMcprJIh4LC96OIlGWz5NhKCWbGsKxA8N7YoWGYy9Z\nmRkVP6peBU2cGdXRWjCrxkKR+uJM9BCG0Ix3BOPy29nWaCEl+5wjBEc=\n-----END RSA PRIVATE KEY-----

Notice the extra \n's after the processing.

Don't be intimidated by the sed line, it just replaces the \n newline with the character \n instead, so the json file is easier to lay out the cert as a 'string'.

Important notes on SNI:

We know we can add certificate mappings on the Load Balancer.
the Load Balancer has been configured for Allowing secure and insecure traffic, Port 443. SSL is terminated at the load balancer. This is what is known as OFFLOADING, it just means the SSL encryption is seen at the load balancer. Behind the load balancer, there is no encryption between it and the server. This allows the SNI hostname to be forwarded to the server, without it being in an encrypted form within the TCP packet.

5. Now lets install apache2 and configure some virtualhosts, at the most basic level. This is for an example and not a perfect setup

apt-get update
apt-get install httpd
vi /etc/apache2/httpd.conf



ServerName example.com
Documentroot /var/www/example.com/html




ServerName domain.com
Documentroot /var/www/domain.com/html


mkdir -p /var/www/domain.com/html
mkdir -p /var/www/example.com/html
echo 'example.com page body testing' > /var/www/example.com/html/index.html
echo 'domain.com page body testing' > /var/www/domain.com/html/index.html
vi /etc/apache2/apache2.conf

add one line in the file like:

Include /etc/apache2/httpd.conf

I just like to configure apache2 this way.

/etc/init.d/apache2 restart

6. Confirm both websites are working thru LB with SNI

# Curl domain
$ curl domain.com
domain.com page body testing

# curl domain 2
$ curl example.com
example.com page body testing

# curl IP address
curl https://194.213.79.117
someotherdefaultpage

# what happened when curling the IP address? Well..There was no TCP servername/hostname forwarded in the header for SNI support to detect the domain x-forwarded-for

# Lets provide the header
curl https://194.213.79.117 -H "host: example.com"

Testing SSL on the hostnames

openssl s_client -connect domain.com:443
openssl s_client -connect domain.com:443 -host domain.com
openssl s_client -connect domain.com:443 -servername domain.com