Exemplo n.º 1
0
def test_deploy(ssl_manager):
    key_path, crt_path = tests_util.create_autossl_signed_cert(
        ssl_blueprint=ssl_manager.ssl_blueprint,
        output_folder=os.environ['AUTOSSL_STORAGE_PATH'],
    )

    # deploy them on server
    ssl_manager.deploy(certificate_path=crt_path, private_key_path=key_path)

    to_be_renewed, servers_to_update = ssl_manager.get_renewal_status()
    assert to_be_renewed is False
    assert len(servers_to_update) == 0

    # ensure first server contain only server certificate
    crt_path_server_1 = util.Path(os.environ['AUTOSSL_CRT_PATH']).joinpath(
        ssl_manager.ssl_blueprint.name + '.crt')
    assert crt_path_server_1.read_text().count(
        '-----BEGIN CERTIFICATE-----') == 1
    assert crt_path_server_1.read_bytes() == crt_path.read_bytes()

    # and 2nd server contains certificate with full chain of trust (2 certificates)
    crt_path_server_2 = util.Path(os.environ['AUTOSSL_CRT_PATH_2']).joinpath(
        ssl_manager.ssl_blueprint.name + '.crt')
    crt_server_2_content = crt_path_server_2.read_text()
    # we should have 2 certificates: server + CA certificates
    assert crt_server_2_content.count('-----BEGIN CERTIFICATE-----') == 2
    # retrieve server certificate (= the first one) and verify it
    first_certificate = '-----BEGIN CERTIFICATE-----' + crt_server_2_content.split(
        '-----BEGIN CERTIFICATE-----')[1]
    assert first_certificate.strip() == crt_path.read_text().strip()
Exemplo n.º 2
0
def env_config():
    # create temporary directories use by blueprint
    temp_crt_dir = tempfile.mkdtemp()
    os.environ['AUTOSSL_CRT_PATH'] = temp_crt_dir
    temp_storage_dir = tempfile.mkdtemp()
    os.environ['AUTOSSL_STORAGE_PATH'] = temp_storage_dir
    temp_tracking_dir = tempfile.mkdtemp()
    os.environ['AUTOSSL_TRACKING_PATH'] = temp_tracking_dir

    yield EnvConfig(util.Path(temp_crt_dir), util.Path(temp_storage_dir),
                    util.Path(temp_tracking_dir))

    # cleanup generated artifacts
    shutil.rmtree(temp_crt_dir, ignore_errors=True)
    shutil.rmtree(temp_storage_dir, ignore_errors=True)
Exemplo n.º 3
0
def create_self_signed_certificate(crt_name,
                                   output_path,
                                   common_name,
                                   sans=None,
                                   certificate_validity_days=365):
    """Generate self signed SSL certificate
    :param crt_name: name of file generated (without extension)
    :type crt_name: str
    :param output_path: ouput directory to generate certificate
    :type output_path: pathlib.Path or str
    :param common_name: certificate common name
    :type common_name: str
    :param sans: certificate alternate names
    :type sans: list
    :param certificate_validity_days: validity duration of certificate in days
    :type certificate_validity_days: int
    """
    if not isinstance(output_path, util.Path):
        output_path = util.Path(str(output_path))
    key_path = output_path.joinpath(crt_name + '.key')
    key_content, csr_path = ssl.generate_csr(name=crt_name,
                                             common_name=common_name,
                                             sans=sans,
                                             output_path=output_path)
    crt_path = output_path.joinpath(crt_name + '.crt')
    crt_content = create_signed_certificate(
        csr_path=csr_path,
        certificate_validity_days=certificate_validity_days,
    )
    crt_path.write_bytes(crt_content)
    key_path.write_bytes(key_content)

    return key_path, crt_path
Exemplo n.º 4
0
def ca_keypair_path():
    key, crt = tests_util.create_ca_certificate(ca_name='Autossl')
    ca_temp_dir = util.Path(tempfile.mkdtemp())
    ca_crt_path = ca_temp_dir / 'local_ca.crt'
    ca_key_path = ca_temp_dir / 'local_ca.key'

    ca_crt_path.write_bytes(crt)
    ca_key_path.write_bytes(key)

    yield CertificateKeyPair(ca_key_path, ca_crt_path)

    # cleanup temp folders
    shutil.rmtree(str(ca_temp_dir), ignore_errors=True)
Exemplo n.º 5
0
def subca_keypair_path(subca_manager, ca_keypair_path):
    storage_path = util.Path(os.environ['AUTOSSL_STORAGE_PATH'])
    key_path = storage_path.joinpath(subca_manager.ssl_blueprint.name + '.key')
    csr_path = storage_path.joinpath(subca_manager.ssl_blueprint.name + '.csr')
    crt_path = storage_path.joinpath(subca_manager.ssl_blueprint.name + '.crt')
    bundle_path = storage_path.joinpath(subca_manager.ssl_blueprint.name +
                                        '.bundle')

    # generate sub-CA certificate request and key
    subca_manager.request_renewal(
        force=True,  # disable interactive user input
    )

    # simulate CA signing
    crt_content = tests_util.create_signed_certificate(
        csr_path=csr_path,
        ca_crt_path=ca_keypair_path.crt,
        ca_key_path=ca_keypair_path.key,
        certificate_validity_days=100)
    crt_path.write_bytes(crt_content)
    bundle_path.write_bytes(ca_keypair_path.crt.read_bytes() + crt_content)

    yield CertificateKeyPair(key_path, crt_path)
Exemplo n.º 6
0
def create_autossl_signed_cert(ssl_blueprint, output_folder):
    """Create certificate signed by Autossl CA for specified blueprint and in specified location

    :param ssl_blueprint: SSL blueprint for which to generate certificate
    :type ssl_blueprint: ssl.SslBlueprint
    :param output_folder: local folder where to generate new key and signed certificate
    :type output_folder: pathlib.Path
    :return: 2-tuple(local path to private key, local path to signed certificate)
    :rtype: tuple(pathlib.Path, pathlib.Path)
    """
    if not isinstance(output_folder, util.Path):
        output_folder = util.Path(output_folder)

    ca_crt_path = DATA_PATH / 'ca' / 'autossl_ca.crt'
    ca_key_path = DATA_PATH / 'ca' / 'autossl_ca.key'

    crt_path = output_folder.joinpath(ssl_blueprint.name + '.crt')
    key_path = output_folder.joinpath(ssl_blueprint.name + '.key')

    # generate new CSR
    key_content, csr_path = ssl.generate_csr(
        name=ssl_blueprint.name,
        common_name=ssl_blueprint.certificate.common_name,
        sans=ssl_blueprint.certificate.sans,
        output_path=output_folder,
    )
    key_path.write_bytes(key_content)

    # sign a new certificate with the CA
    crt_content = create_signed_certificate(
        csr_path=csr_path,
        ca_crt_path=ca_crt_path,
        ca_key_path=ca_key_path,
    )
    crt_path.write_bytes(crt_content)

    return key_path, crt_path
Exemplo n.º 7
0
def parse_arguments(args=None):
    parser = argparse.ArgumentParser(description=autossl.__description__)

    parser.add_argument(
        '--credentials',
        action='append',
        default=[],
        help='Generic user/password credentials. Format: name:user:password')

    parser.add_argument('--credentials-file',
                        type=util.Path,
                        default=util.Path('~/.autossl').expanduser(),
                        help='Local file to store credentials.')

    parser.add_argument('--debug',
                        action="store_const",
                        const=logging.DEBUG,
                        default=logging.INFO,
                        help='Use DEBUG log level rather than INFO')

    parser.add_argument(
        "--staging",
        action='store_true',
        help="Testing mode (for example, use staging CA servers)")

    parser.add_argument(
        "--config",
        type=util.Path,
        help=
        "Path to a file containing common configuration. Same format than SSL blueprint."
    )

    parser.add_argument(
        "--blueprint",
        required=False,
        type=util.Path,
        help=
        "Path to the definition of certificates. Can be single blueprint or a folder"
    )

    action_subparser = parser.add_subparsers(title="action", dest="action")
    action_subparser.required = True  # needed for python3 compatibility

    ################
    # VERSION
    ################
    action_subparser.add_parser("version",
                                help="Display autossl current version")

    ########################################
    # Parser to check if certificate needs to be renewed
    ########################################
    action_subparser.add_parser("check", help="Check for expired certificate.")

    ########################################
    # Parser to request certificate renewal
    ########################################
    action_parser_renew = action_subparser.add_parser(
        "renew", help="Request certificate renewal")
    action_parser_renew.add_argument(
        "--force",
        action='store_true',
        help="Renew certificate now (even if current one is still valid)")

    ########################################
    # Parser to deploy certificate on server
    ########################################
    action_parser_deploy = action_subparser.add_parser(
        "deploy", help="Deploy certificate")
    action_parser_deploy.add_argument(
        '-t',
        '--tracking-record',
        help='Tracking record ID for the change, '
        'and also potentially containing certificate to deploy.')
    action_parser_deploy.add_argument(
        '-k',
        '--private-key',
        type=util.Path,
        help='Local path to certificate private key')
    action_parser_deploy.add_argument(
        '-c',
        '--certificate',
        type=util.Path,
        help='Local path to ssl signed certificate')
    action_parser_deploy.add_argument(
        '--all-servers',
        action='store_true',
        default=False,
        help=
        'Deploy certificate on all servers rather than just the ones out of synch.'
    )

    return parser.parse_args(args)
Exemplo n.º 8
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]

    options = parse_arguments(args=args)

    logger.setLevel(options.debug or logger.level)

    # this is the only action that does not require authentication
    if options.action == "version":
        print(display_version())
        return

    # actions that can be done on multiple blueprints
    if options.action in ['check', 'renew']:

        # build list of all blueprints to process
        blueprints = []
        if options.blueprint.is_file():
            blueprints.append(options.blueprint)
        elif options.blueprint.is_dir():
            for root_path, _, filenames in os.walk(options.blueprint):
                for filename in fnmatch.filter(filenames, '*.yaml'):
                    blueprints.append(util.Path(root_path) / filename)
        else:
            raise IOError("Invalid path specified: '%s'" % options.blueprint)

        # process blueprints 1 by 1
        for blueprint in blueprints:

            my_ssl_manager = manager.SslManager(
                global_config=options.config,
                blueprint_path=blueprint,
                credentials=parse_credentials(
                    cli_credentials=options.credentials,
                    credentials_file=options.credentials_file,
                ),
                staging=options.staging,
            )
            if options.action == 'check':
                logger.info("Processing blueprint %s" % blueprint)
                to_be_renewed, servers_to_update = my_ssl_manager.get_renewal_status(
                )
                if not to_be_renewed and len(servers_to_update) == 0:
                    logger.info(
                        "Certificate and all servers up to date for '%s'. Nothing to do.",
                        my_ssl_manager.ssl_blueprint.name)
            elif options.action == 'renew':
                my_ssl_manager.renew(force=options.force)

    # action on a single blueprint
    elif options.action == 'deploy':

        my_ssl_manager = manager.SslManager(
            global_config=options.config,
            blueprint_path=options.blueprint,
            credentials=parse_credentials(
                cli_credentials=options.credentials,
                credentials_file=options.credentials_file),
            staging=options.staging,
        )

        my_ssl_manager.deploy(
            tracking_record_id=options.tracking_record,
            certificate_path=options.certificate,
            private_key_path=options.private_key,
            all_servers=options.all_servers,
        )
Exemplo n.º 9
0
# functions to help testing and made available for use in autossl plugins

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
from cryptography import x509
import datetime
import random
import string

from autossl import ssl, util

DATA_PATH = util.Path(__file__).parent.joinpath('data')


def create_ca_certificate(ca_name,
                          key_size=4096,
                          certificate_validity_days=365):
    key = rsa.generate_private_key(public_exponent=65537,
                                   key_size=key_size,
                                   backend=default_backend())
    key_id = x509.SubjectKeyIdentifier.from_public_key(key.public_key())

    subject = issuer = x509.Name(
        [x509.NameAttribute(NameOID.COMMON_NAME, u"%s" % ca_name)])

    now = datetime.datetime.utcnow()
    serial = x509.random_serial_number()
    cert = x509.CertificateBuilder() \
        .subject_name(subject) \
Exemplo n.º 10
0
import base64
import collections
import datetime
import json
try:
    from unittest import mock  # py3
except ImportError:
    import mock  # py2
import pytest

from autossl import exception, ssl, util
from autossl.server import incapsula

from tests import util as tests_util

DATA_PATH = util.Path(__file__).parent / 'data'

CertificateKeyPair = collections.namedtuple('CertificateKeyPair', 'key crt')
SITE_ID = '12345678'
API_KEY = '6f4d1878-f2c6-446b-8932-636b8f1705a7'
API_ID = '12345'
CHAIN_OF_TRUST = [
    """"-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/MSQwIgYDVQQK
ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
DTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0NlowSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxl
dCdzIEVuY3J5cHQxIzAhBgNVBAMTGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4
S0EFq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8SMx+yk13
EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0Z8h/pZq4UmEUEz9l6YKH
y9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWAa6xK8xuQSXgvopZPKiAlKQTGdMDQMc2P
Exemplo n.º 11
0
from autossl import util
from autossl.server.local import LocalServer


@pytest.mark.parametrize('class_path, exception_type', [
    ('MyClass', ValueError),
    ('my.package.does.not.exist.MyClass', ImportError),
    ('autossl.server.local.Dummy', AttributeError),
])
def test_str_to_class_error(class_path, exception_type):
    with pytest.raises(exception_type):
        util.str_to_class(class_path=class_path)


@pytest.mark.parametrize('class_path,class_type', [
    ('autossl.server.local.LocalServer', LocalServer),
])
def test_str_to_class(class_path, class_type):
    assert util.str_to_class(class_path=class_path) == class_type


@pytest.mark.parametrize('path', [
    None,
    util.Path(tempfile.mkdtemp())
])
def test_TempDir(path):
    with util.TempDir(path=path) as temp_folder:
        assert temp_folder.path.exists()
    assert not temp_folder.path.exists()