def get_docker_endpoint(self, owner, cloud_id, job_id=None): if job_id: event = get_story(owner.id, job_id) assert owner.id == event['owner_id'], 'Owner ID mismatch!' self.host, docker_port = config.DOCKER_IP, config.DOCKER_PORT return docker_port, event['logs'][0]['container_id'] cloud = Cloud.objects.get(owner=owner, id=cloud_id, deleted=None) self.host, docker_port = dnat(owner, self.host, cloud.port) return docker_port, cloud
def load(self, machines=None): self.hosts = {} self.keys = {} if not machines: clouds = Cloud.objects(owner=self.owner, deleted=None) machines = [(machine.cloud.id, machine.machine_id) for machine in Machine.objects(cloud__in=clouds)] for bid, mid in machines: try: name, ip_addr = self.find_machine_details(bid, mid) key_id, ssh_user, port = self.find_ssh_settings(bid, mid) except Exception as exc: print(exc) continue ip_addr, port = dnat(self.owner, ip_addr, port) if key_id not in self.keys: key = SSHKey.objects.get(owner=self.owner, name=key_id, deleted=None) self.keys[key_id] = key.private if isinstance(key, SignedSSHKey): # if signed ssh key, provide the key appending a -cert.pub # on the name since this is how ssh will include it as # an identify file self.keys['%s-cert.pub' % key_id] = key.certificate # pub key also needed for openssh 7.2 self.keys['%s.pub' % key_id] = key.public if name in self.hosts: num = 2 while ('%s-%d' % (name, num)) in self.hosts: num += 1 name = '%s-%d' % (name, num) self.hosts[name] = { 'ansible_ssh_host': ip_addr, 'ansible_ssh_port': port, 'ansible_ssh_user': ssh_user, 'ansible_ssh_private_key_file': 'id_rsa/%s' % key_id, }
def get_lxd_endpoint(self, owner, cloud_id, job_id=None): cloud = Cloud.objects.get(owner=owner, id=cloud_id, deleted=None) self.host, lxd_port = dnat(owner, self.host, cloud.port) return lxd_port, cloud
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))
def machine_rdp(request): """ Tags: machines --- Rdp file for windows machines. Generates and returns an rdp file for windows machines. READ permission required on cloud. READ permission required on machine. --- cloud: in: path required: true type: string machine: in: path required: true type: string rdp_port: default: 3389 in: query required: true type: integer host: in: query required: true type: string """ cloud_id = request.matchdict.get('cloud') auth_context = auth_context_from_request(request) if cloud_id: machine_id = request.matchdict['machine'] auth_context.check_perm("cloud", "read", cloud_id) try: machine = Machine.objects.get(cloud=cloud_id, machine_id=machine_id, state__ne='terminated') # used by logging_view_decorator request.environ['machine_uuid'] = machine.id except Machine.DoesNotExist: raise NotFoundError("Machine %s doesn't exist" % machine_id) else: machine_uuid = request.matchdict['machine_uuid'] try: machine = Machine.objects.get(id=machine_uuid, state__ne='terminated') # used by logging_view_decorator request.environ['machine_id'] = machine.machine_id request.environ['cloud_id'] = machine.cloud.id except Machine.DoesNotExist: raise NotFoundError("Machine %s doesn't exist" % machine_uuid) cloud_id = machine.cloud.id auth_context.check_perm("cloud", "read", cloud_id) auth_context.check_perm("machine", "read", machine.id) rdp_port = request.params.get('rdp_port', 3389) host = request.params.get('host') if not host: raise BadRequestError('No hostname specified') try: 1 < int(rdp_port) < 65535 except (ValueError, TypeError): rdp_port = 3389 host, rdp_port = dnat(auth_context.owner, host, rdp_port) rdp_content = 'full address:s:%s:%s\nprompt for credentials:i:1' % \ (host, rdp_port) return Response(content_type='application/octet-stream', content_disposition='attachment; filename="%s.rdp"' % host, charset='utf8', pragma='no-cache', body=rdp_content)