def post_install_func(env, is_tlsa_update_required=False): ret = [] # Get the certificate to use for PRIMARY_HOSTNAME. ssl_certificates = get_ssl_certificates(env) cert = get_domain_ssl_files(env['PRIMARY_HOSTNAME'], ssl_certificates, env, use_main_cert=False) if not cert: # Ruh-row, we don't have any certificate usable # for the primary hostname. ret.append("there is no valid certificate for " + env['PRIMARY_HOSTNAME']) # Symlink the best cert for PRIMARY_HOSTNAME to the system # certificate path, which is hard-coded for various purposes, and then # restart postfix and dovecot. system_ssl_certificate = os.path.join( os.path.join(env["STORAGE_ROOT"], 'ssl', 'ssl_certificate.pem')) if cert and os.readlink(system_ssl_certificate) != cert['certificate']: # Update symlink. ret.append("updating primary certificate") ssl_certificate = cert['certificate'] os.unlink(system_ssl_certificate) os.symlink(ssl_certificate, system_ssl_certificate) # Restart postfix and dovecot so they pick up the new file. shell('check_call', ["/usr/sbin/service", "postfix", "restart"]) shell('check_call', ["/usr/sbin/service", "dovecot", "restart"]) ret.append("mail services restarted") # The DANE TLSA record will remain valid so long as the private key # hasn't changed. We don't ever change the private key automatically. # If the user does it, they must manually update DNS. if is_tlsa_update_required: from dns_update import do_dns_update, set_custom_dns_record, build_tlsa_record subprocess.check_output([ "mv", env["STORAGE_ROOT"] + "/ssl/next_ssl_private_key.pem", env["STORAGE_ROOT"] + "/ssl/ssl_private_key.pem" ]) subprocess.check_output([ "openssl", "genrsa", "-out", env["STORAGE_ROOT"] + "/ssl/next_ssl_private_key.pem", "2048" ]) qname1 = "_25._tcp." + env['PRIMARY_HOSTNAME'] qname2 = "_443._tcp." + env['PRIMARY_HOSTNAME'] rtype = "TLSA" value = build_tlsa_record(env, from_cert=False) action = "add" if set_custom_dns_record(qname1, rtype, value, action, env): set_custom_dns_record(qname2, rtype, value, action, env) ret.append(do_dns_update(env)) # Update the web configuration so nginx picks up the new certificate file. from web_update import do_web_update ret.append(do_web_update(env)) return ret
def letsencrypt_dns_cleanup(domain): from dns_update import do_dns_update, set_custom_dns_record try: qname = '_acme-challenge.' + domain if set_custom_dns_record(qname, 'TXT', None, 'remove', env): if not do_dns_update(env): return ("Error updating DNS", 400) return "OK" except ValueError as e: return (str(e), 400)
def dns_set_record(qname, rtype="A"): from dns_update import do_dns_update, set_custom_dns_record try: # Normalize. rtype = rtype.upper() # Read the record value from the request BODY, which must be # ASCII-only. Not used with GET. value = request.args.get( "override_value", request.stream.read().decode("ascii", "ignore").strip()) method = request.args.get("override_method", request.method) if method == "GET": # Get the existing records matching the qname and rtype. return dns_get_records(qname, rtype) elif method in ("POST", "PUT"): # There is a default value for A/AAAA records. if rtype in ("A", "AAAA") and value == "": value = request.environ.get( "HTTP_X_FORWARDED_FOR" ) # normally REMOTE_ADDR but we're behind nginx as a reverse proxy # Cannot add empty records. if value == '': return ("No value for the record provided.", 400) if method == "POST": # Add a new record (in addition to any existing records # for this qname-rtype pair). action = "add" elif method == "PUT": # In REST, PUT is supposed to be idempotent, so we'll # make this action set (replace all records for this # qname-rtype pair) rather than add (add a new record). action = "set" elif method == "DELETE": if value == '': # Delete all records for this qname-type pair. value = None else: # Delete just the qname-rtype-value record exactly. pass action = "remove" if set_custom_dns_record(qname, rtype, value, action, env): return do_dns_update(env) or "Something isn't right." return "OK" except ValueError as e: return (str(e), 400)
def dns_set_record(qname, rtype="A"): from dns_update import do_dns_update, set_custom_dns_record try: # Normalize. rtype = rtype.upper() # Read the record value from the request BODY, which must be # ASCII-only. Not used with GET. value = request.stream.read().decode("ascii", "ignore").strip() if request.method == "GET": # Get the existing records matching the qname and rtype. return dns_get_records(qname, rtype) elif request.method in ("POST", "PUT"): # There is a default value for A/AAAA records. if rtype in ("A", "AAAA") and value == "": value = request.environ.get( "HTTP_X_FORWARDED_FOR" ) # normally REMOTE_ADDR but we're behind nginx as a reverse proxy # Cannot add empty records. if value == "": return ("No value for the record provided.", 400) if request.method == "POST": # Add a new record (in addition to any existing records # for this qname-rtype pair). action = "add" elif request.method == "PUT": # In REST, PUT is supposed to be idempotent, so we'll # make this action set (replace all records for this # qname-rtype pair) rather than add (add a new record). action = "set" elif request.method == "DELETE": if value == "": # Delete all records for this qname-type pair. value = None else: # Delete just the qname-rtype-value record exactly. pass action = "remove" if set_custom_dns_record(qname, rtype, value, action, env): return do_dns_update(env) or "Something isn't right." return "OK" except ValueError as e: return (str(e), 400)
def dns_set_record(qname, rtype="A", value=None): from dns_update import do_dns_update, set_custom_dns_record try: # Get the value from the URL, then the POST parameters, or if it is not set then # use the remote IP address of the request --- makes dynamic DNS easy. To clear a # value, '' must be explicitly passed. if value is None: value = request.form.get("value") if value is None: value = request.environ.get("HTTP_X_FORWARDED_FOR") # normally REMOTE_ADDR but we're behind nginx as a reverse proxy if value == '' or value == '__delete__': # request deletion value = None if set_custom_dns_record(qname, rtype, value, env): return do_dns_update(env) return "OK" except ValueError as e: return (str(e), 400)