예제 #1
0
def _get_signed_certificate(name, args, log=LOGGER):
    """Gets a signed certificate (using acme-tiny)"""
    account = os.path.join(args.path, 'account.key')
    csr = os.path.join(args.path, name, 'domain.csr')
    crt = os.path.join(args.path, name, 'domain.crt')
    out = acme_tiny.get_crt(account, csr, args.acme_dir, log, args.ca)
    _mode(_dump_bytes, 0640)(out, crt)
    os.chmod(crt, 0640)
예제 #2
0
def main():
    crt = acme_tiny.get_crt(config.ACCOUNT_KEY, config.CSR, config.ACMEDIR)
    ssl_args = {'cert': crt}

    def try_read(key, setting):
        if hasattr(config, setting):
            with open(getattr(config, setting), 'r') as f:
                ssl_args[key] = f.read()

    try_read('key', 'SERVER_KEY')
    try_read('cabundle', 'CABUNDLE')

    return CLIENT.uapi('SSL', 'install_ssl', **ssl_args)
예제 #3
0
def create_crt(name):
    if exist_crt(name):
        shutil.copyfile(
            "%s/%s.crt" % (crt_dir, name), "%s/%s_%s.crt" %
            (crt_bak_dir, datetime.now().strftime("%Y%m%d_%H%M%S"), name))

    signed_crt = acme_tiny.get_crt("config/account.key",
                                   "%s/%s.csr" % (crt_dir, name),
                                   acme_challenge_dir, logger, acme_ca)

    if chained_crt == "true":
        signed_crt += urlopen(acme_intermediate).read().decode("utf8")

    with open("%s/%s.crt" % (crt_dir, name), "w") as file:
        file.write(signed_crt)
예제 #4
0
def	renew_domain(domain: str):
	d = date.today()
	csr = f"/etc/ssl/acme/{domain}.csr"
	crt = f"/etc/ssl/acme/{domain}-{d.year}-{d.month}-{d.day}.crt"
	crt_link = f"/etc/ssl/private/{domain}.crt"

	# sign the request using acme_tiny
	crt_data = acme_tiny.get_crt(csr=csr, acme_dir=ACME_CHALLENGE, account_key=ACME_KEY)
	with open(crt, "wt") as crt_file:
		crt_file.write(crt_data)
	utils.log_info("Generated signed certificate " + crt)

	# update the symlink to point to newly generated file
	if os.path.exists(crt_link):
		os.unlink(crt_link)
	os.symlink(crt, crt_link)
	utils.log_info("Symlinked certificate to " + crt_link)

	subprocess.run(["nginx", "-t"], check=True)
	subprocess.run(["systemctl", "reload", "nginx"], check=True)
	utils.log_info("Nginx reloaded")
예제 #5
0
 def cron(self):
     domain = urllib.parse.urlparse(
         self.env['ir.config_parameter'].get_param('web.base.url',
                                                   'localhost')).netloc
     self.validate_domain(domain)
     account_key = self.generate_account_key()
     csr = self.generate_csr(domain)
     acme_challenge = get_challenge_dir()
     if not os.path.isdir(acme_challenge):
         os.makedirs(acme_challenge)
     if self.env.context.get('letsencrypt_dry_run'):
         crt_text = 'I\'m a test text'
     else:  # pragma: no cover
         from acme_tiny import get_crt, DEFAULT_CA
         crt_text = get_crt(account_key,
                            csr,
                            acme_challenge,
                            log=_logger,
                            CA=DEFAULT_CA)
     with open(os.path.join(get_data_dir(), '%s.crt' % domain), 'w')\
             as crt:
         crt.write(crt_text)
         chain_cert = urllib.request.urlopen(
             self.env['ir.config_parameter'].get_param(
                 'letsencrypt.chain_certificate_address',
                 'https://letsencrypt.org/certs/'
                 'lets-encrypt-x3-cross-signed.pem'))
         crt.write(str(chain_cert.read()))
         chain_cert.close()
         _logger.info('wrote %s', crt.name)
     reload_cmd = self.env['ir.config_parameter'].sudo().get_param(
         'letsencrypt.reload_command', False)
     if reload_cmd:
         _logger.info('reloading webserver...')
         self.call_cmdline(['sh', '-c', reload_cmd])
     else:
         _logger.info('no command defined for reloading webserver, please '
                      'do it manually in order to apply new certificate')
예제 #6
0
def generate_cert(domain, cert_dir, challenge_dir):
    """Generate a TLS certificate signed by Let's Encrypt for given domain."""
    account_key = cert_dir / "account.key"
    if not account_key.exists():
        sh.openssl("genrsa", "4096", _out=str(account_key))
    private_key = cert_dir / "domain.key"
    if not private_key.exists():
        sh.openssl("genrsa", "4096", _out=str(private_key))
    csr = cert_dir / "domain.csr"
    if not csr.exists():
        sh.openssl(
            "req",
            "-new",
            "-sha256",
            "-key",
            private_key,
            "-subj",
            f"/CN={domain}",
            _out=str(csr),
        )
    with (cert_dir / "domain.crt").open("w") as fp:
        fp.write(acme_tiny.get_crt(account_key, csr, challenge_dir))
    csr.unlink()
예제 #7
0
def createOrRenew(domain, userkey="keys/user.key", with_www=False, interactive=False, renewalOnly=False):
	DOMAIN_PATH=path.join(STORE_PATH, "keys", domain)
	CHALLENGE_PATH=path.join(STORE_PATH, "challenges", domain)
	isNew = False

	print "Domain: %s" % domain

	if interactive:
		if not ask("Proceed?"): return False

	if not path.isdir(DOMAIN_PATH):
		if renewalOnly:
			print "Set to renewal only, refusing to create new key"
			return False

		print "Directory not found, creating..."
		os.mkdir(DOMAIN_PATH)
		isNew = True

	if not path.isdir(CHALLENGE_PATH):
		print "Creating challenge dir..."
		os.mkdir(CHALLENGE_PATH)
		isNew = True

	#Fetch intermediate
	print "Downloading intermediate certificate..."
	intermediateKey = getHttp(INTERMEDIATE_KEY_URL)
	if not intermediateKey:
		print "Failed to download intermediate certificate"
		return False

	# Check for user key
	if not path.isfile(USERKEY):
		if not ask("No user key was found, generate?"): return False
		print "Generating user key: %s..." % USERKEY
		sh("openssl genrsa 4096 > %s" % USERKEY)

	# Build CSR
	_baseName = "%s/%s" % (DOMAIN_PATH, domain)
	KEY=_baseName + ".key"
	CSR=_baseName + ".csr"
	CRT=_baseName + ".crt"

	if not path.isfile(KEY):
		print "Generating private key..."
		sh("openssl genrsa 4096 > %s" % KEY)
	else: print "  Existing private key found"

	if not path.isfile(CSR):
		print "Generating certificate signing request (csr)..."
		if with_www:
			print "  Set www=true"
			sh('openssl req -new -sha256 -key %s -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:%s,DNS:www.%s")) > %s' % (KEY, domain, domain, CSR))
		else:
			sh('openssl req -new -sha256 -key %s -subj "/CN=%s" > %s' % (KEY, domain, CSR))
	else: print "  Existing CSR found."

	if isNew and interactive:
		print
		print "At this point, make sure your web server is correctly set up"
		print "to point the the challenge directory:"

		print "http://%s/.well-known/acme-challenge/ -> %s" % (domain, CHALLENGE_PATH)
		try: raw_input("[Press enter to continue]")
		except: return False

	# Create certificate
	try:
		crtData = acme_tiny.get_crt(USERKEY, CSR, CHALLENGE_PATH)
		open(CRT, 'w').write(crtData)
	except Exception as e:
		print "Error getting certificate"
		print e
		return False

	# Concat and output certs to /etc/certs
	if not path.isdir(OUT_PATH):
		os.mkdir(OUT_PATH)

	OUT = path.join(OUT_PATH, domain + ".pem")

	print "Writing full key to %s..." % OUT
	FULL_KEY = open(KEY).read() + open(CRT).read() + intermediateKey
	open(OUT, 'w').write(FULL_KEY)

	return True
예제 #8
0
def createOrRenew(domain,
                  userkey="keys/user.key",
                  with_www=False,
                  interactive=False,
                  renewalOnly=False):
    DOMAIN_PATH = path.join(STORE_PATH, "keys", domain)
    CHALLENGE_PATH = path.join(STORE_PATH, "challenges", domain)
    isNew = False

    print "Domain: %s" % domain

    if interactive:
        if not ask("Proceed?"): return False

    if not path.isdir(DOMAIN_PATH):
        if renewalOnly:
            print "Set to renewal only, refusing to create new key"
            return False

        print "Directory not found, creating..."
        os.mkdir(DOMAIN_PATH)
        isNew = True

    if not path.isdir(CHALLENGE_PATH):
        print "Creating challenge dir..."
        os.mkdir(CHALLENGE_PATH)
        isNew = True

    #Fetch intermediate
    print "Downloading intermediate certificate..."
    intermediateKey = getHttp(INTERMEDIATE_KEY_URL)
    if not intermediateKey:
        print "Failed to download intermediate certificate"
        return False

    # Check for user key
    if not path.isfile(USERKEY):
        if not ask("No user key was found, generate?"): return False
        print "Generating user key: %s..." % USERKEY
        sh("openssl genrsa 4096 > %s" % USERKEY)

    # Build CSR
    _baseName = "%s/%s" % (DOMAIN_PATH, domain)
    KEY = _baseName + ".key"
    CSR = _baseName + ".csr"
    CRT = _baseName + ".crt"

    if not path.isfile(KEY):
        print "Generating private key..."
        sh("openssl genrsa 4096 > %s" % KEY)
    else:
        print "  Existing private key found"

    if not path.isfile(CSR):
        print "Generating certificate signing request (csr)..."
        if with_www:
            print "  Set www=true"
            sh('openssl req -new -sha256 -key %s -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:%s,DNS:www.%s")) > %s'
               % (KEY, domain, domain, CSR))
        else:
            sh('openssl req -new -sha256 -key %s -subj "/CN=%s" > %s' %
               (KEY, domain, CSR))
    else:
        print "  Existing CSR found."

    if isNew and interactive:
        print
        print "At this point, make sure your web server is correctly set up"
        print "to point the the challenge directory:"

        print "http://%s/.well-known/acme-challenge/ -> %s" % (domain,
                                                               CHALLENGE_PATH)
        try:
            raw_input("[Press enter to continue]")
        except:
            return False

    # Create certificate
    try:
        crtData = acme_tiny.get_crt(USERKEY, CSR, CHALLENGE_PATH)
        open(CRT, 'w').write(crtData)
    except Exception as e:
        print "Error getting certificate"
        print e
        return False

    # Concat and output certs to /etc/certs
    if not path.isdir(OUT_PATH):
        os.mkdir(OUT_PATH)

    OUT = path.join(OUT_PATH, domain + ".pem")

    print "Writing full key to %s..." % OUT
    FULL_KEY = open(KEY).read() + open(CRT).read() + intermediateKey
    open(OUT, 'w').write(FULL_KEY)

    return True
    def sign_cert(self):
        """
        Sign a certificate for the given domain and csr file
        """

        import acme_tiny

        self.cert_directory = "{}{}".format(self.conf['CERT_DIR'], self.domain)

        sign_args = [
            sys.executable, self.conf["ACME_TINY"], '--account-key',
            self.conf["ACCOUNT_KEY"], '--csr', self.csr_file, '--acme-dir',
            self.conf["CHALLENGE_FOLDER"]
        ]

        if self.conf['STAGING_ONLY']:
            sign_args += ["--ca", self.conf["STAGING_CA"]]

        logging.debug(
            ('Requesting signed certificate for {} with the equivalent for ' +
             'the following command:\n\t$ {}').format(self.domain,
                                                      " ".join(sign_args)))

        if not self.conf['DRY_RUN']:
            # if we are doing a real run, create a backup for writing new crt
            if (os.path.exists(self.crt_file)
                    and not os.path.exists(self.crt_file + '_backup')
                    and not self.conf['STAGING_ONLY']):
                shutil.copyfile(self.crt_file, self.crt_file + '_backup')

            # Do not override crts with staging_only crts
            if self.conf['STAGING_ONLY']:
                crt = "{}/{}_staging.crt".format(self.cert_directory,
                                                 self.domain)
            else:
                crt = "{}/{}.crt".format(self.cert_directory, self.domain)

            # Handoff to acme-tiny
            try:
                if self.conf['STAGING_ONLY']:
                    cert = acme_tiny.get_crt(self.conf["ACCOUNT_KEY"],
                                             self.csr_file,
                                             self.conf["CHALLENGE_FOLDER"],
                                             CA=self.conf["STAGING_CA"])
                else:
                    cert = acme_tiny.get_crt(self.conf["ACCOUNT_KEY"],
                                             self.csr_file,
                                             self.conf["CHALLENGE_FOLDER"])

                # Write the actual cert-file
                with open(crt, 'w') as cert_file:
                    cert_file.write(cert)
                    # If there is an intermediate/chain cert, append it
                    # This is necessary for nginx and does not hurt apache-uses
                    if os.path.exists(self.conf['CHAIN_CERT']):
                        fp = open(self.conf['CHAIN_CERT'], 'r')
                        intermediate = fp.read()
                        cert_file.write(intermediate)
                        fp.close()

            except IOError as err:
                logging.debug("Error: Permission denied: " + err.filename)
                raise LetsEncryptFatalException(
                    "Could not write into the acme-challange " +
                    "folder (rerun with -v for debug information)")
            except Exception as err:
                logging.debug("Error: " + err.message)
                if 'urn:acme:error:rateLimited' in err.message:
                    raise LetsEncryptRateLimitException(
                        "Rate Limit encountered")
                elif 'Wrote file to' in err.message:
                    raise LetsEncryptFatalException(
                        "Acme-challange folder was not accessible from " +
                        "the web (rerun with -v for debug information)")
                else:
                    raise LetsEncryptGenericException(
                        "Certificate Signing Error:\n\t{}".format(err))

                # If we were successful, remove the backup crt
                if os.path.exists(self.crt_file + '_backup'):
                    os.remove(self.crt_file + '_backup')
        else:
            logging.debug("Dry-Run requested, command not executed!")