blob: 1645a668eb8b9185d7f22bfb9991353f431d672a [file] [log] [blame]
Adam Tenglerb892d852017-08-24 15:07:08 +00001from __future__ import absolute_import
2
3# Import python libs
4import logging
5import os
6
7try:
8 import paramiko
9 HAS_PARAMIKO = True
10except:
11 HAS_PARAMIKO = False
12
13# Import Salt libs
14import salt.config
15import salt.wheel
16
17LOG = logging.getLogger(__name__)
18
19
20def __virtual__():
21 '''
22 Only load if paramiko library exist.
23 '''
24 if not HAS_PARAMIKO:
25 return (
26 False,
27 'Can not load module saltkey: paramiko library not found')
28 return True
29
30
31def key_create(id_, host, force=False):
32 '''
33 Generates minion keypair, accepts it on master and injects it to minion via SSH.
34
Adam Tengler62188962017-09-04 13:34:44 +000035 :param id_: expected minion ID of target node
36 :param host: IP address or resolvable hostname/FQDN of target node
37
Adam Tenglerb892d852017-08-24 15:07:08 +000038 CLI Examples:
39
40 .. code-block:: bash
41
42 salt-call saltkey.key_create <MINION_ID> <MINION_IP_ADDRESS> force=False
43 '''
44 ret = {
45 'retcode': 0,
46 'msg': 'Salt Key for minion %s is already accepted' % id_,
47 }
48
49 opts = salt.config.master_config('/etc/salt/master')
50 wheel = salt.wheel.WheelClient(opts)
51 keys = wheel.cmd('key.gen_accept', arg=[id_], kwarg={'force': force})
52 pub_key = keys.get('pub', None)
53 priv_key = keys.get('priv', None)
54
55 if pub_key and priv_key:
56 ssh = paramiko.SSHClient()
57 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
58 # Establish SSH connection to minion
59 try:
60 ssh.connect(host)
61 except paramiko.ssh_exception.AuthenticationException:
62 msg = ('Could not establish SSH connection to minion "%s" on address %s, please ensure '
63 'that current user\'s SSH key is present in minions authorized_keys.') % (id_, host)
64 LOG.error(msg)
65 ret['retcode'] = 1
66 ret['msg'] = msg
67 wheel.cmd_async({'fun': 'key.delete', 'match': id_})
68 return ret
69 except Exception as e:
70 msg = ('Unknown error occured while establishing SSH connection '
71 'to minion "%s" on address %s: %s') % (id_, host, repr(e))
72 LOG.error(msg)
73 ret['retcode'] = 1
74 ret['msg'] = msg
75 wheel.cmd_async({'fun': 'key.delete', 'match': id_})
76 return ret
77 # Setup the keys on minion side the ugly way, nice one didn't work
78 key_path = '/etc/salt/pki/minion'
79 command = ('echo "%(pub_key)s" > %(pub_path)s && chmod 644 %(pub_path)s && '
80 'echo "%(priv_key)s" > %(priv_path)s && chmod 400 %(priv_path)s && '
81 'salt-call --local service.restart salt-minion') % {
82 'pub_path': os.path.join(key_path, 'minion.pub'),
83 'pub_key': pub_key,
84 'priv_path': os.path.join(key_path, 'minion.pem'),
85 'priv_key': priv_key
86 }
87
88 ssh_chan = ssh.get_transport().open_session()
89 ssh_chan.exec_command(command)
90 # Wait for command return
91 while True:
92 if ssh_chan.exit_status_ready():
93 exit_status = ssh_chan.recv_exit_status()
94 stderr = ssh_chan.recv_stderr(1000)
95 stdout = ssh_chan.recv(1000)
96 break
97 ssh.close()
98 # Evaluate SSH command exit status
99 if exit_status != 0:
100 msg = 'Keypair injection to Salt minion failed on target with following error: %s' % stderr
101 LOG.error(msg)
102 ret['retcode'] = exit_status
103 ret['msg'] = msg
104 return ret
105
106 ret['msg'] = 'Salt Key successfully created'
107
108 return ret
109