def connect(self, username, key=None, password=None, cert_file=None, port=22): """Initialize an SSH connection. Tries to connect and configure self. If only password is provided, it will be used for authentication. If key is provided, it is treated as and OpenSSH private RSA key and used for authentication. If both key and password are provided, password is used as a passphrase to unlock the private key. Raises MachineUnauthorizedError if it fails to connect. """ if not key and not password: raise RequiredParameterMissingError("neither key nor password " "provided.") if key: private = key.private if isinstance(key, SignedSSHKey) and cert_file: # signed ssh key, use RSACert rsa_key = paramiko.RSACert(privkey_file_obj=StringIO(private), cert_file_obj=StringIO(cert_file)) else: rsa_key = paramiko.RSAKey.from_private_key(StringIO(private)) else: rsa_key = None attempts = 3 while attempts: attempts -= 1 try: self.ssh.connect( self.host, port=port, username=username, password=password, pkey=rsa_key, allow_agent=False, look_for_keys=False, timeout=10 ) break except paramiko.AuthenticationException as exc: log.error("ssh exception %r", exc) raise MachineUnauthorizedError("Couldn't connect to " "%s@%s:%s. %s" % (username, self.host, port, exc)) except socket.error as exc: log.error("Got ssh error: %r", exc) if not attempts: raise ServiceUnavailableError("SSH timed-out repeatedly.") except Exception as exc: log.error("ssh exception %r", exc) # don't fail if SSHException or other paramiko exception, # eg related to network, but keep until all attempts are made if not attempts: raise ServiceUnavailableError(repr(exc))
def connect_control(self): """ Connect to the control websocket for LXD """ try: self.cws.connect(self.curi) except websocket.WebSocketException: raise MachineUnauthorizedError()
def connect(self): try: if self.header is not None: self.ws.connect(self.uri, header=self.header) else: self.ws.connect(self.uri) except websocket.WebSocketException as exc: msg = "Make sure you are authorized to access this machine" raise MachineUnauthorizedError(msg)
def deploy(self, machine, username=None, port=22): """""" # try to actually deploy log.info("Deploying key to host %s", machine.hostname) filename = '~/.ssh/authorized_keys' grep_output = '`grep \'%s\' %s`' % (self.key.public, filename) new_line_check_cmd = ( 'if [ "$(tail -c1 %(file)s; echo x)" != "\\nx" ];' ' then echo "" >> %(file)s; fi' % { 'file': filename }) append_cmd = ('if [ -z "%s" ]; then echo "%s" >> %s; fi' % (grep_output, self.key.public, filename)) command = new_line_check_cmd + " ; " + append_cmd log.debug("command = %s", command) # FIXME from mist.api.methods import ssh_command deploy_error = False try: # Deploy key. ssh_command(self.key.owner, machine.cloud.id, machine.machine_id, machine.hostname, command, username=username, port=port) log.info("Key associated and deployed successfully.") except MachineUnauthorizedError: # Couldn't deploy key, maybe key was already deployed? deploy_error = True try: ssh_command(self.key.owner, machine.cloud.id, machine.machine_id, machine.hostname, 'uptime', key_id=self.key.id, username=username, port=port) except MachineUnauthorizedError: if deploy_error: super(SSHKeyController, self).disassociate(machine) raise MachineUnauthorizedError("Couldn't connect to " "deploy new SSH key.") raise
def connect(self): try: self.ws.connect(self.uri) except websocket.WebSocketException: raise MachineUnauthorizedError()
def autoconfigure(self, owner, cloud_id, machine_id, key_id=None, username=None, password=None, port=22): """Autoconfigure SSH client. This will do its best effort to find a suitable key and username and will try to connect. If it fails it raises MachineUnauthorizedError, otherwise it initializes self and returns a (key_id, ssh_user) tuple. If connection succeeds, it updates the association information in the key with the current timestamp and the username used to connect. """ log.info("autoconfiguring Shell for machine %s:%s", cloud_id, machine_id) cloud = Cloud.objects.get(owner=owner, id=cloud_id, deleted=None) machine = Machine.objects.get(cloud=cloud, id=machine_id) key_associations = KeyMachineAssociation.objects(machine=machine) log.info('Got cloud & machine: %d key associations' % len(key_associations)) if key_id: keys = [Key.objects.get(owner=owner, id=key_id, deleted=None)] log.info('Got key') else: keys = [ association.key for association in key_associations if isinstance(association.key, Key) ] log.info('Got keys %d' % len(keys)) if username: users = [username] else: users = list( set([ association.ssh_user for association in key_associations if association.ssh_user ])) log.info('Got users:{}'.format(users)) if not users: for name in [ 'root', 'ubuntu', 'ec2-user', 'user', 'azureuser', 'core', 'centos', 'cloud-user', 'fedora' ]: if name not in users: users.append(name) if port != 22: ports = [port] else: ports = list( set([key_assoc.port for key_assoc in key_associations])) if 22 not in ports: ports.append(22) log.info('Got ports:{}'.format(ports)) # store the original destination IP to prevent rewriting it when NATing ssh_host = self.host for key in keys: for ssh_user in users: for port in ports: try: # store the original ssh port in case of NAT # by the OpenVPN server ssh_port = port self.host, port = dnat(owner, ssh_host, port) log.info("ssh -i %s %s@%s:%s", key.name, ssh_user, self.host, port) cert_file = '' if isinstance(key, SignedSSHKey): cert_file = key.certificate self.connect(username=ssh_user, key=key, password=password, cert_file=cert_file, port=port) except MachineUnauthorizedError: continue retval, resp = self.command('uptime') new_ssh_user = None if 'Please login as the user ' in resp: new_ssh_user = resp.split()[5].strip('"') elif 'Please login as the' in resp: # for EC2 Amazon Linux machines, usually with ec2-user new_ssh_user = resp.split()[4].strip('"') if new_ssh_user: log.info("retrying as %s", new_ssh_user) try: self.disconnect() cert_file = '' if isinstance(key, SignedSSHKey): cert_file = key.certificate self.connect(username=new_ssh_user, key=key, password=password, cert_file=cert_file, port=port) ssh_user = new_ssh_user except MachineUnauthorizedError: continue # we managed to connect successfully, return # but first update key trigger_session_update_flag = False for key_assoc in KeyMachineAssociation.objects( machine=machine): if key_assoc.key == key: if key_assoc.ssh_user != ssh_user: key_assoc.ssh_user = ssh_user trigger_session_update_flag = True break else: trigger_session_update_flag = True # in case of a private host do NOT update the key # associations with the port allocated by the OpenVPN # server, instead use the original ssh_port key_assoc = KeyMachineAssociation( key=key, machine=machine, ssh_user=ssh_user, port=ssh_port, sudo=self.check_sudo()) key_assoc.save() machine.save() if trigger_session_update_flag: trigger_session_update(owner.id, ['keys']) return key.name, ssh_user raise MachineUnauthorizedError("%s:%s" % (cloud_id, machine_id))