def __init__(self, *args, **kwargs): """Initialize connection to database :param host: string (ex: vulture-node1:9091) or tuple (ex: ('vulture-node1',9091)) :return: """ super(DataBaseClient, self).__init__(*args, **kwargs) if kwargs.get('host') is not None: host = kwargs.get('host') if isinstance(host, tuple): host = '{}:{}'.format(host[0], host[1]) self.connection_uri = 'mongodb://{}'.format(host) #a.connection['local']['system.replset'].find_one() else: self.connection_uri = self.get_mongodb_connection_uri() try: c = MongoClient(host=self.connection_uri, ssl=True, ssl_certfile=ssl_utils.get_pem_path(), ssl_ca_certs=ssl_utils.get_ca_cert_path(), read_preference=ReadPreference.SECONDARY_PREFERRED) self.hosts = list() self.primary_host = None self.connection = c except Exception as e: raise Exception("Database connection failed")
def __init__(self, *args, **kwargs): """Initialize connection to database :return: """ super(ReplicaSetClient, self).__init__(*args, **kwargs) self.connection_uri = self.get_mongodb_connection_uri() self.ipv6 = False if kwargs: self.ipv6 = kwargs.get('ipv6', False) if not self.ipv6: try: from gui.models.system_settings import Cluster node = Cluster.objects.get().get_current_node() manag_listener = node.get_management_listener() try: ipaddress.IPv4Address(manag_listener.ip) self.ipv6 = False except: try: ipaddress.IPv6Address(manag_listener.ip) self.ipv6 = True except: self.ipv6 = False except: self.ipv6 = False try: c = connect('vulture', host=self.connection_uri, replicaSet='Vulture', ssl=True, ssl_certfile=ssl_utils.get_pem_path(), ssl_ca_certs=ssl_utils.get_ca_cert_path(), read_preference=ReadPreference.SECONDARY_PREFERRED) self.logger.debug("ReplicaSet hosts are : {}".format(c.hosts)) self.hosts = c.nodes self.logger.debug("Primary host is : {}".format(c.primary)) self.primary_host = c.primary self.connection = c except Exception as e: if 'Port number must be an integer' in str(e): self.logger.warning("No configuration available") pass # we need to pass, if didn't we can't create conf elif 'is not a member of replica set' in str(e): self.logger.error( "Oups, this node is not a member of replicaset") self.logger.error( "Need to do rs.add (\"<this_member>:9091\") on the PRIMARY member" ) pass else: self.logger.error("Unable to connect to the database : " + str(e)) raise ReplicaConnectionFailure("Database connection failed, " "error: {}".format(e))
def create_certificate(self): """ Create Node certificate from Cluster CA authority """ if self.certificate is None: # Get PKI next serial number cluster = Cluster.objects.get() serial = cluster.ca_serial serial += 1 crt, key = ssl_utils.mk_signed_cert(ssl_utils.get_ca_cert_path(), ssl_utils.get_ca_key_path(), self.name, 'FR', '', '', '', '', serial) # TODO: Error handling # Save serial number cluster.ca_serial = serial cluster.save() # Store the certificate certificate = SSLCertificate() certificate.name = str(crt.get_subject()) certificate.cn = str(self.name) certificate.o = 'FR' certificate.cert = crt.as_pem().decode('utf8') certificate.key = key.as_pem(cipher=None).decode('utf8') certificate.status = 'V' certificate.issuer = str(crt.get_issuer()) certificate.validfrom = str(crt.get_not_before().get_datetime()) certificate.validtill = str(crt.get_not_after().get_datetime()) certificate.serial = str(serial) certificate.is_ca = False internal = cluster.ca_certificate certificate.chain = str(internal.cert) certificate.save() self.certificate = certificate self.save()
def write_MongoCert (self): """Save the certificate/key and associated ca on disk for use in mongoDB connection MongoDB requires that certificate and key are in the same file :return: certificate_path, chain_path """ file_tmp = None try: file_tmp = open("/home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".pem", "r") except Exception as e: pass # If the file does not exists yet, create it if file_tmp is None: file = open("/home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".pem", "w") file.write(self.cert) if self.key: file.write("\n") #FIXME: Encrypt Key file.write(self.key) file.close() file = open("/home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".key", "w") if self.key: #FIXME: Encrypt Key file.write(self.key) file.close() file = open("/home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".crt", "w") file.write(self.cert) file.close() # Set permissions to this file os.chmod("/home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".pem", 660) os.chmod("/home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".key", 660) os.chmod("/home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".crt", 660) os.system("/usr/bin/chgrp vlt-web /home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".pem") os.system("/usr/bin/chgrp vlt-web /home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".key") os.system("/usr/bin/chgrp vlt-web /home/vlt-sys/Engine/conf/cert-" + str(self.id) + ".crt") else: file_tmp.close() # If the file already exists, nothing to do file_tmp = None try: file_tmp = open("/home/vlt-sys/Engine/conf/ca-" + str(self.id) + ".pem", "r") except Exception as e: pass if file_tmp is None: #Always add the local CA Cert in chain file ca_path = get_ca_cert_path() file = open(ca_path, "r") ca = file.read() file.close() file = open("/home/vlt-sys/Engine/conf/ca-" + str(self.id) + ".pem", "w") file.write(ca) file.write("\n") file.write(self.chain) file.close() # Set permissions to this file try: os.chmod("/home/vlt-sys/Engine/conf/ca-" + str(self.id) + ".pem", 660) os.system("/usr/bin/chgrp vlt-web /home/vlt-sys/Engine/conf/ca-" + str(self.id) + ".pem") except Exception as e: pass else: file_tmp.close() return "/home/vlt-sys/Engine/conf/cert-"+str(self.id)+".pem", "/home/vlt-sys/Engine/conf/ca-" + str(self.id) + ".pem",
sys.path.append('/home/vlt-gui/vulture') os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'vulture.settings') import django django.setup() from gui.models.system_settings import Cluster from gui.models.modssl_settings import ModSSL from vulture_toolkit.system import ssl_utils from M2Crypto import X509 if __name__ == '__main__': ca_cert = X509.load_cert(ssl_utils.get_ca_cert_path()) C = "" ST = "" L = "" O = "" OU = "" for i in ca_cert.get_subject().as_text().split(','): i = i.strip() print(i) if i[:2] == "C=": C = i[2:] elif i[:3] == "ST=": ST = i[3:] elif i[:2] == "L=": L = i[2:]
def execute_command(self, cmd, host=None, database="test"): """Connect to a mongodb instance using mongo client,to execute a command :param cmd: command to execute :param host: Target host, if not defined primary host is used :return: """ if host is not None: hostname = host[0] port = str(host[1]) else: hostname = self.primary_host[0] port = str(self.primary_host[1]) """ Send mongo command """ if not self.ipv6: params_cmd = [ "/usr/local/bin/mongo", "--quiet", "--ssl", "--sslPEMKeyFile", ssl_utils.get_pem_path(), "--sslCAFile", ssl_utils.get_ca_cert_path(), "{}:{}/{}".format(hostname, port, database), "--eval", cmd ] else: params_cmd = [ "/usr/local/bin/mongo", "--quiet", "--ipv6", "--ssl", "--sslPEMKeyFile", ssl_utils.get_pem_path(), "--sslCAFile", ssl_utils.get_ca_cert_path(), "{}:{}/{}".format(hostname, port, database), "--eval", cmd ] proc = subprocess.Popen(params_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) res = proc.communicate() success = res[0] error = res[1] if success: """Extracting response from entire string """ raw_response = success.replace(b"\t", b"").replace(b"\n", b"").replace( b"\r", b"") try: response = json.loads(raw_response) except ValueError: pattern = re.compile( b".*reconnected to server after rs command " b"\(which is normal\).*", re.S) """We can encounter an error when executing command, it's normal we just need to retry command""" if pattern.match(raw_response): response, error = self.execute_command( cmd, host) #TODO Care to infinite loops return response, error else: response = None self.logger.error( "Unexpected error : {}".format(raw_response)) self.logger.error("Command was: {}".format(cmd)) else: self.logger.error(error) return response, error
def create(request): """ View dedicated to certificate creation :param request: Django request object """ form = CertForm(request.POST or None) # Saving information into database and redirect to certificate list if request.method == 'POST' and form.is_valid(): cert = form.save(commit=False) # We want to create a Let's Encrypt certificate... if request.POST.get("cert-type") == "acme-client": # Call acme-client to generate the Let's Encrypt challenge proc = subprocess.Popen( [ '/usr/local/bin/sudo', '-u', 'vlt-sys', '/usr/local/bin/sudo', '/usr/local/bin/sudo', '/usr/local/sbin/acme.sh', '--issue', '-d', cert.cn, '--webroot', '/home/vlt-sys/Engine/conf', '--cert-home', '/usr/local/etc/ssl/acme' ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, env={ 'PATH': "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" }) success, error = proc.communicate() if error: logger.error("Let's encrypt Error: {}".format(error)) return render_to_response( 'cert_create.html', { 'form': form, 'error': error }, context_instance=RequestContext(request)) else: logger.info( "Let's encrypt certificate was issued for '{}".format( cert.cn)) """ At this point, the certificate is ondisk: We need to store it into MongoDB """ proc = subprocess.Popen([ '/usr/local/bin/sudo', '-u', 'vlt-sys', '/usr/local/bin/sudo', '/usr/local/bin/sudo', '/bin/cat', '/usr/local/etc/ssl/acme/{}/{}.key'.format( cert.cn, cert.cn) ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) private_key, error = proc.communicate() if error: logger.error( "Let's encrypt Error: Unable to read private key") return render_to_response( 'cert_create.html', { 'form': form, 'error': 'Unable to read private key' }, context_instance=RequestContext(request)) proc = subprocess.Popen([ '/usr/local/bin/sudo', '-u', 'vlt-sys', '/usr/local/bin/sudo', '/usr/local/bin/sudo', '/bin/cat', '/usr/local/etc/ssl/acme/{}/ca.cer'.format(cert.cn) ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) ca, error = proc.communicate() if error: logger.error("Let's encrypt Error: Unable to read CA") return render_to_response( 'cert_create.html', { 'form': form, 'error': 'Unable to read CA' }, context_instance=RequestContext(request)) proc = subprocess.Popen([ '/usr/local/bin/sudo', '-u', 'vlt-sys', '/usr/local/bin/sudo', '/usr/local/bin/sudo', '/bin/cat', '/usr/local/etc/ssl/acme/{}/{}.cer'.format( cert.cn, cert.cn) ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) certificate, error = proc.communicate() if error: logger.error( "Let's encrypt Error: Unable to read certificate") return render_to_response( 'cert_create.html', { 'form': form, 'error': 'Unable to read certificate' }, context_instance=RequestContext(request)) # Store the certificate x509Cert = X509.load_cert_string(certificate) cert.cert = str(certificate.decode('utf8')) cert.key = str(private_key.decode('utf8')) cert.name = str(x509Cert.get_subject()) cert.status = 'V' cert.issuer = str("LET'S ENCRYPT") cert.validfrom = str(x509Cert.get_not_before().get_datetime()) cert.validtill = str(x509Cert.get_not_after().get_datetime()) if x509Cert.check_ca(): cert.is_ca = True else: cert.is_ca = False cert.serial = str(x509Cert.get_serial_number()) cert.chain = str(ca.decode('utf8')) cert.save() return HttpResponseRedirect('/system/cert/') # Get PKI next serial number cluster = Cluster.objects.get() serial = cluster.ca_serial serial = serial + 1 # Create a certificate ca_cert_file = get_ca_cert_path() ca_key_file = get_ca_key_path() crt, pk2 = mk_signed_cert(ca_cert_file, ca_key_file, cert.cn, cert.c, cert.st, cert.l, cert.o, cert.ou, serial) # Save serial number cluster.ca_serial = serial cluster.save() internal = cluster.ca_certificate # Store the certificate cert.cert = crt.as_pem().decode('utf8') cert.key = pk2.as_pem(cipher=None).decode('utf8') cert.name = str(crt.get_subject()) cert.status = 'V' cert.issuer = str(internal.issuer) cert.validfrom = str(crt.get_not_before().get_datetime()) cert.validtill = str(crt.get_not_after().get_datetime()) cert.is_ca = False cert.serial = str(serial) cert.chain = str(internal.cert) cert.save() return HttpResponseRedirect('/system/cert/') return render_to_response('cert_create.html', { 'form': form, }, context_instance=RequestContext(request))