Authenticate everything with SSL

le

Lots of server tools were made for private hosting. Behind your firewall, nobody knows you are naked. But, in 2013, it's Cloud time, everybody got its own naked virtual server, flavored with some SAAS. Some major services, like memcached recently got its authenticated version, REST ones can be easily proxified, but others, with classical sockets, remain unauthenticated : patching protocols is painful. UDP services don't like authentication, just use them in localhost, and forget mutualized hosting, LXC is now trendy. Mutalized hosting is like the subway, just use a light container like Velib (parisian bike as a service). TCP services can easily handle some authentication. With a persistent connection, it's easier, it's just a simple FSM (Finite State Machine), first give some credentials, and switch from not authenticated state to authenticated state. Mysql can do it, so you can. If you like standards, use SASL, and don't bother, just handle PLAIN authentication, nobody can beat shared secret or SSL for security. SSL is also a secret weapon, it replaces a classical socket with a secured none. SSL is a protocol which handles protocols. SSL can use authentication with certificates, and magically add authentication without modifying the guest protocol. SSL authentication is hard to use with public users, and you have to buy certificates. Inside your hosting solution, it's easier, you own the certificate authority, sign certificates for the servers and the clients. OpenVPN is a good example of certificate authentication. SSL is a complex beast, anything you do without understanding it can cause drama. Easy-RSA provides simple tools to handle certificates with good practices. Stunnel provides a simple proxy for adding SSL communication to any client or server. Don't try to handle broken or weak solutions, just use the best : if you own client and server side, you are the king of your mountain!

Here is samples for authenticating Carbon service, from Graphite project.

Easy-RSA

In a trusted computer, build your own PKI.

git clone git://github.com/OpenVPN/easy-rsa.git
cd easy-rsa/easy-rsa/2.0/

Edit vars file, and sets informations about your country, company...

source vars
./build-ca

CA private key is the weakest link in your security chain, be careful. Build a server certificate

./build-key-server

And some clients

./build-key client_name

.key files are private keys, be kind with them, .crt and .csr are public.

Stunnel

Stunnel is an old beast, born when inetd still ruled servers, but don't be afraid, it's still the best tool. Watch for HAproxy 1.5, it will handles SSL, and challenge Stunnel the elder.

Use a simple config file, with contemporary settings, no compatibility tricks. Here is a server config for wrapping Carbon server.

# vim:ft=dosini
sslVersion = SSLv3
#public
cert = /opt/graphite/ssl/carbon.crt
#private
key = /opt/graphite/ssl/carbon.key
chroot = /var/lib/stunnel4/
setuid = stunnel4
setgid = stunnel4
; PID is created inside the chroot jail
pid = /stunnel4.pid
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
# This enables the mutual authentication
verify = 2
# public CA, for client validation
CAfile = /opt/graphite/ssl/ca.crt
compression = zlib
#debug = 5
output=/var/log/stunnel.log
# Some cargo cult settings
options = NO_SSLv2
options = SINGLE_ECDH_USE
options = SINGLE_DH_USE
[carbons]
# the public port
accept = 2103
# server just listen localhost
connect = 127.0.0.1:2003

Client side is quite similar:

# vim:ft=dosini
sslVersion = SSLv3
cert = client1.crt
key = client1.key
#setuid = stunnel4
#setgid = stunnel4
pid = /tmp/stunnel.pid
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
CAfile = ca.crt
debug = 5
foreground = yes
options = NO_SSLv2
options = SINGLE_ECDH_USE
options = SINGLE_DH_USE
[carbons]
client = yes
accept = 2003
connect = my.public.server.com:2103

It's just a test from a mac, no chown, no pid, no detach. If I connect my telnet to localhost:2003, the real server behind ssl answers. Client checks that the server certificate is signed with my own trusted authority, no risk of man in the middle with a forged certificate.

SSL can revoke certificates, just read the documentation.

Python and SSL

In this example, I don't want to modify the server side, Graphite stack is a bit messy and large, and I fear Twisted code, so, stunnel wraps graphite as a black box. But client side, it's easier, carbon protocol is dummy, and gstatsd, a python gevent Statsd clone is easy to hack.

Python handles SSL nicely, just like gevent.

#!/usr/bin/env python
import socket
import ssl
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_sock = ssl.wrap_socket(s,
                           certfile="./client1.crt",
                           keyfile="./client1.key",
                           ca_certs="./ca.crt",
                           ssl_version=ssl.PROTOCOL_SSLv3,
                           cert_reqs=ssl.CERT_REQUIRED)
ssl_sock.connect(('my.public.server.com', 2103))
now = int(time.time())
ssl_sock.write("local.test.toto 22 %d\n" % now)

You build a socket, wrap it with ssl (and your client certificates), and use it like a plain old socket.

The patch for Gstasd is as simple as this example.

I don't fear patching any Statsd clone (em ruby, nodejs, go ...), ssl is a standard, and Openssl is almost universal.

Http is not the only way to proxying stuff, like obfuscurity suggests with its backstop.

Ssl can already be used as a proxy instead of http.

Keep it simple, secure.


Partager cet article :