-
Notifications
You must be signed in to change notification settings - Fork 51
SimianAndCertificates
TL;DR Simian uses 2 layers of certificate exchange, both SSL and custom, to make certain authentication of client and server.
Simian makes use of X509 certificates signed by a common CA as part of its own authentication process during client connection. This exchange occurs in addition to the certificate exchange that occurs as part of SSL layer initialization.
In a conventional scenario https clients and servers make use of certificate validation at the SSL layer to authenticate each other. However in standard configuration the Google frontend servers which redirect to the AppEngine backend do not make client SSL information fully available. Therefore your Simian server instance cannot verify the identity of the client purely via the SSL layer transactions.
Similarly, because your Simian server will offer a wildcard *
.appspot.com SSL certificate shared by all appspot domains, just having the Simian client trust the server based on this certificate would not be sufficient to prevent certain types of man in the middle attacks to occur.
Therefore once the SSL layer is established, Simian additionally exchanges a second set of messages with signatures and certificates to allow both the Simian client and Simian server instance to fully verify their exact identities. The SSL layer is still used to provide end to end encryption/MITM prevention.
The following files must exist on each Simian client relative to the path /etc/simian/ssl/
:
- ca_public_cert.pem: the certificate for the CA of the server and client certificates.
- server_public_cert.pem: the public certificate, signed by the CA, for the server.
-
root_ca_cert_chain.pem (optional): the root CA certificate chain to validate the server certificate. If not specified,
/usr/bin/security
is used to obtain the root CA certificates chain. Depending on your security preferences, this default may suffice.
The following files should exist in /etc/simian/ssl/certs/
:
- unique_client_uuid_here.pem: public certificate (unique to each client)
The following files should exist in /etc/simian/ssl/private_keys/
:
- unique_client_uuid_here.pem: private key (unique to each client)
Note that below we propose a naming scheme of using the Apple hardware serial number for the client uuid.
The certificates/keys above are not used for the HTTPS transport itself. Rather they are used during the additional authentication steps that occur between the Simian client/server. See the Custom Authentication section of DesignDocument for more information.
TL;DR Can you reuse a CA that you already have at your org?
In some organizations you may already have a certificate authority which can generate public/private key pairs for you. For example, if you are using Puppet, you probably already have keys on each client machine. In this case you should likely reuse this infrastructure and obtain the following:
- public cert of your CA
- a new public cert/private key pair for Simian server
- public cert/private key pair for EACH client machine
Keep in mind the client and server certificates should all be signed by the same CA.
If you don't have any CA infrastructure at all, you will need to create it yourself. There may be open or closed source tools which automate this process for you at a higher level. For example, Apple Keychain Access provides CA tools which may simplify these steps.
However for the purposes of demonstration we will use the OpenSSL command line tools.
Note that Simian will only read PEM file formats, so be sure to output keys and certificates in this format when using whatever tools you choose.
First you must create your CA working directory. Note that the OpenSSL man pages will provide much more exhaustive information about how to supply default values for prompts which may help you automate this process. Here we will attempt to get you started quickly and with minimal prompting from OpenSSL.
First create a directory structure for your CA:
mkdir -p CA/private CA/newcerts CA/crl
cd CA
cp /System/Library/OpenSSL/openssl.cnf .
sed -i .bak 's/^dir.*=.*/dir = ./' openssl.cnf
touch index.txt
echo 00000001 > serial
To make our examples easier to follow we will use an environment variable to temporarily store your CA key password. Please use your own security discretion when doing this.
export CAPASS='my strong password goes here'
Now, create the CA key with that password:
openssl req -config openssl.cnf -new -sha1 -x509 \
-days 3650 -extensions v3_ca \
-keyout private/ca.key \
-out newcerts/ca_public_cert.pem \
-passout env:CAPASS
You will be prompted for naming information by openssl to build a subject for the cert. Be sure to define a Common Name for your CA cert.
Note that you will have to configure the required_issuer
setting in your client settings.cfg
. To see the required issuer, which is the issuer of your CA cert, run:
openssl x509 -in newcerts/ca_public_cert.pem -issuer -noout
If you had used default openssl values the output should be something like:
issuer= /C=AU/ST=Some-State/O=Internet Widgits Pty Ltd
Note that this output format differs from how DNs are specified in Simian's etc/simian/settings.cfg
, which would be C=AU,ST=Some-State,O=Internet Widgits Pty Ltd
, note the commas.
When you upload the CA certificate to Simian's config pages it will also automatically determine the required_issuer
value. You could copy+paste the setting from there.
Guard your ca.key
as secret, but make ca_public_cert.pem
part of your Simian configuration, as etc/simian/ssl/ca_public_cert.pem
Now that you have created your CA you can start creating certificates signed by the CA.
Firstly create the server key and certificate request:
openssl req -config openssl.cnf -sha1 -new -nodes \
-out server.csr \
-keyout private/server_private_key.pem \
-subj "/CN=simian-server"
Now, sign your server certificate with the CA identity:
openssl ca -config openssl.cnf -in server.csr \
-md sha1 -days 3650 -notext \
-cert newcerts/ca_public_cert.pem -keyfile private/ca.key \
-policy policy_anything -out newcerts/server_public_cert.pem \
-passin env:CAPASS -batch && rm -f newcerts/01.pem
Note that openssl has created newcerts/01.pem
in addition to newcerts/server_public_cert.pem
that we specifically requested with the -out
option. We deleted it at the end.
Guard your private/server_private_key.pem
as secret and use it in your Simian server configuration. Make newcerts/server_public_cert.pem
part of your Simian configuration, as etc/simian/ssl/server_public_cert.pem
Note: If you have created a new Simian server certificate and key for a Simian server that has already been configured, you will want to delete the old certificate and key on the server. See our tips and tricks wiki for more information.
Each Simian client needs its own cert and key also. The steps are the same as we did above for the server.
We will use a naming scheme where the certificate Common Name is based on the machine's Apple serial number. This coincides well with the behavior of the simianfacter
tool, which prints the machine serial number value for the certname
value if no other value is defined. This simplifies your client configuration.
If you want to form more specific DNs for your machines you may wish to supply default values in openssl.cnf
and tweak our example openssl commands. Note that you must have a commonName
(cn
) attribute no matter how you structure the rest of your client certificate DNs.
To get started with our examples put a list of your hardware serial numbers into a file. Each serial number should be on its own line or separated by spaces.
Each of these space separated names will become the commonName
(cn
) property in your x509 certificate DN.
For example, if you have two machines, run this to generate a list of clients:
echo W1234567ABC W2345678DEF > cns.txt
Note: Your client machine names should not contain spaces and use only legal characters for your filesystem, or fewer. Keep it simple.
The following step will create a private key and signed certificate for each machine listed in cns.txt
:
for cn in $(cat cns.txt) ; do
rm -f client.csr
openssl req -config openssl.cnf -sha1 -new -nodes \
-out client.csr \
-keyout "private/${cn}.pem" \
-subj "/CN=${cn}"
openssl ca -config openssl.cnf -in client.csr \
-md sha1 -days 3650 -notext \
-cert newcerts/ca_public_cert.pem -keyfile private/ca.key \
-out "newcerts/${cn}.pem" \
-policy policy_anything \
-passin env:CAPASS -batch
done
Now you should have generated signed certs and keys for your machines. Also openssl will have written an index of certificates into index.txt
.
Each of your clients need to have only their own cert and private key populated to specific places on their filesystem:
- the cert
CA/newcerts/COMMONNAME.pem
should be copied to/etc/simian/ssl/certs/
- the private key
CA/private/COMMOMNAME.pem
should be copied to/etc/simian/ssl/private_keys/
We can't anticipate all the methods you may have to deliver these individual files to your specific clients.
However the following general purpose shell statement may help you by packaging all of your generated certs/keys for distribution to each individual client, based on the hardware serial numbers you defined in cns.txt
.
mkdir -p dist
for cert in $(cat cns.txt) ; do
rm -rf tmp
mkdir -p tmp/etc/simian/ssl/{certs,private_keys}/
cp newcerts/${cert}.pem tmp/etc/simian/ssl/certs/
cp newcerts/{server,ca}_public_cert.pem tmp/etc/simian/ssl/
cp private/${cert}.pem tmp/etc/simian/ssl/private_keys/
cd tmp && tar -zcf ../dist/${cert}.tgz . && cd .. && rm -rf tmp
done
In dist/
are generated tarballs, one for each machine. Install the tarball on the machine or adapt the code above to form another kind of distribution package type.
Once you have completed all of the steps in this document you have all certificates and keys ready to supply to clients or to the server for configuration.