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_cert(domain): tls_cert = get_domain_ssl_files(domain, ssl_certificates, env, allow_missing_cert=True) if tls_cert is None: return ("danger", "No Certificate Installed") cert_status, cert_status_details = check_certificate(domain, tls_cert["certificate"], tls_cert["private-key"]) if cert_status == "OK": return ("success", "Signed & valid. " + cert_status_details) elif cert_status == "SELF-SIGNED": return ("warning", "Self-signed. Get a signed certificate to stop warnings.") else: return ("danger", "Certificate has a problem: " + cert_status)
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_cert(domain): try: tls_cert = get_domain_ssl_files(domain, ssl_certificates, env, allow_missing_cert=True) except OSError: # PRIMARY_HOSTNAME cert is missing tls_cert = None if tls_cert is None: return ("danger", "No certificate installed.") cert_status, cert_status_details = check_certificate(domain, tls_cert["certificate"], tls_cert["private-key"]) if cert_status == "OK": return ("success", "Signed & valid. " + cert_status_details) elif cert_status == "SELF-SIGNED": return ("warning", "Self-signed. Get a signed certificate to stop warnings.") else: return ("danger", "Certificate has a problem: " + cert_status)
def check_ssl_cert(domain, rounded_time, ssl_certificates, env, output): # Check that TLS 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 certificate file stored? tls_cert = get_domain_ssl_files(domain, ssl_certificates, env, allow_missing_cert=True) if tls_cert is None: output.print_warning( """No TLS (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 TLS Certificates page in the control panel to install a TLS certificate.""") return # Check that the certificate is good. cert_status, cert_status_details = check_certificate( domain, tls_cert["certificate"], tls_cert["private-key"], rounded_time=rounded_time) if cert_status == "OK": # The certificate is ok. The details has expiry info. output.print_ok("TLS (SSL) certificate is signed & valid. " + cert_status_details) elif cert_status == "SELF-SIGNED": # Offer instructions for purchasing a signed certificate. if domain == env['PRIMARY_HOSTNAME']: output.print_error( """The TLS (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).""") else: output.print_error( """The TLS (SSL) certificate for this domain is self-signed.""" ) else: output.print_error("The TLS (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_cert(domain): ssl_certificates = get_ssl_certificates(env) x = get_domain_ssl_files(domain, ssl_certificates, env, allow_missing_cert=True) if x is None: return ("danger", "No Certificate Installed") ssl_key, ssl_certificate, ssl_via = x cert_status, cert_status_details = check_certificate(domain, ssl_certificate, ssl_key) if cert_status == "OK": if not ssl_via: return ("success", "Signed & valid. " + cert_status_details) else: # This is an alternate domain but using the same cert as the primary domain. return ("success", "Signed & valid. " + ssl_via) elif cert_status == "SELF-SIGNED": return ("warning", "Self-signed. Get a signed certificate to stop warnings.") else: return ("danger", "Certificate has a problem: " + cert_status)
def check_ssl_cert(domain, rounded_time, ssl_certificates, env, output): # Check that TLS 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 certificate file stored? tls_cert = get_domain_ssl_files(domain, ssl_certificates, env, allow_missing_cert=True) if tls_cert is None: output.print_warning( """No TLS (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 TLS Certificates page in the control panel to install a TLS certificate.""" ) return # Check that the certificate is good. cert_status, cert_status_details = check_certificate( domain, tls_cert["certificate"], tls_cert["private-key"], rounded_time=rounded_time ) if cert_status == "OK": # The certificate is ok. The details has expiry info. output.print_ok("TLS (SSL) certificate is signed & valid. " + cert_status_details) elif cert_status == "SELF-SIGNED": # Offer instructions for purchasing a signed certificate. if domain == env["PRIMARY_HOSTNAME"]: output.print_error( """The TLS (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).""" ) else: output.print_error("""The TLS (SSL) certificate for this domain is self-signed.""") else: output.print_error("The TLS (SSL) certificate has a problem: " + cert_status) if cert_status_details: output.print_line("") output.print_line(cert_status_details) output.print_line("")
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) 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_certificates = get_ssl_certificates(env) ssl_key, ssl_certificate, ssl_via = get_domain_ssl_files(domain, ssl_certificates, 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))
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) 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_certificates = get_ssl_certificates(env) tls_cert = get_domain_ssl_files(domain, ssl_certificates, env) if not os.path.exists(tls_cert["certificate"]): sys.exit(1) cert_status, cert_status_details = check_certificate(domain, tls_cert["certificate"], tls_cert["private-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))
def make_domain_config(domain, templates, ssl_certificates, env): # GET SOME VARIABLES # Where will its root directory be for static files? root = get_web_root(domain, env) # What private key and SSL certificate will we use for this domain? ssl_key, ssl_certificate, ssl_via = get_domain_ssl_files(domain, ssl_certificates, env) # ADDITIONAL DIRECTIVES. nginx_conf_extra = "" # Because the certificate may change, we should recognize this so we # can trigger an nginx update. def hashfile(filepath): import hashlib sha1 = hashlib.sha1() f = open(filepath, 'rb') try: sha1.update(f.read()) finally: f.close() return sha1.hexdigest() nginx_conf_extra += "# ssl files sha1: %s / %s\n" % (hashfile(ssl_key), hashfile(ssl_certificate)) # Add in any user customizations in YAML format. hsts = "yes" nginx_conf_custom_fn = os.path.join(env["STORAGE_ROOT"], "www/custom.yaml") if os.path.exists(nginx_conf_custom_fn): yaml = rtyaml.load(open(nginx_conf_custom_fn)) if domain in yaml: yaml = yaml[domain] # any proxy or redirect here? for path, url in yaml.get("proxies", {}).items(): nginx_conf_extra += "\tlocation %s {\n\t\tproxy_pass %s;\n\t}\n" % (path, url) for path, url in yaml.get("redirects", {}).items(): nginx_conf_extra += "\trewrite %s %s permanent;\n" % (path, url) # override the HSTS directive type hsts = yaml.get("hsts", hsts) # Add the HSTS header. if hsts == "yes": nginx_conf_extra += "add_header Strict-Transport-Security max-age=31536000;\n" elif hsts == "preload": nginx_conf_extra += "add_header Strict-Transport-Security \"max-age=10886400; includeSubDomains; preload\";\n" # Add in any user customizations in the includes/ folder. nginx_conf_custom_include = os.path.join(env["STORAGE_ROOT"], "www", safe_domain_name(domain) + ".conf") if os.path.exists(nginx_conf_custom_include): nginx_conf_extra += "\tinclude %s;\n" % (nginx_conf_custom_include) # PUT IT ALL TOGETHER # Combine the pieces. Iteratively place each template into the "# ADDITIONAL DIRECTIVES HERE" placeholder # of the previous template. nginx_conf = "# ADDITIONAL DIRECTIVES HERE\n" for t in templates + [nginx_conf_extra]: nginx_conf = re.sub("[ \t]*# ADDITIONAL DIRECTIVES HERE *\n", t, nginx_conf) # Replace substitution strings in the template & return. nginx_conf = nginx_conf.replace("$STORAGE_ROOT", env['STORAGE_ROOT']) nginx_conf = nginx_conf.replace("$HOSTNAME", domain) nginx_conf = nginx_conf.replace("$ROOT", root) nginx_conf = nginx_conf.replace("$SSL_KEY", ssl_key) nginx_conf = nginx_conf.replace("$SSL_CERTIFICATE", ssl_certificate) nginx_conf = nginx_conf.replace("$REDIRECT_DOMAIN", re.sub(r"^www\.", "", domain)) # for default www redirects to parent domain return nginx_conf
def make_domain_config(domain, templates, ssl_certificates, env): # GET SOME VARIABLES # Where will its root directory be for static files? root = get_web_root(domain, env) # What private key and SSL certificate will we use for this domain? tls_cert = get_domain_ssl_files(domain, ssl_certificates, env) # ADDITIONAL DIRECTIVES. nginx_conf_extra = "" # Because the certificate may change, we should recognize this so we # can trigger an nginx update. def hashfile(filepath): import hashlib sha1 = hashlib.sha1() f = open(filepath, 'rb') try: sha1.update(f.read()) finally: f.close() return sha1.hexdigest() nginx_conf_extra += "# ssl files sha1: %s / %s\n" % ( hashfile(tls_cert["private-key"]), hashfile(tls_cert["certificate"])) # Add in any user customizations in YAML format. hsts = "yes" nginx_conf_custom_fn = os.path.join(env["STORAGE_ROOT"], "www/custom.yaml") if os.path.exists(nginx_conf_custom_fn): yaml = rtyaml.load(open(nginx_conf_custom_fn)) if domain in yaml: yaml = yaml[domain] # any proxy or redirect here? for path, url in yaml.get("proxies", {}).items(): nginx_conf_extra += "\tlocation %s {\n\t\tproxy_pass %s;\n\t}\n" % (path, url) for path, url in yaml.get("redirects", {}).items(): nginx_conf_extra += "\trewrite %s %s permanent;\n" % (path, url) # override the HSTS directive type hsts = yaml.get("hsts", hsts) # Add the HSTS header. if hsts == "yes": nginx_conf_extra += "add_header Strict-Transport-Security max-age=31536000;\n" elif hsts == "preload": nginx_conf_extra += "add_header Strict-Transport-Security \"max-age=10886400; includeSubDomains; preload\";\n" # Add in any user customizations in the includes/ folder. nginx_conf_custom_include = os.path.join(env["STORAGE_ROOT"], "www", safe_domain_name(domain) + ".conf") if os.path.exists(nginx_conf_custom_include): nginx_conf_extra += "\tinclude %s;\n" % (nginx_conf_custom_include) # PUT IT ALL TOGETHER # Combine the pieces. Iteratively place each template into the "# ADDITIONAL DIRECTIVES HERE" placeholder # of the previous template. nginx_conf = "# ADDITIONAL DIRECTIVES HERE\n" for t in templates + [nginx_conf_extra]: nginx_conf = re.sub("[ \t]*# ADDITIONAL DIRECTIVES HERE *\n", t, nginx_conf) # Replace substitution strings in the template & return. nginx_conf = nginx_conf.replace("$STORAGE_ROOT", env['STORAGE_ROOT']) nginx_conf = nginx_conf.replace("$HOSTNAME", domain) nginx_conf = nginx_conf.replace("$ROOT", root) nginx_conf = nginx_conf.replace("$SSL_KEY", tls_cert["private-key"]) nginx_conf = nginx_conf.replace("$SSL_CERTIFICATE", tls_cert["certificate"]) nginx_conf = nginx_conf.replace("$REDIRECT_DOMAIN", re.sub(r"^www\.", "", domain)) # for default www redirects to parent domain return nginx_conf
def make_domain_config(domain, templates, ssl_certificates, env): # GET SOME VARIABLES # Where will its root directory be for static files? root = get_web_root(domain, env) # What private key and SSL certificate will we use for this domain? tls_cert = get_domain_ssl_files(domain, ssl_certificates, env) # ADDITIONAL DIRECTIVES. nginx_conf_extra = "" # Because the certificate may change, we should recognize this so we # can trigger an nginx update. def hashfile(filepath): import hashlib sha1 = hashlib.sha1() f = open(filepath, 'rb') try: sha1.update(f.read()) finally: f.close() return sha1.hexdigest() nginx_conf_extra += "\t# ssl files sha1: %s / %s\n" % (hashfile(tls_cert["private-key"]), hashfile(tls_cert["certificate"])) # Add in any user customizations in YAML format. hsts = "yes" nginx_conf_custom_fn = os.path.join(env["STORAGE_ROOT"], "www/custom.yaml") if os.path.exists(nginx_conf_custom_fn): yaml = rtyaml.load(open(nginx_conf_custom_fn)) if domain in yaml: yaml = yaml[domain] # any proxy or redirect here? for path, url in yaml.get("proxies", {}).items(): # Parse some flags in the fragment of the URL. pass_http_host_header = False proxy_redirect_off = False frame_options_header_sameorigin = False m = re.search("#(.*)$", url) if m: for flag in m.group(1).split(","): if flag == "pass-http-host": pass_http_host_header = True elif flag == "no-proxy-redirect": proxy_redirect_off = True elif flag == "frame-options-sameorigin": frame_options_header_sameorigin = True url = re.sub("#(.*)$", "", url) nginx_conf_extra += "\tlocation %s {" % path nginx_conf_extra += "\n\t\tproxy_pass %s;" % url if proxy_redirect_off: nginx_conf_extra += "\n\t\tproxy_redirect off;" if pass_http_host_header: nginx_conf_extra += "\n\t\tproxy_set_header Host $http_host;" if frame_options_header_sameorigin: nginx_conf_extra += "\n\t\tproxy_set_header X-Frame-Options SAMEORIGIN;" nginx_conf_extra += "\n\t\tproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;" nginx_conf_extra += "\n\t\tproxy_set_header X-Forwarded-Host $http_host;" nginx_conf_extra += "\n\t\tproxy_set_header X-Forwarded-Proto $scheme;" nginx_conf_extra += "\n\t\tproxy_set_header X-Real-IP $remote_addr;" nginx_conf_extra += "\n\t}\n" for path, alias in yaml.get("aliases", {}).items(): nginx_conf_extra += "\tlocation %s {" % path nginx_conf_extra += "\n\t\talias %s;" % alias nginx_conf_extra += "\n\t}\n" for path, url in yaml.get("redirects", {}).items(): nginx_conf_extra += "\trewrite %s %s permanent;\n" % (path, url) # override the HSTS directive type hsts = yaml.get("hsts", hsts) # Add the HSTS header. if hsts == "yes": nginx_conf_extra += "\tadd_header Strict-Transport-Security \"max-age=15768000\" always;\n" elif hsts == "preload": nginx_conf_extra += "\tadd_header Strict-Transport-Security \"max-age=15768000; includeSubDomains; preload\" always;\n" # Add in any user customizations in the includes/ folder. nginx_conf_custom_include = os.path.join(env["STORAGE_ROOT"], "www", safe_domain_name(domain) + ".conf") if not os.path.exists(nginx_conf_custom_include): with open(nginx_conf_custom_include, "a+") as f: f.writelines([ f"# Custom configurations for {domain} go here\n", "# To use php: use the \"php-fpm\" alias\n\n", "index index.html index.htm;\n" ]) nginx_conf_extra += "\tinclude %s;\n" % (nginx_conf_custom_include) # PUT IT ALL TOGETHER # Combine the pieces. Iteratively place each template into the "# ADDITIONAL DIRECTIVES HERE" placeholder # of the previous template. nginx_conf = "# ADDITIONAL DIRECTIVES HERE\n" for t in templates + [nginx_conf_extra]: nginx_conf = re.sub("[ \t]*# ADDITIONAL DIRECTIVES HERE *\n", t, nginx_conf) # Replace substitution strings in the template & return. nginx_conf = nginx_conf.replace("$STORAGE_ROOT", env['STORAGE_ROOT']) nginx_conf = nginx_conf.replace("$HOSTNAME", domain) nginx_conf = nginx_conf.replace("$ROOT", root) nginx_conf = nginx_conf.replace("$SSL_KEY", tls_cert["private-key"]) nginx_conf = nginx_conf.replace("$SSL_CERTIFICATE", tls_cert["certificate"]) nginx_conf = nginx_conf.replace("$REDIRECT_DOMAIN", re.sub(r"^www\.", "", domain)) # for default www redirects to parent domain return nginx_conf