mirror of
https://github.com/xcat2/confluent.git
synced 2025-04-04 17:48:35 +00:00
Implement SSH host key management
Like self-signed TLS certificates, SSH host keys warrant a similar security policy. This implementations follows the lead of the TLS management and uses the same policy name and interpretation, just storing the value in 'pubkeys.ssh' for the node rather than an extensible set of entry points (for now).
This commit is contained in:
parent
a2445e7f65
commit
a574c69535
@ -278,4 +278,8 @@ node = {
|
||||
'description': ('Fingerprint of the TLS certificate recognized as'
|
||||
'belonging to the hardware manager of the server'),
|
||||
},
|
||||
'pubkeys.ssh': {
|
||||
'description': ('Fingerprint of the SSH key of the OS running on the '
|
||||
'system.'),
|
||||
},
|
||||
}
|
||||
|
@ -14,17 +14,48 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
__author__ = 'jjohnson2'
|
||||
|
||||
# This plugin provides an ssh implementation comforming to the 'console'
|
||||
# specification. consoleserver or shellserver would be equally likely
|
||||
# to use this.
|
||||
|
||||
import confluent.exceptions as cexc
|
||||
import confluent.interface.console as conapi
|
||||
import confluent.log as log
|
||||
import eventlet
|
||||
import hashlib
|
||||
paramiko = eventlet.import_patched('paramiko')
|
||||
|
||||
|
||||
class HostKeyHandler(paramiko.client.MissingHostKeyPolicy):
|
||||
|
||||
def __init__(self, configmanager, node):
|
||||
self.cfm = configmanager
|
||||
self.node = node
|
||||
|
||||
def missing_host_key(self, client, hostname, key):
|
||||
fingerprint = 'sha512$' + hashlib.sha512(key).hexdigest()
|
||||
cfg = self.cfm.get_node_attributes(
|
||||
self.node, ('pubkeys.ssh', 'pubkeys.addpolicy'))
|
||||
if 'pubkeys.ssh' not in cfg[self.node]:
|
||||
if ('pubkeys.addpolicy' in cfg[self.node] and
|
||||
cfg[self.node]['pubkeys.addpolicy'] and
|
||||
cfg[self.node]['pubkeys.addpolicy']['value'] == 'manual'):
|
||||
raise cexc.PubkeyInvalid('New ssh key detected',
|
||||
key, fingerprint, 'pubkeys.ssh')
|
||||
auditlog = log.Logger('audit')
|
||||
auditlog.log({'node': self.node, 'event': 'sshautoadd',
|
||||
'fingerprint': fingerprint})
|
||||
self.cfm.set_node_attributes(
|
||||
{self.node: {'pubkeys.ssh': fingerprint}})
|
||||
return True
|
||||
elif cfg[self.node]['pubkeys.ssh']['value'] == fingerprint:
|
||||
return True
|
||||
raise cexc.PubKeyInvalid(
|
||||
'Mismatched SSH host key detected', key, fingerprint, 'pubkeys.ssh'
|
||||
)
|
||||
|
||||
|
||||
class SshShell(conapi.Console):
|
||||
|
||||
def __init__(self, node, config, username='', password=''):
|
||||
@ -33,7 +64,7 @@ class SshShell(conapi.Console):
|
||||
self.nodeconfig = config
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.inputmode = 0 # 0 = username, 1 = password...
|
||||
self.inputmode = 0 # 0 = username, 1 = password...
|
||||
|
||||
def recvdata(self):
|
||||
while self.connected:
|
||||
@ -45,7 +76,7 @@ class SshShell(conapi.Console):
|
||||
|
||||
def connect(self, callback):
|
||||
# for now, we just use the nodename as the presumptive ssh destination
|
||||
#TODO(jjohnson2): use a 'nodeipget' utility function for architectures
|
||||
# TODO(jjohnson2): use a 'nodeipget' utility function for architectures
|
||||
# that would rather not use the nodename as anything but an opaque
|
||||
# identifier
|
||||
self.datacallback = callback
|
||||
|
Loading…
x
Reference in New Issue
Block a user