示例#1
0
def update_apache_config(site):
    vhost = site['VHost']
    server_name = site['ServerName']
    Logger.info('Updating Apache configuration for virtual host at {}{}'.format(
        vhost, ', {}'.format(server_name) if server_name else ''))
    default_cert_path = apache_util.get_apache_ssl_cert_path(vhost, server_name)
    default_key_path = apache_util.get_apache_ssl_key_path(vhost, server_name)
    current_cert_path = apache_util.get_apache_vhost_directive(
        vhost, server_name, 'SSLCertificateFile')
    current_key_path = apache_util.get_apache_vhost_directive(
        vhost, server_name, 'SSLCertificateKeyFile')

    if current_cert_path != default_cert_path:
        apache_util.set_apache_vhost_directive(
            vhost,
            server_name,
            'SSLCertificateFile',
            default_cert_path)

    if current_key_path != default_key_path:
        apache_util.set_apache_vhost_directive(
            vhost,
            server_name,
            'SSLCertificateKeyFile',
            default_key_path)
def is_cert_renewal_needed(site):
    vhost = site['VHost']
    server_name = site.get('ServerName')

    if (not os.path.isfile(
            apache_util.get_apache_ssl_cert_path(
                vhost, server_name))) or (not os.path.isfile(
                    apache_util.get_apache_ssl_key_path(vhost, server_name))):
        Logger.info(
            "Certificate for {} {} does not exist and needs renewal".format(
                vhost, server_name or ''))
        return True

    host, port = apache_util.parse_connection_address_from_vhost(vhost)
    try:
        pem_cert = ssl.get_server_certificate((host, port))
    except socket.error as e:
        raise Exception(
            'Could not retrieve server certificate from "{}:{}": {}'.format(
                host, port, e))

    # Check whether the cert is expired
    cert_expired, cert_expiration_utc = util.is_cert_expired(
        pem_cert, vhost, site['KeyTalkProvider'], site['KeyTalkService'],
        Logger)
    if cert_expired:
        Logger.info(
            "Certificate for {} {} effectively expires at {} UTC and needs renewal"
            .format(vhost, server_name or '', cert_expiration_utc))
        return True

    # Check whether the cert is revoked
    if util.is_cert_revoked(pem_cert, Logger):
        Logger.info(
            "Certificate for {} {} has been revoked and needs renewal".format(
                vhost, server_name or ''))
        return True

    # The cert doesn't need renewal
    Logger.info(
        "Certificate for {} {} effectively expires at {} UTC and does not require renewal (run with {} to renew anyway)"
        .format(vhost, server_name or '', cert_expiration_utc, force_arg))
    return False
def install_apache_ssl_cert(pem_cert_key_path, site, restart_apache=False):
    vhost = site['VHost']
    Logger.info(
        'Installing SSL certificate for virtual host at {VHost}'.format(
            **site))

    server_name = site['ServerName']
    ssl_cert_path = apache_util.get_apache_ssl_cert_path(vhost, server_name)
    ssl_key_path = apache_util.get_apache_ssl_key_path(vhost, server_name)

    certs = util.parse_certs(pem_cert_key_path, Logger)
    if not certs:
        raise Exception(
            "No X.509 certs found in {} received by KeyTalk client".format(
                pem_cert_key_path))
    keys = util.parse_keys(pem_cert_key_path, Logger)
    if not keys:
        raise Exception(
            "No X.509 keys found in {} received by KeyTalk client".format(
                pem_cert_key_path))
    cas = util.parse_cas(Logger)

    if util.same_file(ssl_cert_path, ssl_key_path):
        Logger.debug("Saving SSL certificate with key and {} CAs to {}".format(
            len(cas), ssl_cert_path))
        util.save_to_file('\n'.join(certs + keys + cas), ssl_cert_path)
    else:
        Logger.debug(
            "Saving SSL certificates (serial: {}) and {} CAs to {}".format(
                OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
                                                certs[0]).get_serial_number(),
                len(cas), ssl_cert_path))
        util.save_to_file('\n'.join(certs + cas), ssl_cert_path)
        Logger.debug("Saving SSL key to " + ssl_key_path)
        util.save_to_file('\n'.join(keys), ssl_key_path)

    # ask Apache to gracefully reload key material
    if restart_apache:
        reload_apache()
def process_vhost(site_configuration, current_vhost_string, current_vhost_name,
                  apache_vhosts, force_renew_certs):
    global error_messages
    global warning_messages

    current_site = site_configuration
    try:
        # Validation
        parsed_site, validation_errors = util.parse_settings(
            current_site, util.APACHE_RENEWAL_SETTINGS)
        # parsed_site either contains correctly parsed site settings with populated defaults or None (and a non-empty validation error list).
        # Even if parsing failed, we want to present the user with a complete error list. So for purposes of further validation
        # we fill current_site at least defined values (e.g. None) using
        # populate_defaults such that validate_site_configuration can is able to
        # do its checks.
        current_site = parsed_site or util.populate_defaults(
            current_site, util.APACHE_RENEWAL_SETTINGS)

        validation_errors.extend(
            validate_site_configuration(current_site, apache_vhosts.keys()))
        if validation_errors:
            message = make_validation_error_message(validation_errors,
                                                    current_vhost_string)
            log_error(message)
            raise Exception(
                'Errors during validation of VHost "{}, {}".'.format(
                    current_vhost_string, current_vhost_name))

        # Processing
        if not apache_util.is_apache_running():
            if (not os.path.isfile(
                    apache_util.get_apache_ssl_cert_path(
                        current_vhost_string,
                        current_vhost_name))) or (not os.path.isfile(
                            apache_util.get_apache_ssl_key_path(
                                current_vhost_string, current_vhost_name))):
                log_warning(
                    'Apache is not running, but certificate/keyfile missing. Attempting to correct. Note: this will not restart apache.'
                )
                pem_cert_key_path = get_cert(current_site)
                install_apache_ssl_cert(pem_cert_key_path, current_site)
                email_results(current_site)
                return True
            else:
                raise Exception(
                    'Apache is not running, skipping certificate update for VHost {} {}.'
                    .format(current_vhost_string, current_vhost_name))

        update_apache_config(current_site)
        if force_renew_certs or is_cert_renewal_needed(current_site):
            pem_cert_key_path = get_cert(current_site)
            install_apache_ssl_cert(pem_cert_key_path, current_site)
    except Exception as e:
        # Log error, but continue processing the next VHost
        log_error(
            'VHost "{}, {}": {} {} {}'.format(current_vhost_string,
                                              current_vhost_name, type(e), e,
                                              util.format_traceback()),
            'VHost "{}, {}": {} {}'.format(current_vhost_string,
                                           current_vhost_name, type(e), e))
        return False
    finally:
        email_results(current_site)
        error_messages = []
        warning_messages = []

    return True