示例#1
0
def acme_from_config_key(config, key):
    "Wrangle ACME client construction"
    # TODO: Allow for other alg types besides RS256
    net = acme_client.ClientNetwork(key,
                                    verify_ssl=(not config.no_verify_ssl),
                                    user_agent=_determine_user_agent(config))
    return acme_client.Client(config.server, key=key, net=net)
示例#2
0
def lambda_handler(event, context):
    bucket = event['bucket']
    region = event['region']

    LOG.info(
        "Retrieving configuration file from bucket '{0}' in region '{1}' ".
        format(bucket, region))
    connection = s3.connect_to_region(region,
                                      calling_format=OrdinaryCallingFormat())
    try:
        bucket = connection.get_bucket(bucket)
    except S3ResponseError as e:
        print(e)
        LOG.error("Cannot fetch bucket : {}".format(bucket))
        exit(1)

    conf = load_config(bucket)
    if conf == None:
        LOG.error("Cannot find file 'letslambda.yml' in S3 bucket '{0}".format(
            bucket))
        exit(1)

    key = loadAccountKey(bucket, conf)
    acme_client = client.Client(conf['directory'], key)
    for domain in conf['domains']:
        authorization_resource = get_authorization(acme_client, domain)
        challenge = get_dns_challenge(authorization_resource)
        answer_dns_challenge(acme_client, domain, challenge)
        (certificate, key) = requestCertificate(acme_client, bucket, domain,
                                                authorization_resource)
        iam_cert = createIAMCertificate(domain, certificate, key)
        updateELB(domain, iam_cert)
示例#3
0
def test_revoke_by_privkey():
    client = make_client(None)
    domains = [random_domain()]
    key = OpenSSL.crypto.PKey()
    key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
    key_pem = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)
    csr_pem = acme_crypto_util.make_csr(key_pem, domains, False)
    order = client.new_order(csr_pem)
    cleanup = do_http_challenges(client, order.authorizations)
    try:
        order = client.poll_order_and_request_issuance(order)
    finally:
        cleanup()

    # Create a new client with the JWK as the cert private key
    jwk = jose.JWKRSA(key=key)
    net = acme_client.ClientNetwork(key,
                                    acme_version=2,
                                    user_agent="Boulder integration tester")

    new_client = acme_client.Client(os.getenv(
        'DIRECTORY', 'http://localhost:4001/directory'),
                                    key=jwk,
                                    net=net,
                                    acme_version=2)

    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
                                           order.fullchain_pem)
    client.revoke(jose.ComparableX509(cert), 0)
示例#4
0
def main():
    if sys.argv[1] == 'staging':
        directory = 'https://acme-staging.api.letsencrypt.org/directory'
    else:
        directory = 'https://acme-v01.api.letsencrypt.org/directory'

    key = josepy.JWKRSA(key=serialization.load_pem_private_key(
       sys.stdin.read(),
       password=None,
       backend=default_backend())
    )

    net = acme_client.ClientNetwork(key)

    client = acme_client.Client(
        directory=directory,
        key=key,
        net=net
    )

    new_reg = messages.NewRegistration.from_data(
        email=sys.argv[2]
    )

    acct = None
    try:
        regr = client.register(new_reg)
    except errors.ConflictError as e: 
        acct = e.location

    print(json.dumps({'body': {}, 'uri': acct}))
示例#5
0
def MakeACMEJOSEKey():
	path = os.path.join(KEY_FOLDER, "private_key.json")
	textfile = open(path,'r')
	filetext = textfile.read()
	textfile.close()
	global KEY 
	KEY = jose.JWK.json_loads(filetext)
	global ACME_CLIENT
	ACME_CLIENT = client.Client(PRODUCTION_CA+'directory', KEY)
示例#6
0
文件: le.py 项目: vfiebig/rpaas
def _revoke(rawkey, rawcert):
    ns = ConfigNamespace(None)
    acme = acme_client.Client(
        ns.server,
        key=JWKRSA(key=serialization.load_pem_private_key(
            rawkey, password=None, backend=default_backend())))
    acme.revoke(
        jose.ComparableX509(
            OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
                                            rawcert)))
示例#7
0
def make_client(email=None):
    """Build an acme.Client and register a new account with a random key."""
    key = josepy.JWKRSA(key=rsa.generate_private_key(65537, 2048, default_backend()))

    net = acme_client.ClientNetwork(key, user_agent="Boulder integration tester")

    client = acme_client.Client(DIRECTORY, key=key, net=net)
    account = client.register(messages.NewRegistration.from_data(email=email))
    client.agree_to_tos(account)
    client.account = account
    return client
示例#8
0
def registerNewAccount(conf, key):
    """
    Attempt to create a new account on the ACME server
    with the key. No problem if it fails because this
    kye is already used.
    """
    LOG.info("Registering with ACME server with the new key")
    newReg = messages.NewRegistration(contact=tuple(conf['info']),
                                      key=key.public_key())
    acme_client = client.Client(conf['directory'], key)
    registration_resource = acme_client.register(newReg)
    LOG.info("Agreeing on the TOS on your behalf")
    acme_client.agree_to_tos(registration_resource)
示例#9
0
    def action_register(self):
        if not self.key:
            self._generate_key
        key = self._deserialize_key(self.key)

        acme = client.Client(DIRECTORY_URL, key)
        regr = acme.register()
        self.tos_text = regr.terms_of_service
        acme.agree_to_tos(regr)
        self.tos = True

        self.state = "cert"
        return self.tos
示例#10
0
文件: cli.py 项目: tkfu/letsencrypt
def revoke(args, config, unused_plugins):  # TODO: coop with renewal config
    """Revoke a previously obtained certificate."""
    if args.key_path is not None:  # revocation by cert key
        logger.debug("Revoking %s using cert key %s",
                     args.cert_path[0], args.key_path[0])
        acme = acme_client.Client(
            config.server, key=jose.JWK.load(args.key_path[1]))
    else:  # revocation by account key
        logger.debug("Revoking %s using Account Key", args.cert_path[0])
        acc, _ = _determine_account(args, config)
        # pylint: disable=protected-access
        acme = client._acme_from_config_key(config, acc.key)
    acme.revoke(jose.ComparableX509(crypto_util.pyopenssl_load_certificate(
        args.cert_path[1])[0]))
示例#11
0
    def __init__(self, installer, config, no_confirm=False):
        # XXX
        self.acme = acme_client.Client(new_reg_uri=None, key=None, alg=None)

        self.installer = installer
        self.config = config
        self.no_confirm = no_confirm

        le_util.make_or_verify_dir(config.cert_key_backup, 0o700, os.geteuid())

        # TODO: Find a better solution for this...
        self.list_path = os.path.join(config.cert_key_backup, "LIST")
        # Make sure that the file is available for use for rest of class
        open(self.list_path, "a").close()
示例#12
0
文件: wile.py 项目: lumatijev/wile
def wile(obj, directory_url, staging, account_key_path, new_account_key_size, verbose):
    if verbose > 1:
        logging.basicConfig(level=logging.DEBUG)
    elif verbose > 0:
        logging.basicConfig(level=logging.INFO)
    else:
        logging.basicConfig(level=logging.WARNING)

    if staging:
        directory_url = 'https://acme-staging.api.letsencrypt.org/directory'
    account_key = get_or_gen_key(account_key_path, new_account_key_size)

    logger.debug('connecting to ACME directory at %s' % directory_url)
    obj['account_key'] = account_key
    obj['acme'] = client.Client(directory_url, account_key)
示例#13
0
def make_client(email=None):
    """Build an acme.Client and register a new account with a random key."""
    key = josepy.JWKRSA(key=rsa.generate_private_key(65537, 2048, default_backend()))

    net = acme_client.ClientNetwork(key, acme_version=2,
                                    user_agent="Boulder integration tester")

    client = acme_client.Client(DIRECTORY, key=key, net=net, acme_version=2)
    tos = client.directory.meta.terms_of_service
    if tos == ACCEPTABLE_TOS:
        net.account = client.register(messages.NewRegistration.from_data(email=email,
            terms_of_service_agreed=True))
    else:
        raise Exception("Unrecognized terms of service URL %s" % tos)
    return client
示例#14
0
文件: ca.py 项目: aracloud/bigacme
 def __init__(self, configuration, test=False):
     if test:
         self.key = None
     else:
         with open(configuration.cm_key, "r") as key_file:
             private_key = serialization.load_pem_private_key(
                 key_file.read(),
                 password=None,
                 backend=default_backend()
                 )
         self.key = jose.JWKRSA(key=private_key)
     user_agent = 'bigacme (https://github.com/magnuswatn/bigacme/)'
     network = client.ClientNetwork(self.key, user_agent=user_agent)
     network.session.proxies = {'https': configuration.ca_proxy}
     acme_client = client.Client(directory=configuration.ca, key=self.key, net=network)
     self.client = acme_client
示例#15
0
def make_client(email=None):
    """Build an acme.Client and register a new account with a random key."""
    key = jose.JWKRSA(
        key=rsa.generate_private_key(65537, 2048, default_backend()))

    net = acme_client.ClientNetwork(key,
                                    verify_ssl=False,
                                    user_agent="Boulder integration tester")

    client = acme_client.Client(DIRECTORY, key=key, net=net)
    tos = client.directory.meta.terms_of_service
    if tos is not None and "Do%20what%20thou%20wilt" in tos:
        net.account = client.register(
            messages.NewRegistration.from_data(email=email,
                                               terms_of_service_agreed=True))
    else:
        raise Exception("Unrecognized terms of service URL %s" % tos)
    return client
示例#16
0
from acme import messages


logging.basicConfig(level=logging.DEBUG)


DIRECTORY_URL = 'https://acme-staging.api.letsencrypt.org/directory'
BITS = 2048  # minimum for Boulder
DOMAIN = 'example1.com'  # example.com is ignored by Boulder

# generate_private_key requires cryptography>=0.5
key = jose.JWKRSA(key=rsa.generate_private_key(
    public_exponent=65537,
    key_size=BITS,
    backend=default_backend()))
acme = client.Client(DIRECTORY_URL, key)

regr = acme.register()
logging.info('Auto-accepting TOS: %s', regr.terms_of_service)
acme.agree_to_tos(regr)
logging.debug(regr)

authzr = acme.request_challenges(
    identifier=messages.Identifier(typ=messages.IDENTIFIER_FQDN, value=DOMAIN))
logging.debug(authzr)

authzr, authzr_response = acme.poll(authzr)

csr = OpenSSL.crypto.load_certificate_request(
    OpenSSL.crypto.FILETYPE_ASN1, pkg_resources.resource_string(
        'acme', os.path.join('testdata', 'csr.der')))
def request_cert(domain):
    domain = domain.lower()
  
    print("Generating user key")
    user_key = josepy.JWKRSA(
        key=rsa.generate_private_key(
            public_exponent=65537,
            key_size=KEY_SIZE,
            backend=default_backend()
        )
    )

    print("Connecting to Let's Encrypt on {}".format(DIRECTORY_URL))
    acme = client.Client(DIRECTORY_URL, user_key)
    print("Registering")
    regr = acme.register()
    print("Agreeing to ToS")
    acme.agree_to_tos(regr)

    print("Requesting challenges")
    authzr = acme.request_challenges(
        identifier=messages.Identifier(typ=messages.IDENTIFIER_FQDN, value=domain)
    )

    print("Looking for HTTP challenge")
    challenge = get_http_challenge(authzr)

    print("You need to set up the challenge response.")
    print("URL: http://{}{}".format(domain, challenge.chall.path))
    print("Content: {}".format(challenge.chall.validation(user_key)))

    response = challenge.chall.response(user_key)
    while not response.simple_verify(challenge.chall, domain, user_key.public_key()):
        raw_input("It doesn't look like it's set up yet; press return when it is.")

    print("Authorizing -- here goes...")
    auth_response = acme.answer_challenge(challenge, challenge.chall.response(user_key))
    print("Response was {}".format(auth_response))

    print("Waiting for authorization to become valid")
    while True:
        print("Polling")
        authzr, authzr_response = acme.poll(authzr)
        challenge = get_http_challenge(authzr)
        if challenge.status.name == "valid":
            break
        print("HTTP challenge is currently {}".format(challenge))
        time.sleep(1)
    print("Auth valid")

    print("Generating CSR")
    certificate_key = crypto.PKey()
    certificate_key.generate_key(crypto.TYPE_RSA, 2048)
    csr = crypto.X509Req()
    csr.get_subject().CN = domain
    csr.set_pubkey(certificate_key)
    csr.sign(certificate_key, "sha256")

    print("Requesting certificate")
    certificate_response = acme.request_issuance(josepy.util.ComparableX509(csr), [authzr])
    print("Got it!")

    print("Fetching chain")
    chain = acme.fetch_chain(certificate_response)
    print("Done!")

    print("Here are the details:")

    print("Private key:")
    print(crypto.dump_privatekey(FILETYPE_PEM, certificate_key))

    print("Combined cert:")
    print(crypto.dump_certificate(FILETYPE_PEM, certificate_response.body.wrapped))
    for cert in chain:
        print(crypto.dump_certificate(FILETYPE_PEM, cert.wrapped))
示例#18
0
import Crypto.PublicKey.RSA
import M2Crypto

from acme import client
from acme import messages
from acme import jose

logging.basicConfig(level=logging.DEBUG)

NEW_REG_URL = 'https://www.letsencrypt-demo.org/acme/new-reg'
BITS = 2048  # minimum for Boulder
DOMAIN = 'example1.com'  # example.com is ignored by Boulder

key = jose.JWKRSA.load(
    Crypto.PublicKey.RSA.generate(BITS).exportKey(format="PEM"))
acme = client.Client(NEW_REG_URL, key)

regr = acme.register(contact=())
logging.info('Auto-accepting TOS: %s', regr.terms_of_service)
acme.update_registration(
    regr.update(body=regr.body.update(agreement=regr.terms_of_service)))
logging.debug(regr)

authzr = acme.request_challenges(identifier=messages.Identifier(
    typ=messages.IDENTIFIER_FQDN, value=DOMAIN),
                                 new_authzr_uri=regr.new_authzr_uri)
logging.debug(authzr)

authzr, authzr_response = acme.poll(authzr)

csr = M2Crypto.X509.load_request_string(
示例#19
0
def _acme_from_config_key(config, key):
    # TODO: Allow for other alg types besides RS256
    return acme_client.Client(directory=config.server,
                              key=key,
                              verify_ssl=(not config.no_verify_ssl))
示例#20
0
 def get_client(self):
     client = acme_client.Client(self.directory_url, self.get_jwk_key())
     if not self.is_registered:
         self.register_account(client)
     return client
示例#21
0
 def acme(self):
     if not self.__client:
         self.__client = client.Client(self.__directory_url,
                                       self.account_key)
     return self.__client
示例#22
0
def run_acme_reg_to_finish(domain, regr_uri, accnt_key, site_key, csr, tmp_chall_dict, directory_url):
    accnt_key = jose.JWKRSA(key=accnt_key)
    acme = client.Client(directory_url, accnt_key)
    msg = messages.RegistrationResource(uri=regr_uri)
    regr = acme.query_registration(msg)

    log.info('Auto-accepting TOS: %s from: %s', regr.terms_of_service, directory_url)
    acme.agree_to_tos(regr)

    authzr = acme.request_challenges(
        identifier=messages.Identifier(typ=messages.IDENTIFIER_FQDN, value=domain))
    log.debug('Created auth client %s', authzr)

    def get_http_challenge(x, y):
        return y if isinstance(y.chall, challenges.HTTP01) else x

    challb = reduce(get_http_challenge, authzr.body.challenges, None)
    chall_tok = challb.chall.validation(accnt_key)

    v = chall_tok.split('.')[0]
    log.info('Exposing challenge on %s', v)
    tmp_chall_dict.set(v, ChallTok(chall_tok))

    test_path = 'http://localhost:8082{}'.format(challb.path)
    local_req = Request(test_path, headers={'Host': domain})
    log.debug('Testing local url path: %s', test_path)

    try:
        resp = urlopen(local_req)
        t = resp.read().decode('utf-8').strip()
        if t != chall_tok:
            raise ValueError
    except (IOError, ValueError):
        log.info('Resolving challenge locally failed. ACME request will fail. %s', test_path)
        raise

    cr = acme.answer_challenge(challb, challb.chall.response(accnt_key))
    log.debug('Acme CA responded to challenge request with: %s', cr)

    try:
        # Wrap this step and log the failure particularly here because this is
        # the expected point of failure for applications that are not reachable
        # from the public internet.
        cert_res, _ = acme.poll_and_request_issuance(jose.util.ComparableX509(csr), (authzr,))

        # NOTE pylint disabled due to spurious reporting. See docs:
        # https://letsencrypt.readthedocs.io/projects/acme/en/latest/api/jose/util.html#acme.jose.util.ComparableX509
        # pylint: disable=no-member
        cert_str = cert_res.body._dump(FILETYPE_PEM)
    except messages.Error as error:
        log.err("Failed in request issuance step %s", error)
        raise

    chain_certs = acme.fetch_chain(cert_res)

    # The chain certs returned by the LE CA will always have at least one
    # intermediate cert. Other certificate authorities that run ACME may
    # behave differently, but we aren't using them.
    chain_str = dump_certificate(FILETYPE_PEM, chain_certs[0])

    # pylint: disable=no-member
    expr_date = convert_asn1_date(cert_res.body.wrapped.get_notAfter())
    log.info('Retrieved cert using ACME that expires on %s', expr_date)

    return cert_str, chain_str
示例#23
0
def register_account_key(directory_url, accnt_key):
    accnt_key = jose.JWKRSA(key=accnt_key)
    acme = client.Client(directory_url, accnt_key)

    regr = acme.register()
    return regr.uri, regr.terms_of_service
示例#24
0
    def _update(self):
        if not self.dom_key or not self.dom_csr:
            self.state = 'cert'
            return
        if not self.key:
            self.state = 'priv_key'
            return

        k = self._deserialize_key(self.key)
        acme = client.Client(DIRECTORY_URL, k)

        authzr = acme.request_challenges(identifier=messages.Identifier(
            typ=messages.IDENTIFIER_FQDN, value=self.name))

        challb = self._supported_challb(authzr)
        if not challb:
            _logger.warning(
                _("Didn't find any http01 challenge. Just try again."))
            _logger.warning(authzr)
            raise exceptions.Warning(
                _("Didn't find any http01 challenge. Just try again."))
        response, self.challenge_validation = challb.response_and_validation(k)
        self.challenge_path = challb.path.split('/')[-1]

        challenge = Challenge()
        challenge.set_challenge(self.challenge_path, self.challenge_validation)

        _logger.info("Need to response %s on url %s",
                     self.challenge_validation, self.challenge_path)

        # write data to file, because it seems that the data is not written to the database bevor
        # the controller requests it.  So the controller loads it from the file:
        #challenge_file = os.path.join(get_challenge_dir(), self.challenge_path)
        #f = open(challenge_file, 'w')
        #f.write(self.challenge_validation)
        #_logger.info("saved %s to '%s'", self.challenge_validation, challenge_file)

        #self.dom_verified = response.simple_verify(
        #    challb.chall, self.name, acme.key.public_key())
        #f.close()

        #if not self.dom_verified:
        #    _logger.warning('%s was not successfully self-verified. '
        #                   'CA is likely to fail as well!', self.name)
        #            raise exceptions.Warning(_("%s was not successfully self-verified. CA is likely to fail as well!"% self.name))
        #else:
        #    _logger.info('%s was successfully self-verified', self.name)

        # os.unlink(challenge_file)
        # _logger.info("unlinked %s", challenge_file)

        #        authzr, authzr_response = acme.poll(authzr)

        acme.answer_challenge(challb, response)

        csr = OpenSSL.crypto.load_certificate_request(
            OpenSSL.crypto.FILETYPE_PEM, self.dom_csr)

        certr, authzr = acme.poll_and_request_issuance(
            jose.util.ComparableX509(csr), (authzr, ))

        self.cert = OpenSSL.crypto.dump_certificate(
            OpenSSL.crypto.FILETYPE_PEM, certr.body)
        if self.cert:
            expire_time = time.strptime(certr.body.get_notAfter(),
                                        "%Y%m%d%H%M%SZ")
            self.expires = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT,
                                         expire_time)

        return self.cert
示例#25
0
import josepy as jose

from acme import client as acme_client
from acme import errors as acme_errors
from acme import messages

DIRECTORY = os.getenv('DIRECTORY', 'http://localhost:4000/directory')

if len(sys.argv) != 2:
    print("Usage: python deactivate.py private_key.pem")
    sys.exit(1)

data = open(sys.argv[1], "r").read()
key = jose.JWKRSA(
    key=serialization.load_pem_private_key(data, None, default_backend()))

net = acme_client.ClientNetwork(key,
                                verify_ssl=False,
                                user_agent="acme account deactivator")

client = acme_client.Client(DIRECTORY, key=key, net=net)
try:
    # We expect this to fail and give us a Conflict response with a Location
    # header pointing at the account's URL.
    client.register()
except acme_errors.ConflictError as e:
    location = e.location
if location is None:
    raise "Key was not previously registered (but now is)."
client.deactivate_registration(messages.RegistrationResource(uri=location))
示例#26
0
def lambda_handler(event, context):
    if 'bucket' not in event:
        LOG.critical("No bucket name has been provided. Exiting.")
        exit(1)
    s3_bucket = event['bucket']

    if 'region' not in event.keys(
    ) and 'AWS_DEFAULT_REGION' not in os.environ.keys():
        LOG.critical("Unable to determine AWS region code. Exiting.")
        exit(1)
    else:
        if 'region' not in event.keys():
            LOG.warning(
                "Using local environment to determine AWS region code.")
            s3_region = os.environ['AWS_DEFAULT_REGION']
            LOG.warning("Local region set to '{0}'.".format(s3_region))
        else:
            s3_region = event['region']

    if 'defaultkey' not in event:
        LOG.warning("No default KMS key provided, defaulting to 'AES256'.")
        kms_key = 'AES256'
    else:
        LOG.info("Using {0} as default KMS key.".format(event['defaultkey']))
        kms_key = event['defaultkey']

    if 'config' not in event:
        letslambda_config = 'letslambda.yml'
    else:
        letslambda_config = event['config']

    LOG.info(
        "Retrieving configuration file from bucket '{0}' in region '{1}' ".
        format(s3_bucket, s3_region))
    s3_client = boto3.client('s3',
                             config=Config(signature_version='s3v4',
                                           region_name=s3_region))

    conf = load_config(s3_client, s3_bucket, letslambda_config)
    if conf == None:
        LOG.critical("Cannot load letslambda configuration. Exiting.")
        exit(1)

    conf['region'] = os.environ['AWS_DEFAULT_REGION']
    conf['s3_client'] = s3_client
    conf['s3_bucket'] = s3_bucket
    conf['letslambda_config'] = letslambda_config
    conf['kms_key'] = kms_key

    account_key = load_letsencrypt_account_key(conf)

    acme_client = client.Client(conf['directory'], account_key)
    for domain in conf['domains']:
        if 'r53_zone' not in domain.keys():
            LOG.error(
                "Missing parameter 'r53_zone' for domain '{0}'. Skipping domain."
                .format(domain['name']))
            continue

        if 'kmsKeyArn' not in domain.keys():
            domain['kmsKeyArn'] = conf['kms_key']

        if 'reuse_key' not in domain.keys():
            domain['reuse_key'] = True

        if 'elb_port' not in domain.keys():
            domain['elb_port'] = 443

        if 'elb_region' not in domain.keys():
            domain['elb_region'] = conf['region']

        authorization_resource = get_authorization(acme_client, domain)
        challenge = get_dns_challenge(authorization_resource)
        res = answer_dns_challenge(conf, acme_client, domain, challenge)
        if res is not True:
            LOG.error(
                "An error occurred while answering the DNS challenge. Skipping domain '{0}'."
                .format(domain['name']))
            continue

        (chain, certificate,
         key) = request_certificate(conf, domain, acme_client,
                                    authorization_resource)
        if key == False or certificate == False:
            LOG.error(
                "An error occurred while requesting the signed certificate. Skipping domain '{0}'."
                .format(domain['name']))
            continue

        save_certificates_to_s3(conf, domain, chain, certificate)
        iam_cert = upload_to_iam(conf, domain, chain, certificate, key)
        if iam_cert is not False and iam_cert['ResponseMetadata'][
                'HTTPStatusCode'] is 200 and 'elb' in domain.keys():
            update_elb_server_certificate(
                conf, domain, iam_cert['ServerCertificateMetadata']['Arn'])
        else:
            LOG.error(
                "An error occurred while saving your server certificate in IAM. Skipping domain '{0}'."
                .format(domain['name']))
            continue