def check_ssl_cert(domain, env): # Check that SSL certificate is signed. # Skip the check if the A record is not pointed here. if query_dns(domain, "A", None) not in (env['PUBLIC_IP'], None): return # Where is the SSL stored? ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env) if not os.path.exists(ssl_certificate): env['out'].print_error( "The SSL certificate file for this domain is missing.") return # Check that the certificate is good. cert_status = check_certificate(domain, ssl_certificate, ssl_key) if cert_status == "SELF-SIGNED": fingerprint = shell('check_output', [ "openssl", "x509", "-in", ssl_certificate, "-noout", "-fingerprint" ]) fingerprint = re.sub(".*Fingerprint=", "", fingerprint).strip() if domain == env['PRIMARY_HOSTNAME']: env['out'].print_error( """The SSL certificate for this domain is currently self-signed. You will get a security warning when you check or send email and when visiting this domain in a web browser (for webmail or static site hosting). You may choose to confirm the security exception, but check that the certificate fingerprint matches the following:""") env['out'].print_line("") env['out'].print_line(" " + fingerprint, monospace=True) else: env['out'].print_error( """The SSL certificate for this domain is currently self-signed. Visitors to a website on this domain will get a security warning. If you are not serving a website on this domain, then it is safe to leave the self-signed certificate in place.""") env['out'].print_line("") env['out'].print_line( """You can purchase a signed certificate from many places. You will need to provide this Certificate Signing Request (CSR) to whoever you purchase the SSL certificate from:""") env['out'].print_line("") env['out'].print_line(open(ssl_csr_path).read().strip(), monospace=True) env['out'].print_line("") env['out'].print_line( """When you purchase an SSL certificate you will receive a certificate in PEM format and possibly a file containing intermediate certificates in PEM format. If you receive intermediate certificates, use a text editor and paste your certificate on top and then the intermediate certificates below it. Save the file and place it onto this machine at %s. Then run "service nginx restart".""" % ssl_certificate) elif cert_status == "OK": env['out'].print_ok("SSL certificate is signed & valid.") else: env['out'].print_error("The SSL certificate has a problem:") env['out'].print_line("") env['out'].print_line(cert_status) env['out'].print_line("")
def check_ssl_cert(domain, env): # Check that SSL certificate is signed. # Skip the check if the A record is not pointed here. if query_dns(domain, "A") != env['PUBLIC_IP']: return # Where is the SSL stored? ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env) if not os.path.exists(ssl_certificate): print_error("The SSL certificate file for this domain is missing.") return # Check that the certificate is good. cert_status = check_certificate(domain, ssl_certificate, ssl_key) if cert_status == "SELF-SIGNED": fingerprint = shell('check_output', [ "openssl", "x509", "-in", ssl_certificate, "-noout", "-fingerprint" ]) fingerprint = re.sub(".*Fingerprint=", "", fingerprint).strip() if domain == env['PRIMARY_HOSTNAME']: print_error("""The SSL certificate for this domain is currently self-signed. You will get a security warning when you check or send email and when visiting this domain in a web browser (for webmail or static site hosting). You may choose to confirm the security exception, but check that the certificate fingerprint matches the following:""") print() print(" " + fingerprint) else: print_error("""The SSL certificate for this domain is currently self-signed. Visitors to a website on this domain will get a security warning. If you are not serving a website on this domain, then it is safe to leave the self-signed certificate in place.""") print() print_block("""You can purchase a signed certificate from many places. You will need to provide this Certificate Signing Request (CSR) to whoever you purchase the SSL certificate from:""") print() print(open(ssl_csr_path).read().strip()) print() print_block("""When you purchase an SSL certificate you will receive a certificate in PEM format and possibly a file containing intermediate certificates in PEM format. If you receive intermediate certificates, use a text editor and paste your certificate on top and then the intermediate certificates below it. Save the file and place it onto this machine at %s. Then run "service nginx restart".""" % ssl_certificate) elif cert_status == "OK": print_ok("SSL certificate is signed & valid.") else: print_error("The SSL certificate has a problem:") print("") print(cert_status) print("")
def check_ssl_cert(domain, env): # Check that SSL certificate is signed. # Skip the check if the A record is not pointed here. if query_dns(domain, "A", None) not in (env['PUBLIC_IP'], None): return # Where is the SSL stored? ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env) if not os.path.exists(ssl_certificate): env['out'].print_error( "The SSL certificate file for this domain is missing.") return # Check that the certificate is good. cert_status, cert_status_details = check_certificate( domain, ssl_certificate, ssl_key) if cert_status == "OK": # The certificate is ok. The details has expiry info. env['out'].print_ok("SSL certificate is signed & valid. " + cert_status_details) elif cert_status == "SELF-SIGNED": # Offer instructions for purchasing a signed certificate. fingerprint = shell('check_output', [ "openssl", "x509", "-in", ssl_certificate, "-noout", "-fingerprint" ]) fingerprint = re.sub(".*Fingerprint=", "", fingerprint).strip() if domain == env['PRIMARY_HOSTNAME']: env['out'].print_error( """The SSL certificate for this domain is currently self-signed. You will get a security warning when you check or send email and when visiting this domain in a web browser (for webmail or static site hosting). Use the SSL Certificates page in this control panel to install a signed SSL certificate. You may choose to leave the self-signed certificate in place and confirm the security exception, but check that the certificate fingerprint matches the following:""") env['out'].print_line("") env['out'].print_line(" " + fingerprint, monospace=True) else: env['out'].print_warning( """The SSL certificate for this domain is currently self-signed. Visitors to a website on this domain will get a security warning. If you are not serving a website on this domain, then it is safe to leave the self-signed certificate in place. Use the SSL Certificates page in this control panel to install a signed SSL certificate.""") else: env['out'].print_error("The SSL certificate has a problem: " + cert_status) if cert_status_details: env['out'].print_line("") env['out'].print_line(cert_status_details) env['out'].print_line("")
def check_ssl_cert(domain, rounded_time, ssl_certificates, env, output): # Check that SSL certificate is signed. # Skip the check if the A record is not pointed here. if query_dns(domain, "A", None) not in (env['PUBLIC_IP'], None): return # Where is the SSL stored? x = get_domain_ssl_files(domain, ssl_certificates, env, allow_missing_cert=True) if x is None: output.print_warning("""No SSL certificate is installed for this domain. Visitors to a website on this domain will get a security warning. If you are not serving a website on this domain, you do not need to take any action. Use the SSL Certificates page in the control panel to install a SSL certificate.""") return ssl_key, ssl_certificate, ssl_via = x # Check that the certificate is good. cert_status, cert_status_details = check_certificate(domain, ssl_certificate, ssl_key, rounded_time=rounded_time) if cert_status == "OK": # The certificate is ok. The details has expiry info. output.print_ok("SSL certificate is signed & valid. %s %s" % (ssl_via if ssl_via else "", cert_status_details)) elif cert_status == "SELF-SIGNED": # Offer instructions for purchasing a signed certificate. fingerprint = shell('check_output', [ "openssl", "x509", "-in", ssl_certificate, "-noout", "-fingerprint" ]) fingerprint = re.sub(".*Fingerprint=", "", fingerprint).strip() if domain == env['PRIMARY_HOSTNAME']: output.print_error("""The SSL certificate for this domain is currently self-signed. You will get a security warning when you check or send email and when visiting this domain in a web browser (for webmail or static site hosting). Use the SSL Certificates page in the control panel to install a signed SSL certificate. You may choose to leave the self-signed certificate in place and confirm the security exception, but check that the certificate fingerprint matches the following:""") output.print_line("") output.print_line(" " + fingerprint, monospace=True) else: output.print_error("""The SSL certificate for this domain is self-signed.""") else: output.print_error("The SSL certificate has a problem: " + cert_status) if cert_status_details: output.print_line("") output.print_line(cert_status_details) output.print_line("")
def check_ssl_cert(domain, env): # Check that SSL certificate is signed. # Skip the check if the A record is not pointed here. if query_dns(domain, "A") != env['PUBLIC_IP']: return # Where is the SSL stored? ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env) if not os.path.exists(ssl_certificate): print_error("The SSL certificate file for this domain is missing.") return # Check that the certificate is good. cert_status = check_certificate(ssl_certificate) if cert_status == "SELF-SIGNED": fingerprint = shell('check_output', [ "openssl", "x509", "-in", ssl_certificate, "-noout", "-fingerprint" ]) fingerprint = re.sub(".*Fingerprint=", "", fingerprint).strip() print_error("""The SSL certificate for this domain is currently self-signed. That's OK if you are willing to confirm security exceptions when you check your mail (either via IMAP or webmail), but if you are serving a website on this domain then users will not be able to access the site. When confirming security exceptions, check that the certificate fingerprint matches:""") print() print(" " + fingerprint) print() print_block("""You can purchase a signed certificate from many places. You will need to provide this Certificate Signing Request (CSR) to whoever you purchase the SSL certificate from:""") print() print(open(ssl_csr_path).read().strip()) print() print_block("""When you purchase an SSL certificate you will receive a certificate in PEM format and possibly a file containing intermediate certificates in PEM format. If you receive intermediate certificates, use a text editor and paste your certificate on top and then the intermediate certificates below it. Save the file and place it onto this machine at %s.""" % ssl_certificate) elif cert_status == "OK": print_ok("SSL certificate is signed.") else: print_error("The SSL certificate has a problem:") print("") print(cert_status) print("")
def ssl_get_csr(domain): from web_update import get_domain_ssl_files, create_csr ssl_key, ssl_certificate, csr_path = get_domain_ssl_files(domain, env) return create_csr(domain, ssl_key, env)
linelen = 0 if linelen == 0 and w.strip() == "": continue print(w, end="") linelen += len(w) print() def print_line(self, message, monospace=False): for line in message.split("\n"): self.print_block(line) if __name__ == "__main__": import sys from utils import load_environment env = load_environment() if len(sys.argv) == 1: run_checks(env, ConsoleOutput()) elif sys.argv[1] == "--check-primary-hostname": # See if the primary hostname appears resolvable and has a signed certificate. domain = env['PRIMARY_HOSTNAME'] if query_dns(domain, "A") != env['PUBLIC_IP']: sys.exit(1) ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files( domain, env) if not os.path.exists(ssl_certificate): sys.exit(1) cert_status = check_certificate(domain, ssl_certificate, ssl_key) if cert_status != "OK": sys.exit(1) sys.exit(0)
getattr(output, attr)(*args, **kwargs) if __name__ == "__main__": from utils import load_environment env = load_environment() pool = multiprocessing.pool.Pool(processes=10) if len(sys.argv) == 1: run_checks(False, env, ConsoleOutput(), pool) elif sys.argv[1] == "--show-changes": run_and_output_changes(env, pool, sys.argv[-1] == "--smtp") elif sys.argv[1] == "--check-primary-hostname": # See if the primary hostname appears resolvable and has a signed certificate. domain = env['PRIMARY_HOSTNAME'] if query_dns(domain, "A") != env['PUBLIC_IP']: sys.exit(1) ssl_key, ssl_certificate, ssl_via = get_domain_ssl_files(domain, env) if not os.path.exists(ssl_certificate): sys.exit(1) cert_status, cert_status_details = check_certificate(domain, ssl_certificate, ssl_key, warn_if_expiring_soon=False) if cert_status != "OK": sys.exit(1) sys.exit(0) elif sys.argv[1] == "--version": print(what_version_is_this(env))
return w def playback(self, output): for attr, args, kwargs in self.buf: getattr(output, attr)(*args, **kwargs) if __name__ == "__main__": from utils import load_environment env = load_environment() pool = multiprocessing.pool.Pool(processes=10) if len(sys.argv) == 1: run_checks(False, env, ConsoleOutput(), pool) elif sys.argv[1] == "--show-changes": run_and_output_changes(env, pool, sys.argv[-1] == "--smtp") elif sys.argv[1] == "--check-primary-hostname": # See if the primary hostname appears resolvable and has a signed certificate. domain = env['PRIMARY_HOSTNAME'] if query_dns(domain, "A") != env['PUBLIC_IP']: sys.exit(1) ssl_key, ssl_certificate, ssl_via = get_domain_ssl_files(domain, env) if not os.path.exists(ssl_certificate): sys.exit(1) cert_status, cert_status_details = check_certificate(domain, ssl_certificate, ssl_key) if cert_status != "OK": sys.exit(1) sys.exit(0)
print() print(" ", end="") linelen = 0 if linelen == 0 and w.strip() == "": continue print(w, end="") linelen += len(w) print() def print_line(self, message, monospace=False): for line in message.split("\n"): self.print_block(line) if __name__ == "__main__": import sys from utils import load_environment env = load_environment() if len(sys.argv) == 1: run_checks(env, ConsoleOutput()) elif sys.argv[1] == "--check-primary-hostname": # See if the primary hostname appears resolvable and has a signed certificate. domain = env['PRIMARY_HOSTNAME'] if query_dns(domain, "A") != env['PUBLIC_IP']: sys.exit(1) ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env) if not os.path.exists(ssl_certificate): sys.exit(1) cert_status, cert_status_details = check_certificate(domain, ssl_certificate, ssl_key) if cert_status != "OK": sys.exit(1) sys.exit(0)
def buy_ssl_certificate(api_key, domain, command, env): if domain != env['PRIMARY_HOSTNAME'] \ and domain not in get_web_domains(env): raise ValueError( "Domain is not %s or a domain we're serving a website for." % env['PRIMARY_HOSTNAME']) # Initialize. gandi = xmlrpc.client.ServerProxy('https://rpc.gandi.net/xmlrpc/') try: existing_certs = gandi.cert.list(api_key) except Exception as e: if "Invalid API key" in str(e): print( "Invalid API key. Check that you copied the API Key correctly from https://www.gandi.net/admin/api_key." ) sys.exit(1) else: raise # Where is the SSL cert stored? ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env) # Have we already created a cert for this domain? for cert in existing_certs: if cert['cn'] == domain: break else: # No existing cert found. Purchase one. if command != 'purchase': print( "No certificate or order found yet. If you haven't yet purchased a certificate, run ths script again with the 'purchase' command. Otherwise wait a moment and try again." ) sys.exit(1) else: # Start an order for a single standard SSL certificate. # Use DNS validation. Web-based validation won't work because they # require a file on HTTP but not HTTPS w/o redirects and we don't # serve anything plainly over HTTP. Email might be another way but # DNS is easier to automate. op = gandi.cert.create( api_key, { "csr": open(ssl_csr_path).read(), "dcv_method": "dns", "duration": 1, # year? "package": "cert_std_1_0_0", }) print("An SSL certificate has been ordered.") print() print(op) print() print( "In a moment please run this script again with the 'setup' command." ) if cert['status'] == 'pending': # Get the information we need to update our DNS with a code so that # Gandi can verify that we own the domain. dcv = gandi.cert.get_dcv_params( api_key, { "csr": open(ssl_csr_path).read(), "cert_id": cert['id'], "dcv_method": "dns", "duration": 1, # year? "package": "cert_std_1_0_0", }) if dcv["dcv_method"] != "dns": raise Exception( "Certificate ordered with an unknown validation method.") # Update our DNS data. dns_config = env['STORAGE_ROOT'] + '/dns/custom.yaml' if os.path.exists(dns_config): dns_records = rtyaml.load(open(dns_config)) else: dns_records = {} qname = dcv['md5'] + '.' + domain value = dcv['sha1'] + '.comodoca.com.' dns_records[qname] = {"CNAME": value} with open(dns_config, 'w') as f: f.write(rtyaml.dump(dns_records)) shell('check_call', ['tools/dns_update']) # Okay, done with this step. print("DNS has been updated. Gandi will check within 60 minutes.") print() print( "See https://www.gandi.net/admin/ssl/%d/details for the status of this order." % cert['id']) elif cert['status'] == 'valid': # The certificate is ready. # Check before we overwrite something we shouldn't. if os.path.exists(ssl_certificate): cert_status = check_certificate(None, ssl_certificate, None) if cert_status != "SELF-SIGNED": print( "Please back up and delete the file %s so I can save your new certificate." % ssl_certificate) sys.exit(1) # Form the certificate. # The certificate comes as a long base64-encoded string. Break in # into lines in the usual way. pem = "-----BEGIN CERTIFICATE-----\n" pem += "\n".join(chunk for chunk in re.split(r"(.{64})", cert['cert']) if chunk != "") pem += "\n-----END CERTIFICATE-----\n\n" # Append intermediary certificates. pem += urllib.request.urlopen( "https://www.gandi.net/static/CAs/GandiStandardSSLCA.pem").read( ).decode("ascii") # Write out. with open(ssl_certificate, "w") as f: f.write(pem) print( "The certificate has been installed in %s. Restarting services..." % ssl_certificate) # Restart dovecot and if this is for PRIMARY_HOSTNAME. if domain == env['PRIMARY_HOSTNAME']: shell('check_call', ["/usr/sbin/service", "dovecot", "restart"]) shell('check_call', ["/usr/sbin/service", "postfix", "restart"]) # Restart nginx in all cases. shell('check_call', ["/usr/sbin/service", "nginx", "restart"]) else: print( "The certificate has an unknown status. Please check https://www.gandi.net/admin/ssl/%d/details for the status of this order." % cert['id'])
def buy_ssl_certificate(api_key, domain, command, env): if domain != env['PRIMARY_HOSTNAME'] \ and domain not in get_web_domains(env): raise ValueError("Domain is not %s or a domain we're serving a website for." % env['PRIMARY_HOSTNAME']) # Initialize. gandi = xmlrpc.client.ServerProxy('https://rpc.gandi.net/xmlrpc/') try: existing_certs = gandi.cert.list(api_key) except Exception as e: if "Invalid API key" in str(e): print("Invalid API key. Check that you copied the API Key correctly from https://www.gandi.net/admin/api_key.") sys.exit(1) else: raise # Where is the SSL cert stored? ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env) # Have we already created a cert for this domain? for cert in existing_certs: if cert['cn'] == domain: break else: # No existing cert found. Purchase one. if command != 'purchase': print("No certificate or order found yet. If you haven't yet purchased a certificate, run ths script again with the 'purchase' command. Otherwise wait a moment and try again.") sys.exit(1) else: # Start an order for a single standard SSL certificate. # Use DNS validation. Web-based validation won't work because they # require a file on HTTP but not HTTPS w/o redirects and we don't # serve anything plainly over HTTP. Email might be another way but # DNS is easier to automate. op = gandi.cert.create(api_key, { "csr": open(ssl_csr_path).read(), "dcv_method": "dns", "duration": 1, # year? "package": "cert_std_1_0_0", }) print("An SSL certificate has been ordered.") print() print(op) print() print("In a moment please run this script again with the 'setup' command.") if cert['status'] == 'pending': # Get the information we need to update our DNS with a code so that # Gandi can verify that we own the domain. dcv = gandi.cert.get_dcv_params(api_key, { "csr": open(ssl_csr_path).read(), "cert_id": cert['id'], "dcv_method": "dns", "duration": 1, # year? "package": "cert_std_1_0_0", }) if dcv["dcv_method"] != "dns": raise Exception("Certificate ordered with an unknown validation method.") # Update our DNS data. dns_config = env['STORAGE_ROOT'] + '/dns/custom.yaml' if os.path.exists(dns_config): dns_records = rtyaml.load(open(dns_config)) else: dns_records = { } qname = dcv['md5'] + '.' + domain value = dcv['sha1'] + '.comodoca.com.' dns_records[qname] = { "CNAME": value } with open(dns_config, 'w') as f: f.write(rtyaml.dump(dns_records)) shell('check_call', ['tools/dns_update']) # Okay, done with this step. print("DNS has been updated. Gandi will check within 60 minutes.") print() print("See https://www.gandi.net/admin/ssl/%d/details for the status of this order." % cert['id']) elif cert['status'] == 'valid': # The certificate is ready. # Check before we overwrite something we shouldn't. if os.path.exists(ssl_certificate): cert_status, cert_status_details = check_certificate(None, ssl_certificate, None) if cert_status != "SELF-SIGNED": print("Please back up and delete the file %s so I can save your new certificate." % ssl_certificate) sys.exit(1) # Form the certificate. # The certificate comes as a long base64-encoded string. Break in # into lines in the usual way. pem = "-----BEGIN CERTIFICATE-----\n" pem += "\n".join(chunk for chunk in re.split(r"(.{64})", cert['cert']) if chunk != "") pem += "\n-----END CERTIFICATE-----\n\n" # Append intermediary certificates. pem += urllib.request.urlopen("https://www.gandi.net/static/CAs/GandiStandardSSLCA.pem").read().decode("ascii") # Write out. with open(ssl_certificate, "w") as f: f.write(pem) print("The certificate has been installed in %s. Restarting services..." % ssl_certificate) # Restart dovecot and if this is for PRIMARY_HOSTNAME. if domain == env['PRIMARY_HOSTNAME']: shell('check_call', ["/usr/sbin/service", "dovecot", "restart"]) shell('check_call', ["/usr/sbin/service", "postfix", "restart"]) # Restart nginx in all cases. shell('check_call', ["/usr/sbin/service", "nginx", "restart"]) else: print("The certificate has an unknown status. Please check https://www.gandi.net/admin/ssl/%d/details for the status of this order." % cert['id'])