Exemple #1
0
def get_domain_ssl_files(domain, env):
    # What SSL private key will we use? Allow the user to override this, but
    # in many cases using the same private key for all domains would be fine.
    # Don't allow the user to override the key for PRIMARY_HOSTNAME because
    # that's what's in the main file.
    ssl_key = os.path.join(env["STORAGE_ROOT"], 'ssl/ssl_private_key.pem')
    ssl_key_is_alt = False
    alt_key = os.path.join(env["STORAGE_ROOT"],
                           'ssl/%s/private_key.pem' % safe_domain_name(domain))
    if domain != env['PRIMARY_HOSTNAME'] and os.path.exists(alt_key):
        ssl_key = alt_key
        ssl_key_is_alt = True

    # What SSL certificate will we use?
    ssl_certificate_primary = os.path.join(env["STORAGE_ROOT"],
                                           'ssl/ssl_certificate.pem')
    if domain == env['PRIMARY_HOSTNAME']:
        # For PRIMARY_HOSTNAME, use the one we generated at set-up time.
        ssl_certificate = ssl_certificate_primary
    else:
        # For other domains, we'll probably use a certificate in a different path.
        ssl_certificate = os.path.join(
            env["STORAGE_ROOT"],
            'ssl/%s/ssl_certificate.pem' % safe_domain_name(domain))

        # But we can be smart and reuse the main SSL certificate if is has
        # a Subject Alternative Name matching this domain. Don't do this if
        # the user has uploaded a different private key for this domain.
        if not ssl_key_is_alt:
            from whats_next import check_certificate
            if check_certificate(domain, ssl_certificate_primary,
                                 None) == "OK":
                ssl_certificate = ssl_certificate_primary

    # Where would the CSR go? As with the SSL cert itself, the CSR must be
    # different for each domain name.
    if domain == env['PRIMARY_HOSTNAME']:
        csr_path = os.path.join(env["STORAGE_ROOT"],
                                'ssl/ssl_cert_sign_req.csr')
    else:
        csr_path = os.path.join(
            env["STORAGE_ROOT"], 'ssl/%s/certificate_signing_request.csr' %
            safe_domain_name(domain))

    return ssl_key, ssl_certificate, csr_path
Exemple #2
0
def get_domain_ssl_files(domain, env):
	# What SSL private key will we use? Allow the user to override this, but
	# in many cases using the same private key for all domains would be fine.
	# Don't allow the user to override the key for PRIMARY_HOSTNAME because
	# that's what's in the main file.
	ssl_key = os.path.join(env["STORAGE_ROOT"], 'ssl/ssl_private_key.pem')
	ssl_key_is_alt = False
	alt_key = os.path.join(env["STORAGE_ROOT"], 'ssl/%s/private_key.pem' % safe_domain_name(domain))
	if domain != env['PRIMARY_HOSTNAME'] and os.path.exists(alt_key):
		ssl_key = alt_key
		ssl_key_is_alt = True

	# What SSL certificate will we use?
	ssl_certificate_primary = os.path.join(env["STORAGE_ROOT"], 'ssl/ssl_certificate.pem')
	if domain == env['PRIMARY_HOSTNAME']:
		# For PRIMARY_HOSTNAME, use the one we generated at set-up time.
		ssl_certificate = ssl_certificate_primary
	else:
		# For other domains, we'll probably use a certificate in a different path.
		ssl_certificate = os.path.join(env["STORAGE_ROOT"], 'ssl/%s/ssl_certificate.pem' % safe_domain_name(domain))

		# But we can be smart and reuse the main SSL certificate if is has
		# a Subject Alternative Name matching this domain. Don't do this if
		# the user has uploaded a different private key for this domain.
		if not ssl_key_is_alt:
			from whats_next import check_certificate
			if check_certificate(domain, ssl_certificate_primary, None) == "OK":
				ssl_certificate = ssl_certificate_primary

	# Where would the CSR go? As with the SSL cert itself, the CSR must be
	# different for each domain name.
	if domain == env['PRIMARY_HOSTNAME']:
		csr_path = os.path.join(env["STORAGE_ROOT"], 'ssl/ssl_cert_sign_req.csr')
	else:
		csr_path = os.path.join(env["STORAGE_ROOT"], 'ssl/%s/certificate_signing_request.csr' % safe_domain_name(domain))

	return ssl_key, ssl_certificate, csr_path
Exemple #3
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 = check_certificate(ssl_certificate)
			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'])