-
-
Save mgwilliams/22d88f51e4faf42452ac to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
GPG Runner | |
''' | |
# Import Python libs | |
import re | |
# Import third party libs | |
import gnupg | |
# Import Salt libs | |
import salt.client | |
uid_re = re.compile('.*\<(.*)\>') | |
class GPG(gnupg.GPG): | |
def sign_key(self, uid): | |
args = ['--batch', '--yes', '--sign-key', uid] | |
result = self.result_map['generate'](self) | |
f = gnupg._make_binary_stream('', self.encoding) | |
r = self._handle_io(args, f, result) | |
return r | |
def _gpg(): | |
return GPG(gnupghome=__opts__.get('gpg_dir', '/etc/salt/gpg/master/')) | |
def _public_key(): | |
''' | |
Export the master's public key | |
''' | |
return _gpg().export_keys('__salt-master__') or None | |
def generate_key(length=2048): | |
''' | |
Generate the master's key, if it does not exist. | |
Returns the public key or None if it already exists. | |
Returns False if key generation fails. | |
.. code-block:: bash | |
salt-run gpg.generate_key [length=key_length] | |
length | |
Length of the key. Default: 2048. | |
**Examples:** | |
Generate a key with the default length of 2048: | |
.. code-block:: bash | |
salt-run gpg.generate_key | |
Generate a longer key: | |
.. code-block:: bash | |
salt-run gpg.generate_key length=4096 | |
''' | |
if _public_key() is not None: | |
print 'Skipping key generation, already exists.' | |
return None | |
print 'Generating keys for master.' | |
gpg = _gpg() | |
r = gpg.gen_key(gpg.gen_key_input(name_real='__salt-master__', | |
name_email='__salt-master__', key_type='RSA', key_length=length)) | |
return gpg.export_keys(r.fingerprint) or False | |
def public_key(generate=False, length=2048): | |
''' | |
Return the master's public key. | |
.. code-block:: bash | |
salt-run gpg.public_key [[generate=(true|false)] length=key_length]] | |
generate | |
Generate the master's key if it does not already exist. | |
length | |
Length of the key, if it needs to be generated. | |
**Examples:** | |
Get the public key, generating it with the default length of 2048, if needed: | |
.. code-block:: bash | |
salt-run gpg.public_key generate=true | |
''' | |
pub = _public_key() | |
if pub is None and generate: | |
pub = generate_key(length) | |
if not pub: | |
print 'No master key found. Try gpg.generate_key.' | |
else: | |
print pub | |
def import_keys(data): | |
''' | |
Import the keys contained in data into the master's keychain. | |
.. code-block:: bash | |
salt-run gpg.import_keys \\ | |
"-----BEGIN PGP PUBLIC KEY BLOCK-----\\nVersion: (...) \\n-----END PGP PUBLIC KEY BLOCK-----\\n" | |
''' | |
data = data.replace("\\n", "\n") | |
r = _gpg().import_keys(data) | |
return r.count or False | |
def list_minions(): | |
''' | |
List the minions for which this master has keys. | |
.. code-block:: bash | |
salt-run gpg.list_minions | |
''' | |
uids = [k['uids'][0] for k in _gpg().list_keys() if '__salt-master__' not in k['uids'][0]] | |
minions = [uid_re.findall(k)[0] for k in uids] | |
print 'minions:' | |
for m in minions: | |
print ' {0}'.format(m) | |
def distribute_keys(target='* ', match='glob'): | |
''' | |
Distribute the master's public key to minions and import the minion's keys | |
into the master's keychain. | |
.. code-block:: bash | |
salt-run gpg.distribute_keys [target=target_expr [match=expr_form]] | |
target | |
A target expression. Default: '*'. | |
match | |
The expression form of 'target': | |
glob - Bash glob completion - Default | |
pcre - Perl style regular expression | |
list - Python list of hosts | |
grain - Match based on a grain comparison | |
grain_pcre - Grain comparison with a regex | |
pillar - Pillar data comparison | |
nodegroup - Match on nodegroup | |
range - Use a Range server for matching | |
compound - Pass a compound match string | |
**Example:** | |
Distribute keys between the master and the 'webserver' nodegroup: | |
.. code-block:: bash | |
salt-run gpg.distribute_keys target=webserver match-nodegroup | |
''' | |
master_pub = _public_key() | |
client = salt.client.LocalClient(__opts__['conf_file']) | |
gpg = _gpg() | |
print 'Gathering minions\' public keys (this could take awhile).' | |
minion_keys = client.cmd(target, 'gpg.public_key', kwarg={'generate': True}, timeout=1200, expr_form=match) | |
print 'Importing minion keys:' | |
for minion, key in minion_keys.items(): | |
if import_keys(key): | |
gpg.sign_key(minion) | |
print ' {0}: ok'.format(minion) | |
else: | |
print ' {0}: fail'.format(minion) | |
results = client.cmd(target, 'gpg.import_keys', [master_pub], timeout=90, expr_form=match) | |
print 'Distributing master key:' | |
for minion, count in results.items(): | |
if count: | |
print ' {0}: ok'.format(minion) | |
else: | |
print ' {0}: fail'.format(minion) | |
def encrypt(grain_id, data, target='*', match='glob'): | |
gpg = _gpg() | |
client = salt.client.LocalClient(__opts__['conf_file']) | |
minions = client.cmd(target, 'test.ping', timeout=30, expr_form=match).keys() | |
for minion in minions: | |
r = gpg.encrypt(data, minion) | |
print r.ok | |
print r.stderr | |
r = client.cmd(minion, 'grains.setval', [grain_id, r.data], timeout=30) | |
print r |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment