salt/doc/topics/tutorials/multimaster_pki.rst
2015-07-28 11:35:32 -06:00

399 lines
13 KiB
ReStructuredText

=======================================
Multi-Master-PKI Tutorial With Failover
=======================================
This tutorial will explain, how to run a salt-environment where a single
minion can have multiple masters and fail-over between them if its current
master fails.
The individual steps are
- setup the master(s) to sign its auth-replies
- setup minion(s) to verify master-public-keys
- enable multiple masters on minion(s)
- enable master-check on minion(s)
Please note, that it is advised to have good knowledge of the salt-
authentication and communication-process to understand this tutorial.
All of the settings described here, go on top of the default
authentication/communication process.
Motivation
==========
The default behaviour of a salt-minion is to connect to a master and accept
the masters public key. With each publication, the master sends his public-key
for the minion to check and if this public-key ever changes, the minion
complains and exits. Practically this means, that there can only be a single
master at any given time.
Would it not be much nicer, if the minion could have any number of masters
(1:n) and jump to the next master if its current master died because of a
network or hardware failure?
.. note::
There is also a MultiMaster-Tutorial with a different approach and topology
than this one, that might also suite your needs or might even be better suited
`Multi-Master Tutorial <http://docs.saltstack.com/en/latest/topics/tutorials/multimaster.html>`_
It is also desirable, to add some sort of authenticity-check to the very first
public key a minion receives from a master. Currently a minions takes the
first masters public key for granted.
The Goal
========
Setup the master to sign the public key it sends to the minions and enable the
minions to verify this signature for authenticity.
Prepping the master to sign its public key
==========================================
For signing to work, both master and minion must have the signing and/or
verification settings enabled. If the master signs the public key but the
minion does not verify it, the minion will complain and exit. The same
happens, when the master does not sign but the minion tries to verify.
The easiest way to have the master sign its public key is to set
.. code-block:: yaml
master_sign_pubkey: True
After restarting the salt-master service, the master will automatically
generate a new key-pair
.. code-block:: yaml
master_sign.pem
master_sign.pub
A custom name can be set for the signing key-pair by setting
.. code-block:: yaml
master_sign_key_name: <name_without_suffix>
The master will then generate that key-pair upon restart and use it for
creating the public keys signature attached to the auth-reply.
The computation is done for every auth-request of a minion. If many minions
auth very often, it is advised to use conf_master:`master_pubkey_signature`
and conf_master:`master_use_pubkey_signature` settings described below.
If multiple masters are in use and should sign their auth-replies, the signing
key-pair master_sign.* has to be copied to each master. Otherwise a minion
will fail to verify the masters public when connecting to a different master
than it did initially. That is because the public keys signature was created
with a different signing key-pair.
Prepping the minion to verify received public keys
==================================================
The minion must have the public key (and only that one!) available to be
able to verify a signature it receives. That public key (defaults to
master_sign.pub) must be copied from the master to the minions pki-directory.
.. code-block:: bash
/etc/salt/pki/minion/master_sign.pub
DO NOT COPY THE master_sign.pem FILE. IT MUST STAY ON THE MASTER AND
ONLY THERE!
When that is done, enable the signature checking in the minions configuration
.. code-block:: yaml
verify_master_pubkey_sign: True
and restart the minion. For the first try, the minion should be run in manual
debug mode.
.. code-block:: bash
$ salt-minion -l debug
Upon connecting to the master, the following lines should appear on the output:
.. code-block:: bash
[DEBUG ] Attempting to authenticate with the Salt Master at 172.16.0.10
[DEBUG ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG ] salt.crypt.verify_signature: Loading public key
[DEBUG ] salt.crypt.verify_signature: Verifying signature
[DEBUG ] Successfully verified signature of master public key with verification public key master_sign.pub
[INFO ] Received signed and verified master pubkey from master 172.16.0.10
[DEBUG ] Decrypting the current master AES key
If the signature verification fails, something went wrong and it will look
like this
.. code-block:: bash
[DEBUG ] Attempting to authenticate with the Salt Master at 172.16.0.10
[DEBUG ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG ] salt.crypt.verify_signature: Loading public key
[DEBUG ] salt.crypt.verify_signature: Verifying signature
[DEBUG ] Failed to verify signature of public key
[CRITICAL] The Salt Master server's public key did not authenticate!
In a case like this, it should be checked, that the verification pubkey
(master_sign.pub) on the minion is the same as the one on the master.
Once the verification is successful, the minion can be started in daemon mode
again.
For the paranoid among us, its also possible to verify the public whenever it
is received from the master. That is, for every single auth-attempt which can be
quite frequent. For example just the start of the minion will force the signature
to be checked 6 times for various things like auth, mine, highstate, etc.
If that is desired, enable the setting
.. code-block:: yaml
always_verify_signature: True
Multiple Masters For A Minion
=============================
Configuring multiple masters on a minion is done by specifying two settings:
- a list of masters addresses
- what type of master is defined
.. code-block:: yaml
master:
- 172.16.0.10
- 172.16.0.11
- 172.16.0.12
.. code-block:: yaml
master_type: failover
This tells the minion that all the master above are available for it to
connect to. When started with this configuration, it will try the master
in the order they are defined. To randomize that order, set
.. code-block:: yaml
master_shuffle: True
The master-list will then be shuffled before the first connection attempt.
The first master that accepts the minion, is used by the minion. If the
master does not yet know the minion, that counts as accepted and the minion
stays on that master.
For the minion to be able to detect if its still connected to its current
master enable the check for it
.. code-block:: yaml
master_alive_interval: <seconds>
If the loss of the connection is detected, the minion will temporarily
remove the failed master from the list and try one of the other masters
defined (again shuffled if that is enabled).
Testing the setup
=================
At least two running masters are needed to test the failover setup.
Both masters should be running and the minion should be running on the command
line in debug mode
.. code-block:: bash
$ salt-minion -l debug
The minion will connect to the first master from its master list
.. code-block:: bash
[DEBUG ] Attempting to authenticate with the Salt Master at 172.16.0.10
[DEBUG ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG ] salt.crypt.verify_signature: Loading public key
[DEBUG ] salt.crypt.verify_signature: Verifying signature
[DEBUG ] Successfully verified signature of master public key with verification public key master_sign.pub
[INFO ] Received signed and verified master pubkey from master 172.16.0.10
[DEBUG ] Decrypting the current master AES key
A test.ping on the master the minion is currently connected to should be run to
test connectivity.
If successful, that master should be turned off. A firewall-rule denying the
minions packets will also do the trick.
Depending on the configured conf_minion:`master_alive_interval`, the minion
will notice the loss of the connection and log it to its logfile.
.. code-block:: bash
[INFO ] Connection to master 172.16.0.10 lost
[INFO ] Trying to tune in to next master from master-list
The minion will then remove the current master from the list and try connecting
to the next master
.. code-block:: bash
[INFO ] Removing possibly failed master 172.16.0.10 from list of masters
[WARNING ] Master ip address changed from 172.16.0.10 to 172.16.0.11
[DEBUG ] Attempting to authenticate with the Salt Master at 172.16.0.11
If everything is configured correctly, the new masters public key will be
verified successfully
.. code-block:: bash
[DEBUG ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[DEBUG ] salt.crypt.verify_signature: Loading public key
[DEBUG ] salt.crypt.verify_signature: Verifying signature
[DEBUG ] Successfully verified signature of master public key with verification public key master_sign.pub
the authentication with the new master is successful
.. code-block:: bash
[INFO ] Received signed and verified master pubkey from master 172.16.0.11
[DEBUG ] Decrypting the current master AES key
[DEBUG ] Loaded minion key: /etc/salt/pki/minion/minion.pem
[INFO ] Authentication with master successful!
and the minion can be pinged again from its new master.
Performance Tuning
==================
With the setup described above, the master computes a signature for every
auth-request of a minion. With many minions and many auth-requests, that
can chew up quite a bit of CPU-Power.
To avoid that, the master can use a pre-created signature of its public-key.
The signature is saved as a base64 encoded string which the master reads
once when starting and attaches only that string to auth-replies.
Enabling this also gives paranoid users the possibility, to have the signing
key-pair on a different system than the actual salt-master and create the public
keys signature there. Probably on a system with more restrictive firewall rules,
without internet access, less users, etc.
That signature can be created with
.. code-block:: bash
$ salt-key --gen-signature
This will create a default signature file in the master pki-directory
.. code-block:: bash
/etc/salt/pki/master/master_pubkey_signature
It is a simple text-file with the binary-signature converted to base64.
If no signing-pair is present yet, this will auto-create the signing pair and
the signature file in one call
.. code-block:: bash
$ salt-key --gen-signature --auto-create
Telling the master to use the pre-created signature is done with
.. code-block:: yaml
master_use_pubkey_signature: True
That requires the file 'master_pubkey_signature' to be present in the masters
pki-directory with the correct signature.
If the signature file is named differently, its name can be set with
.. code-block:: yaml
master_pubkey_signature: <filename>
With many masters and many public-keys (default and signing), it is advised to
use the salt-masters hostname for the signature-files name. Signatures can be
easily confused because they do not provide any information about the key the
signature was created from.
Verifying that everything works is done the same way as above.
How the signing and verification works
======================================
The default key-pair of the salt-master is
.. code-block:: yaml
/etc/salt/pki/master/master.pem
/etc/salt/pki/master/master.pub
To be able to create a signature of a message (in this case a public-key),
another key-pair has to be added to the setup. Its default name is:
.. code-block:: yaml
master_sign.pem
master_sign.pub
The combination of the master.* and master_sign.* key-pairs give the
possibility of generating signatures. The signature of a given message
is unique and can be verified, if the public-key of the signing-key-pair
is available to the recipient (the minion).
The signature of the masters public-key in master.pub is computed with
.. code-block:: yaml
master_sign.pem
master.pub
M2Crypto.EVP.sign_update()
This results in a binary signature which is converted to base64 and attached
to the auth-reply send to the minion.
With the signing-pairs public-key available to the minion, the attached
signature can be verified with
.. code-block:: yaml
master_sign.pub
master.pub
M2Cryptos EVP.verify_update().
When running multiple masters, either the signing key-pair has to be present
on all of them, or the master_pubkey_signature has to be pre-computed for
each master individually (because they all have different public-keys).
DO NOT PUT THE SAME master.pub ON ALL MASTERS FOR EASE OF USE.