mirror of
https://github.com/xcat2/confluent.git
synced 2026-01-12 19:12:37 +00:00
@@ -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.'),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -77,10 +77,12 @@ class PubkeyInvalid(ConfluentException):
|
||||
apierrorcode = 502
|
||||
apierrorstr = '502 - Invalid certificate or key on target'
|
||||
|
||||
def __init__(self, text, certificate, fingerprint, attribname):
|
||||
def __init__(self, text, certificate, fingerprint, attribname, event):
|
||||
super(PubkeyInvalid, self).__init__(self, text)
|
||||
self.fingerprint = fingerprint
|
||||
bodydata = {'fingerprint': fingerprint,
|
||||
bodydata = {'message': text,
|
||||
'event': event,
|
||||
'fingerprint': fingerprint,
|
||||
'fingerprintfield': attribname,
|
||||
'certificate': base64.b64encode(certificate)}
|
||||
self.errorbody = json.dumps(bodydata)
|
||||
|
||||
@@ -14,17 +14,50 @@
|
||||
# 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.asbytes()).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.asbytes(), fingerprint,
|
||||
'pubkeys.ssh', 'newkey')
|
||||
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.asbytes(), fingerprint,
|
||||
'pubkeys.ssh', 'mismatch'
|
||||
)
|
||||
|
||||
|
||||
class SshShell(conapi.Console):
|
||||
|
||||
def __init__(self, node, config, username='', password=''):
|
||||
@@ -33,7 +66,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 +78,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
|
||||
@@ -58,7 +91,8 @@ class SshShell(conapi.Console):
|
||||
|
||||
def logon(self):
|
||||
self.ssh = paramiko.SSHClient()
|
||||
self.ssh.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
|
||||
self.ssh.set_missing_host_key_policy(
|
||||
HostKeyHandler(self.nodeconfig, self.node))
|
||||
try:
|
||||
self.ssh.connect(self.node, username=self.username,
|
||||
password=self.password, allow_agent=False,
|
||||
|
||||
@@ -82,7 +82,7 @@ class TLSCertVerifier(object):
|
||||
# manually
|
||||
raise cexc.PubkeyInvalid('New certificate detected',
|
||||
certificate, fingerprint,
|
||||
self.fieldname)
|
||||
self.fieldname, 'newkey')
|
||||
# since the policy is not manual, go ahead and add new key
|
||||
# after logging to audit log
|
||||
auditlog = log.Logger('audit')
|
||||
@@ -93,6 +93,6 @@ class TLSCertVerifier(object):
|
||||
return True
|
||||
elif storedprint[self.node][self.fieldname]['value'] == fingerprint:
|
||||
return True
|
||||
raise cexc.PubKeyInvalid(
|
||||
raise cexc.PubkeyInvalid(
|
||||
'Mismatched certificate detected', certificate, fingerprint,
|
||||
self.fieldname)
|
||||
self.fieldname, 'mismatch')
|
||||
|
||||
Reference in New Issue
Block a user