# Hacking a New SSL Certificate Structure for Ganeti 2.12.x

If you have somehow mashed the the server/client certificates on your cluster, or otherwise gotten into a deep SSL mess, and you, as we did, found the advice at  [GanetiAndSSL](https://code.google.com/p/ganeti/wiki/GanetiAndSSL) did not work for you, then maybe the following will help. We speculate that  the damage to our certs was caused during the upgrade from 2.11 to 2.12.  There's lots of evidence from the mailing list postings that the change in security  model bit a lot of people during the upgrade process.  This recipe was hacked at some cost in source diving and certificate exploring (on a working cluster) by Rob Austein, Hans Kuhn, and Randy Bush.

Be aware that this has only been tested for 2.12 and it's possible the security  model will change in the future. There are no guarantees it will even work for  your case and it is offered in the spirit of shared discovery.

Apologies for the examples assuming the node names of our cluster, vm[0123].

## Generate Server and Client Certificates and ssconf_master_candidates_certs

Despite hints in documentation, conferences, presentations, etc.

- There is no Certificate Authority.
- All certificates are self-signed.
- Client certificates are NOT signed by the server certificate.
- Things break if the CN is not the same for all certificates.
- The client.pem files we found were all ancient X.509v1 certificates with no extensions etc.
- --no-ssl in /etc/default/ganeti didn't allow us to run without SSL

The following script gets a list of {nodename, uuid} and generates certificates and a new ssconf_master_candidates_certs file.

```
#!/bin/sh -

make_cert() {
    local filename=$1 hostname=$2 
    openssl req -batch					\
	    -newkey rsa:2048 -keyout $filename -nodes	\
	    -x509	     -out    $filename		\
	    -sha1					\
	    -days   1825				\
	    -subj   "/CN=$hostname"
    }

make_cert server.pem ganeti.example.com

rm -f ssconf_master_candidates_certs.new

# the following use of gnt-node assumes a semi-working cluster if not,
# you need to hack a file of the form {hostname uuid} for all hosts.
# this can be rescued from the old ssconf_master_candidates_certs
#cat nodehack |
gnt-node list -o name,uuid --no-headers |
while read hn uuid
do
    fn=${hn%%.*}.client.pem
    make_cert $fn ganeti.example.com
    fp="$(openssl x509 -noout -fingerprint -sha1 -in $fn | awk -F= '{print $2}')"
    echo >> ssconf_master_candidates_certs.new "${uuid}=${fp}"
    done
```

This generates a server.pem, a set of {nodename}.client.pem files, and a ssconf_master_candidates_certs.new file which you will distribute to the nodes in a later step.

## Updating the /var/lib/ganeti/config.data

The hashes of the certificates need to be corrected in the /var/lib/ganeti/config.data file.  This code needs a copy of the config.data file in your working directory.

```
#!/usr/bin/env python
import json

with open("ssconf_master_candidates_certs.new", "r") as f:
  candidate_certs = dict(line.strip().split("=") for line in f)

with open("config.data", "rb") as f:
  config = json.load(f)

config["cluster"]["candidate_certs"] = candidate_certs

with open("config.data.new", "wb") as f:
  json.dump(config, f)
```

And it generates a file config.data.new to be pushed in the next step.

## Pushing the Files to Nodes

The generated certificates need to be pushed to all nodes, along with the ssconf_master_candidates_certs file and the config.data.

Apologies that this example uses our node names vm[0123] and is run as root.

```
#!/bin/sh

for i in 0 1 2 3; do 

   rsync vm$i.client.pem vm$i:/var/lib/ganeti/client.pem
   ssh vm$i chown gnt-masterd:gnt-masterd /var/lib/ganeti/client.pem
   ssh vm$i chmod 440 /var/lib/ganeti/client.pem
					    
   rsync server.pem vm$i:/var/lib/ganeti
   ssh vm$i chown gnt-masterd:gnt-masterd /var/lib/ganeti/server.pem
   ssh vm$i chmod 440 /var/lib/ganeti/server.pem

   rsync ssconf_master_candidates_certs.new \
   	 vm$i:/var/lib/ganeti/ssconf_master_candidates_certs
   ssh vm$i chown root:root /var/lib/ganeti/ssconf_master_candidates_certs
   ssh vm$i chmod 444 /var/lib/ganeti/ssconf_master_candidates_certs

   rsync config.data.new vm$i:/var/lib/ganeti/config.data
   ssh vm$i chown gnt-masterd:gnt-confd /var/lib/ganeti/config.data
   ssh vm$i chmod 640 /var/lib/ganeti/config.data

   done 
```

## Declare Victory

At this point, we were able to restart ganeti on all nodes. You'll need  to log into each server to run this command, because the master isn't  able to communicate to the nodes yet.

```
service ganeti restart
```

and successfully verify the cluster

```
gnt-cluster verify
```

We were even able to generate a new generation of credentials. This  command generates a single server.pem that is distributed to all nodes,  as well as a unique per-node client.pem that is distributed to the  appropriate node. ssconf_master_candidates_certs is generated, and  finally the ganeti service is restarted on all nodes.

```
gnt-cluster renew-crypto --new-cluster-certificate
```

Oddly, the client.pem objects, presumably generated by Ganeti itself  when we told it to renew-crypto, were X.509v3 CA certificates, with BasicConstraints, AKI, and SKI extensions.  Still self-signed, and no  evidence that they signed anything else.