示例#1
0
def test_policy_expected_errors_for_create_cert():
    """Either a subject or subject alternative name property are required for creating a certificate"""
    client = CertificateClient("...", object())

    with pytest.raises(ValueError, match=NO_SAN_OR_SUBJECT):
        policy = CertificatePolicy()
        client.begin_create_certificate("...", policy=policy)

    with pytest.raises(ValueError, match=NO_SAN_OR_SUBJECT):
        policy = CertificatePolicy(issuer_name=WellKnownIssuerNames.self)
        client.begin_create_certificate("...", policy=policy)
示例#2
0
class KeyVaultCertificates:
    def __init__(self):
        # DefaultAzureCredential() expects the following environment variables:
        # * AZURE_CLIENT_ID
        # * AZURE_CLIENT_SECRET
        # * AZURE_TENANT_ID
        credential = DefaultAzureCredential()
        self.certificate_client = CertificateClient(
            vault_url=os.environ["AZURE_PROJECT_URL"], credential=credential)

        self.certificate_name = "cert-name-" + uuid.uuid1().hex

    def create_certificate(self):
        self.certificate_client.begin_create_certificate(
            name=self.certificate_name,
            policy=CertificatePolicy.get_default()).wait()
        print("\tdone")

    def get_certificate(self):
        print("Getting a certificate...")
        certificate = self.certificate_client.get_certificate(
            name=self.certificate_name)
        print(f"\tdone, certificate: {certificate.name}.")

    def delete_certificate(self):
        print("Deleting a certificate...")
        deleted_certificate = self.certificate_client.delete_certificate(
            name=self.certificate_name)
        print("\tdone: " + deleted_certificate.name)

    def run(self):
        print("")
        print("------------------------")
        print("Key Vault - Certificates\nIdentity - Credential")
        print("------------------------")
        print("1) Create a certificate")
        print("2) Get that certificate")
        print("3) Delete that certificate (Clean up the resource)")
        print("")

        try:
            self.create_certificate()
            self.get_certificate()
        finally:
            self.delete_certificate()
示例#3
0
class KeyVaultCertificates:
    def __init__(self):
        # DefaultAzureCredential() expects the following environment variables:
        # * AZURE_CLIENT_ID
        # * AZURE_CLIENT_SECRET
        # * AZURE_TENANT_ID
        authority_host = os.environ.get('AZURE_AUTHORITY_HOST') or KnownAuthorities.AZURE_PUBLIC_CLOUD
        credential = DefaultAzureCredential(authority=authority_host)
        self.certificate_client = CertificateClient(
            vault_url=os.environ["AZURE_PROJECT_URL"], credential=credential
        )

        self.certificate_name = "cert-name-" + uuid.uuid1().hex

    def create_certificate(self):
        print("Creating certificate (name: {})".format(self.certificate_name))
        create_poller = self.certificate_client.begin_create_certificate(
            certificate_name=self.certificate_name,
            policy=CertificatePolicy.get_default())
        print("\twaiting...")
        create_poller.result()
        print("\tdone")

    def get_certificate(self):
        print("Getting a certificate...")
        certificate = self.certificate_client.get_certificate(certificate_name=self.certificate_name)
        print("\tdone, certificate: {}.".format(certificate.name))

    def delete_certificate(self):
        print("Deleting a certificate...")
        poller = self.certificate_client.begin_delete_certificate(certificate_name=self.certificate_name)
        deleted_certificate = poller.result()
        print("\tdone: " + deleted_certificate.name)

    def run(self):
        print("")
        print("------------------------")
        print("Key Vault - Certificates\nIdentity - Credential")
        print("------------------------")
        print("1) Create a certificate")
        print("2) Get that certificate")
        print("3) Delete that certificate (Clean up the resource)")
        print("")

        try:
            self.create_certificate()
            self.get_certificate()
        finally:
            self.delete_certificate()
示例#4
0
    def backup_restore_certificate(self):
        """
        backs up a key vault certificate and restores it to another key vault
        """
        # create a key vault
        first_vault = self.create_vault()

        # create a certificate client
        credential = DefaultAzureCredential()
        first_certificate_client = CertificateClient(
            vault_url=first_vault.properties.vault_uri, credential=credential)

        # add a certificate to the vault
        certificate_name = get_name('certificate')

        certificate = first_certificate_client.begin_create_certificate(
            certificate_name, CertificatePolicy.get_default()).result()
        print('created certificate {}'.format(certificate.name))

        # list the certificates in the vault
        certificate_properties = first_certificate_client.list_properties_of_certificates(
        )
        print("all of the certificates in the client's vault:")
        for certificate_property in certificate_properties:
            print(certificate_property.name)

        # backup the certificate
        backup = first_certificate_client.backup_certificate(certificate_name)
        print('backed up certificate {}'.format(certificate_name))

        # create a second vault
        second_vault = self.create_vault()

        # create a certificate client
        second_certificate_client = CertificateClient(
            vault_url=second_vault.properties.vault_uri, credential=credential)

        # restore the certificate to the new vault
        restored = second_certificate_client.restore_certificate_backup(backup)
        print('restored certificate {}'.format(restored.name))

        # list the certificates in the new vault
        certificate_properties = second_certificate_client.list_properties_of_certificates(
        )
        print("all of the certificates in the new vault:")
        for certificate_property in certificate_properties:
            print(certificate_property.name)
示例#5
0
class KeyVaultCertificates(KeyVaultBase):
    def __init__(self):

        credential = self.get_default_credential()
        self.certificate_client = CertificateClient(
            vault_url=os.environ["AZURE_PROJECT_URL"], credential=credential)

        self.certificate_name = "cert-name-" + uuid.uuid1().hex

    def create_certificate(self):
        print("Creating certificate (name: {})".format(self.certificate_name))
        create_poller = self.certificate_client.begin_create_certificate(
            certificate_name=self.certificate_name,
            policy=CertificatePolicy.get_default())
        print("\twaiting...")
        create_poller.result()
        print("\tdone")

    def get_certificate(self):
        print("Getting a certificate...")
        certificate = self.certificate_client.get_certificate(
            certificate_name=self.certificate_name)
        print("\tdone, certificate: {}.".format(certificate.name))

    def delete_certificate(self):
        print("Deleting a certificate...")
        poller = self.certificate_client.begin_delete_certificate(
            certificate_name=self.certificate_name)
        deleted_certificate = poller.result()
        print("\tdone: " + deleted_certificate.name)

    def run(self):
        print("")
        print("------------------------")
        print("Key Vault - Certificates\nIdentity - Credential")
        print("------------------------")
        print("1) Create a certificate")
        print("2) Get that certificate")
        print("3) Delete that certificate (Clean up the resource)")
        print("")

        try:
            self.create_certificate()
            self.get_certificate()
        finally:
            self.delete_certificate()
# Instantiate a certificate client that will be used to call the service.
# Notice that the client is using default Azure credentials.
# To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID',
# 'AZURE_CLIENT_SECRET' and 'AZURE_TENANT_ID' are set with the service principal credentials.
VAULT_ENDPOINT = os.environ["VAULT_ENDPOINT"]
credential = DefaultAzureCredential()
client = CertificateClient(vault_endpoint=VAULT_ENDPOINT,
                           credential=credential)
try:
    print("\n.. Create Certificate")
    cert_name = "BackupRestoreCertificate"

    # Let's create a certificate for your key vault.
    # if the certificate already exists in the Key Vault, then a new version of the certificate is created.
    # A long running poller is returned for the create certificate operation.
    create_certificate_poller = client.begin_create_certificate(
        name=cert_name, policy=CertificatePolicy.get_default())

    # The result call awaits the completion of the create certificate operation and returns the final result.
    # It will return a certificate if creation is successful, and will return the CertificateOperation if not.
    certificate = create_certificate_poller.result()
    print("Certificate with name '{0}' created.".format(cert_name))

    # Backups are good to have, if in case certificates gets deleted accidentally.
    # For long term storage, it is ideal to write the backup to a file.
    print("\n.. Create a backup for an existing certificate")
    certificate_backup = client.backup_certificate(name=cert_name)
    print("Backup created for certificate with name '{0}'.".format(cert_name))

    # The storage account certificate is no longer in use, so you can delete it.
    print("\n.. Delete the certificate")
    client.delete_certificate(name=cert_name)
示例#7
0
        issuer_name=WellKnownIssuerNames.self,
        subject="CN=*.microsoft.com",
        san_dns_names=["sdk.azure-int.net"],
        exportable=True,
        key_type="RSA",
        key_size=2048,
        reuse_key=False,
        content_type=CertificateContentType.pkcs12,
        validity_in_months=24,
    )
    cert_name = "HelloWorldCertificate"

    # begin_create_certificate returns a poller. Calling result() on the poller will return the certificate
    # as a KeyVaultCertificate if creation is successful, and the CertificateOperation if not. The wait()
    # call on the poller will wait until the long running operation is complete.
    certificate = client.begin_create_certificate(certificate_name=cert_name,
                                                  policy=cert_policy).result()
    print("Certificate with name '{0}' created".format(certificate.name))

    # Let's get the bank certificate using its name
    print("\n.. Get a certificate by name")
    bank_certificate = client.get_certificate(cert_name)
    print("Certificate with name '{0}' was found'.".format(
        bank_certificate.name))

    # After one year, the bank account is still active, and we have decided to update the tags.
    print("\n.. Update a certificate by name")
    tags = {"a": "b"}
    updated_certificate = client.update_certificate_properties(
        certificate_name=bank_certificate.name, tags=tags)
    print("Certificate with name '{0}' was updated on date '{1}'".format(
        bank_certificate.name, updated_certificate.properties.updated_on))
示例#8
0
def run_example():
    """Resource Group management example."""
    #
    # Create the Resource Manager Client with an Application (service principal) token provider
    #
    subscription_id = os.environ.get(
        'AZURE_SUBSCRIPTION_ID',
        '11111111-1111-1111-1111-111111111111')  # your Azure Subscription Id
    credential = ClientSecretCredential(
        client_id=os.environ['AZURE_CLIENT_ID'],
        client_secret=os.environ['AZURE_CLIENT_SECRET'],
        tenant_id=os.environ['AZURE_TENANT_ID'])
    resource_client = ResourceManagementClient(credential, subscription_id)
    compute_client = ComputeManagementClient(credential, subscription_id)
    network_client = NetworkManagementClient(credential, subscription_id)
    kv_mgmt_client = KeyVaultManagementClient(credential, subscription_id)

    cert_client = CertificateClient(
        "https://{}.vault.azure.net".format(KV_NAME), credential)

    # Create Resource group
    print('\nCreate Resource Group')
    resource_group = resource_client.resource_groups.create_or_update(
        GROUP_NAME, {'location': LOCATION})
    print_item(resource_group)

    # Resolve the client_id as object_id for KeyVault access policy.
    # If you already know your object_id, you can skip this part
    sp_object_id = os.environ.get('AZURE_CLIENT_OBJECT_ID',
                                  '11111111-1111-1111-1111-111111111111'
                                  )  # your service principal's object id

    # Create Key Vault account
    print('\nCreate Key Vault account')
    async_vault_poller = kv_mgmt_client.vaults.begin_create_or_update(
        GROUP_NAME,
        KV_NAME,
        {
            'location': LOCATION,
            'properties': {
                'sku': {
                    'name': 'standard'
                },
                'tenant_id':
                os.environ['AZURE_TENANT_ID'],
                'access_policies': [{
                    'tenant_id': os.environ['AZURE_TENANT_ID'],
                    'object_id': sp_object_id,
                    'permissions': {
                        # Only "certificates" and "secrets" are needed for this sample
                        'certificates': ['all'],
                        'secrets': ['all']
                    }
                }],
                # Critical to allow the VM to download certificates later
                'enabled_for_deployment':
                True
            }
        })
    vault = async_vault_poller.result()
    print_item(vault)

    # # KeyVault recommentation is to wait 20 seconds after account creation for DNS update
    time.sleep(20)

    # Ask KeyVault to create a Certificate
    certificate_name = "cert1"
    print('\nCreate Key Vault Certificate')
    certificate_poller = cert_client.begin_create_certificate(
        certificate_name, policy=DEFAULT_POLICY)
    certificate_poller.wait()
    while True:
        check = cert_client.get_certificate_operation(certificate_name)
        if check.status != 'inProgress':
            break
        try:
            print("Waiting for certificate creation to finish")
            time.sleep(10)
        except KeyboardInterrupt:
            print("Certificate creation wait cancelled.")
            raise
    print_item(check)

    print('\nGet Key Vault created certificate as a secret')
    secret_client = SecretClient("https://{}.vault.azure.net".format(KV_NAME),
                                 credential)
    certificate_as_secret = secret_client.get_secret(
        certificate_name,
        ""  # Latest version
    )
    print_item(certificate_as_secret)

    print("\nCreate Network")
    # Create Network components of the VM
    # This is not related to the main topic of this sample and is just required to create the VM
    subnet = create_virtual_network(network_client)
    public_ip = create_public_ip(network_client)
    nic = create_network_interface(network_client, subnet, public_ip)
    print_item(nic)

    # Create a VM with some Key Vault certificates
    params_create = {
        'location': LOCATION,
        'hardware_profile': get_hardware_profile(),
        'network_profile': get_network_profile(nic.id),
        'storage_profile': get_storage_profile(),
        'os_profile': {
            'admin_username':
            ADMIN_LOGIN,
            'admin_password':
            ADMIN_PASSWORD,
            'computer_name':
            'testkvcertificates',
            # This is the Key Vault critical part
            'secrets': [{
                'source_vault': {
                    'id': vault.id,
                },
                'vault_certificates': [{
                    'certificate_url':
                    certificate_as_secret.id
                }]
            }]
        }
    }

    print("\nCreate VM")
    vm_poller = compute_client.virtual_machines.begin_create_or_update(
        GROUP_NAME,
        VM_NAME,
        params_create,
    )
    vm_result = vm_poller.result()
    print_item(vm_result)

    # Get the PublicIP after VM creation, since assignment is dynamic
    public_ip = network_client.public_ip_addresses.get(GROUP_NAME,
                                                       PUBLIC_IP_NAME)

    print("You can connect to the VM using:")
    print("ssh {}@{}".format(
        ADMIN_LOGIN,
        public_ip.ip_address,
    ))
    print("And password: {}\n".format(ADMIN_PASSWORD))

    print("Your certificate is available in this folder: /var/lib/waagent")
    print("You must be root to see it (sudo su)\n")

    input("Press enter to delete this Resource Group.")

    # Delete Resource group and everything in it
    print('Delete Resource Group')
    delete_async_operation = resource_client.resource_groups.begin_delete(
        GROUP_NAME)
    delete_async_operation.wait()
    print("\nDeleted: {}".format(GROUP_NAME))
# Notice that the client is using default Azure credentials.
# To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID',
# 'AZURE_CLIENT_SECRET' and 'AZURE_TENANT_ID' are set with the service principal credentials.
VAULT_URL = os.environ["VAULT_URL"]
credential = DefaultAzureCredential()
client = CertificateClient(vault_url=VAULT_URL, credential=credential)

# Let's create certificates holding storage and bank accounts credentials. If the certificate
# already exists in the Key Vault, then a new version of the certificate is created.
print("\n.. Create Certificates")

bank_cert_name = "BankRecoverCertificate"
storage_cert_name = "ServerRecoverCertificate"

bank_certificate_poller = client.begin_create_certificate(
    certificate_name=bank_cert_name, policy=CertificatePolicy.get_default()
)
storage_certificate_poller = client.begin_create_certificate(
    certificate_name=storage_cert_name, policy=CertificatePolicy.get_default()
)

bank_certificate = bank_certificate_poller.result()
storage_certificate = storage_certificate_poller.result()
print("Certificate with name '{0}' was created.".format(bank_certificate.name))
print("Certificate with name '{0}' was created.".format(storage_certificate.name))

# The storage account was closed, need to delete its credentials from the Key Vault.
print("\n.. Delete a Certificate")
deleted_bank_poller = client.begin_delete_certificate(bank_cert_name)
deleted_bank_certificate = deleted_bank_poller.result()
# To ensure certificate is deleted on the server side.
class Acme2KeyVault:
    """
    Provisions ACME/Let's Encrypt TLS certificates
    """
    def __init__(self, credential: ChainedTokenCredential, options: Options):
        self.options = options
        self._cert_client = CertificateClient(options.azure_keyvault_uri,
                                              credential)
        self._dns_client = DnsManagementClient(credential,
                                               options.azure_subscription_id)
        blob_svc_client = BlobServiceClient.from_connection_string(
            options.cert_request_connection_str, )
        self._container_client = blob_svc_client.get_container_client(
            options.cert_request_container)

    def _cert_policy_from_request(
            self, cert_request: CertRequest) -> CertificatePolicy:
        subject = f"CN={cert_request.common_name}"
        if self.options.cert_subject:
            subject += " " + self.options.cert_subject

        return CertificatePolicy(
            issuer_name="Unknown",
            key_size=self.options.cert_key_size,
            subject=subject,
            san_dns_names=cert_request.alternative_names,
            validity_in_months=CERT_VALIDITY_MONTHS,
            exportable=True,
        )

    def _generate_new_cert_key(self, cert_request: CertRequest) -> str:
        """
        Generates a new certificate key and returns it in the PEM format
        (as required by Azure keyvault)
        Note: Deletes any previous certificate operation with the same id
        """
        # Delete the previous certificate operation if it exists
        try:
            self._cert_client.delete_certificate_operation(cert_request.id)
        except HttpResponseError as e:
            if e.status_code != 404:
                raise

        # Generate a new certificate key
        self._cert_client.begin_create_certificate(
            certificate_name=cert_request.id,
            policy=self._cert_policy_from_request(cert_request),
        )

        # Get the CSR for the new certificate key
        cert_op = self._cert_client.get_certificate_operation(cert_request.id)
        return _csr_bytes_to_pem(cert_op.csr)

    def _create_acme_client(self) -> acme_client.ClientV2:
        net = acme_client.ClientNetwork(key=josepy.JWKRSA(
            key=rsa.generate_private_key(
                public_exponent=ACME_RSA_PUBLIC_EXPONENT,
                key_size=ACME_RSA_KEY_SIZE,
                backend=default_backend(),
            )))
        directory = acme_messages.Directory.from_json(
            net.get(self.options.acme_directory_url).json())
        return acme_client.ClientV2(directory=directory, net=net)

    def _authorization_to_relative_domain(
        self,
        authorization: acme_messages.Authorization,
    ):
        relative_domain = authorization.identifier.value.replace(
            f".{self.options.azure_dns_zone}", "")
        return f"_acme-challenge.{relative_domain}"

    def _setup_dns_challenge(
        self,
        record_set_name: str,
        value: str,
    ):
        self._dns_client.record_sets.create_or_update(
            resource_group_name=self.options.azure_dns_zone_resource_group,
            zone_name=self.options.azure_dns_zone,
            relative_record_set_name=record_set_name,
            record_type=RecordType.TXT,
            parameters=RecordSet(
                ttl=ACME_CHALLENGE_TXT_RECORD_TTL,
                txt_records=[TxtRecord(value=[value])],
            ),
        )

    def _teardown_dns_challenge(
        self,
        record_set_name: str,
    ):
        self._dns_client.record_sets.delete(
            resource_group_name=self.options.azure_dns_zone_resource_group,
            zone_name=self.options.azure_dns_zone,
            relative_record_set_name=record_set_name,
            record_type=RecordType.TXT,
        )

    def _verify_challenge(
        self,
        client: acme_client.ClientV2,
        authz: acme_messages.Authorization,
    ):
        challenge_body, dns_challenge = _find_dns_challenge(authz)
        validation_domain = self._authorization_to_relative_domain(authz)
        response, validation_value = dns_challenge.response_and_validation(
            client.net.key)

        try:
            logging.debug(
                "Creating DNS challenge: '%s' = '%s'",
                validation_domain,
                validation_value,
            )
            self._setup_dns_challenge(
                record_set_name=validation_domain,
                value=validation_value,
            )
            logging.debug("Answering DNS challenge")
            client.answer_challenge(challenge_body, response)
        finally:
            logging.debug("Tearing down DNS challenge: '%s'",
                          validation_domain)
            self._teardown_dns_challenge(record_set_name=validation_domain, )

    def _order_certificate(self, csr: str) -> str:
        logging.debug("Registering an account")
        client = self._create_acme_client()
        client.new_account(
            acme_messages.NewRegistration.from_data(
                email=self.options.acme_contact_email,
                terms_of_service_agreed=True,
            ))

        logging.debug("Placing a new order")
        order = client.new_order(csr)

        logging.debug("Verifying challenges")
        authz_resource: acme_messages.AuthorizationResource
        for authz_resource in order.authorizations:  # pylint: disable=not-an-iterable
            authz: acme_messages.Authorization = authz_resource.body
            self._verify_challenge(client, authz)

        logging.debug("Finalizing order")
        finalized_order = client.poll_and_finalize(order)
        return finalized_order.fullchain_pem

    def _store_certificate(self, cert_request: CertRequest, certificate: str):
        self._cert_client.merge_certificate(
            cert_request.id,
            [certificate.encode("ascii")],
        )

    def provision(self, cert_request: CertRequest):
        """
        Provision a TLS certificate based on the given certificate request.

        This can be used for both provisioning new certificates as well as renewing existing ones.
        """
        logging.info("Generating a certificate key %s", cert_request.id)
        csr = self._generate_new_cert_key(cert_request)

        logging.info("Ordering a certificate for %s", cert_request.common_name)
        certificate = self._order_certificate(csr)

        logging.info("Storing certificate %s", cert_request.id)
        self._store_certificate(cert_request, certificate)

    def save(self, cert_request: CertRequest):
        """
        Saves the certificate request details for certificate renewal purposes
        """
        blob_client = self._container_client.get_blob_client(
            cert_request.blob_name)
        blob_client.upload_blob(data=cert_request.json(), overwrite=True)

    def _cert_needs_renewal(self, certificate: CertificateProperties) -> bool:
        # Disabled certificates are not renewed
        if not certificate.enabled:
            return False

        now = datetime.now(tz=timezone.utc)
        time_until_expiration = certificate.expires_on.replace() - now
        return time_until_expiration.days <= self.options.cert_expiry_threshold_days

    def find_cert_names_needing_renewal(self) -> typing.List[str]:
        """
        Find all the names of the certificates from Key Vault that need to be renewed
        """
        certificates = self._cert_client.list_properties_of_certificates()
        return [
            certificate.name for certificate in certificates
            if self._cert_needs_renewal(certificate)
        ]

    def find_certs_needing_renewal(self) -> typing.List[CertRequest]:
        """
        Find all the certificates from Key Vault that need to be renewed
        """
        cert_requests: typing.List[CertRequest] = []
        for cert_name in self.find_cert_names_needing_renewal():
            blob_client = self._container_client.get_blob_client(
                _cert_name_to_blob_name(cert_name))
            try:
                bytes = blob_client.download_blob().readall()
                cert_request = CertRequest.parse_raw(bytes)
                cert_requests.append(cert_request)
            except HttpResponseError as e:
                if e.status_code == 404:
                    logging.error(
                        "Could not find cert request document for certificate %s",
                        cert_name,
                    )
                else:
                    raise

        return cert_requests
示例#11
0
def create_or_update_cert(
        kv_cert_name,
        *domains,
        use_prod=False,
        keyvault_url='https://ponti-certs-kvjwxwal2p6n.vault.azure.net/',
        dns_zone_resource_group='damienpontifex.com-rg',
        dns_zone_name='damienpontifex.com',
        registration_email='*****@*****.**',
        dns_subscription_id="fa2cbf67-1293-4f9c-8884-a0379a9e0c64"):

    # Get directory
    if use_prod:
        directory_url = 'https://acme-v02.api.letsencrypt.org/directory'
        user_key_name = 'acme'
        issuance_period_months = 3
    else:
        directory_url = 'https://acme-staging-v02.api.letsencrypt.org/directory'
        user_key_name = 'acme-staging'
        issuance_period_months = 1

    credential = DefaultAzureCredential()

    challenge_handler = functools.partial(
        dns_challenge_handler,
        credential=credential,
        subscription_id=dns_subscription_id,
        dns_zone_resource_group=dns_zone_resource_group,
        dns_zone_name=dns_zone_name)

    cert_client = CertificateClient(vault_url=keyvault_url,
                                    credential=credential)

    #%%
    key = KeyVaultRSAKey(credential, keyvault_url, user_key_name)

    account_key = josepy.JWKRSA(key=key)
    client_network = acme.client.ClientNetwork(account_key)

    directory = messages.Directory.from_json(
        client_network.get(directory_url).json())

    client = acme.client.ClientV2(directory, client_network)

    new_regr = acme.messages.Registration.from_data(
        key=account_key,
        email=registration_email,
        terms_of_service_agreed=True)

    # Register or fetch account
    try:
        regr = client.new_account(new_regr)
        logger.info('Created new account')
    except acme.errors.ConflictError as e:
        regr = acme.messages.RegistrationResource(uri=e.location,
                                                  body=new_regr)
        regr = client.query_registration(regr)
        logger.info('Got existing account')

    cert_policy = CertificatePolicy(
        issuer_name='Unknown',
        subject_name=f'CN={domains[0]}',
        exportable=True,
        key_type=KeyType.rsa,
        key_size=2048,
        content_type=CertificateContentType.pkcs12,
        san_dns_names=domains[1:] if len(domains) > 1 else [],
        validity_in_months=issuance_period_months)

    try:
        # Check an existing certificate operation isn't in progress
        cert_op = cert_client.get_certificate_operation(
            certificate_name=kv_cert_name)
        logger.info('Existing cert operation in progress')
    except ResourceNotFoundError:
        cert_op = cert_client.begin_create_certificate(
            certificate_name=kv_cert_name, policy=cert_policy)
        logger.info('New cert operation')

    # cert_op = kvclient.create_certificate(KEYVAULT_URL, certificate_name=kv_cert_name, certificate_policy=cert_policy)
    cert_op_res = cert_op.result()
    cert_op_r = cert_client.get_certificate_operation(kv_cert_name)

    logger.info('Created certificate request in key vault')

    # Wrap with header and footer for pem to show certificate request
    csr_pem = "-----BEGIN CERTIFICATE REQUEST-----\n" + base64.b64encode(
        cert_op_r.csr).decode() + "\n-----END CERTIFICATE REQUEST-----\n"

    # Submit order
    order_resource = client.new_order(csr_pem)
    logger.info('Submitted order')

    # Challenges from order
    # Respond to challenges
    challenges_to_respond_to = list(
        challenge_handler(authorizations=order_resource.authorizations,
                          account_key=account_key))

    for dns_challenge in challenges_to_respond_to:
        # Perform challenge
        auth_response = client.answer_challenge(
            dns_challenge, dns_challenge.chall.response(account_key))

    logger.info('Answered challenges')

    # Poll for status
    # Finalize order
    # Download certificate
    final_order = client.poll_and_finalize(order_resource)

    logger.info('Finalised order')

    # Strip header and footer of BEGIN/END CERTIFICATE
    # with open('cert.pem', 'w') as f:
    #     f.write(final_order.fullchain_pem)

    certificate_vals = [
        val.replace('\n', '').encode()
        for val in final_order.fullchain_pem.split('-----')
        if 'CERTIFICATE' not in val and len(val.replace('\n', '')) != 0
    ]

    cert_client.merge_certificate(name=kv_cert_name,
                                  x509_certificates=certificate_vals)

    logger.info('Merged certificate back to key vault')
    def deleted_certificate_recovery(self):
        """
        a sample of enumerating, retrieving, recovering and purging deleted certificates from a key vault 
        """
        # create a vault enabling the soft delete feature
        vault = self.create_vault()

        # create a certificate client
        credential = DefaultAzureCredential()
        certificate_client = CertificateClient(
            vault_url=vault.properties.vault_uri, credential=credential)

        # create certificates in the vault
        cert_to_recover = get_name('cert')
        cert_to_purge = get_name('cert')

        create_certificate_poller = certificate_client.begin_create_certificate(
            cert_to_recover, policy=CertificatePolicy.get_default())
        created_certificate = create_certificate_poller.result()
        print('created certificate {}'.format(created_certificate.name))

        create_certificate_poller = certificate_client.begin_create_certificate(
            cert_to_purge, policy=CertificatePolicy.get_default())
        created_certificate = create_certificate_poller.result()
        print('created certificate {}'.format(created_certificate.name))

        # list the vault certificates
        certificates = certificate_client.list_properties_of_certificates()
        print('list the vault certificates')
        for certificate in certificates:
            print(certificate.name)

        # delete the certificates
        deleted_certificate_poller = certificate_client.begin_delete_certificate(
            cert_to_recover)
        deleted_certificate = deleted_certificate_poller.result()
        deleted_certificate_poller.wait()
        print('deleted certificate {}'.format(deleted_certificate.name))

        deleted_certificate_poller = certificate_client.begin_delete_certificate(
            cert_to_purge)
        deleted_certificate = deleted_certificate_poller.result()
        deleted_certificate_poller.wait()
        print('deleted certificate {}'.format(deleted_certificate.name))

        # list the deleted certificates
        deleted_certs = certificate_client.list_deleted_certificates()
        print('deleted certificates:')
        for deleted_cert in deleted_certs:
            print(deleted_cert.name)

        # recover a deleted certificate
        recovered_certificate_poller = certificate_client.begin_recover_deleted_certificate(
            cert_to_recover)
        recovered_certificate_certificate = recovered_certificate_poller.result(
        )
        print('recovered certificate {}'.format(
            recovered_certificate_certificate.name))

        # purge a deleted certificate
        certificate_client.purge_deleted_certificate(cert_to_purge)
        time.sleep(50)
        print('purged certificate {}'.format(cert_to_purge))

        # list the vault certificates
        certificates = certificate_client.list_properties_of_certificates()
        print("all of the certificates in the client's vault:")
        for certificate in certificates:
            print(certificate.name)
from azure.identity import CertificateCredential, DefaultAzureCredential
from azure.keyvault.certificates import CertificateClient, CertificateContentType, CertificatePolicy
from azure.keyvault.secrets import SecretClient

VAULT_URL = os.environ["VAULT_URL"]

credential = DefaultAzureCredential()

# a CertificateClient to create self-signed certs to work with
CERT_CLIENT = CertificateClient(VAULT_URL, credential)

# Key Vault stores certificate private keys as secrets, so we use a SecretClient to retrieve them
SECRET_CLIENT = SecretClient(VAULT_URL, credential)

# Creating a self-signed cert to work with
create_cert_poller = CERT_CLIENT.begin_create_certificate("azure-identity-sample", CertificatePolicy.get_default())
cert = create_cert_poller.result()

# The certificate as returned by begin_create_certificate() or get_certificate() contains
# only the public portion of the certificate. Key Vault will release the private key only
# if the certificate's policy indicates it's exportable (certs are exportable by default).
policy = CERT_CLIENT.get_certificate_policy(cert.name)
assert policy.exportable, "Expected an exportable certificate because that's Key Vault's default"

# The policy's content_type indicates whether the certificate is stored in PEM or PKCS12 format
assert policy.content_type == CertificateContentType.pkcs12, "Expected PKCS12 because that's Key Vault's default"

# Key Vault stores the complete certificate, with its private key, as a secret sharing the certificate's name
# Because this certificate is stored in PKCS12 format, the secret's value is base64 encoded bytes
encoded_cert = SECRET_CLIENT.get_secret(cert.name).value
pkcs12_bytes = base64.b64decode(encoded_cert)