acme-dns-azure


Nameacme-dns-azure JSON
Version 0.4.0 PyPI version JSON
download
home_pagehttps://github.com/ZEISS/acme-dns-azure
SummaryACME client setup based on Certbot for dns-01 challenges via Azure Cloud services
upload_time2024-08-02 07:50:03
maintainerNone
docs_urlNone
authorZEISS Digital Innovation Partners
requires_python<4.0,>=3.8
licenseMIT
keywords acme dns azure certbot letsencrypt
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Introduction

This repository aims to leverage the automatic renewal of SSL certficates within Azure Cloud in a secure manner.

A wrapper library is provided to automatically renew certifactes based on the [ACME DNS-01 challenge](https://letsencrypt.org/docs/challenge-types/#:~:text=all%20of%20them.-,DNS%2D01%20challenge,-This%20challenge%20asks) by using [certbot](https://certbot.eff.org/).

The library supports the usage of best practices for securely handling certificates by:

- using certbot
- removing the need of a file system for storing certificates
- Azure Key Vault for central and only storage of secrets and certificates
- enabling easy and flexible automation

# Installing acme-dns-azure

acme-dns-azure is available on PyPi:

```bash
python -m pip install acme-dns-azure
```

For usage exampless please refer to [examples](examples)

## Scope

Based on the provided configuration and trigger, the wrapper library supports following flow.

![architecture](https://github.com/ZEISS/acme-dns-azure/blob/main/docs/architecture_concept.png?raw=true)

1. Receive certificates, receive EAB & ACME credentials (if configured), receive ACME account information (if already present) from KeyVault. Resolve DNS and setup certbot related configuration.
2. Certbot: Init renewal process to certificate authority
3. Certbot: DNS Challenge - create TXT record
4. Certbot: Renew certificates
5. Certbot: DNS Challenge - delete TXT record
6. Upload renewed certificates, create/update ACME account information as secret within KeyVault.

Note: When using [DNS delegation](https://docs.certbot-dns-azure.co.uk/en/latest/#:~:text=management.microsoftazure.de/-,DNS%20delegation,%C2%B6,-DNS%20delegation%2C%20also) step _3._ and _5._ differ as the TXT record won´t be deleted.

### Features

The library handles following use cases:

- Create new certificates
- Update domain references in existing certificates
- Renew existing certificates

Auth is possible by using:

- Service Principal
- User Assigned Identity

### Integration

The library can be used by:

- running as script
- Python package within your app

Within [examples](examples) you can find example implementations for running the python package:

- Azure function
- Container

![usage](https://github.com/ZEISS/acme-dns-azure/blob/main/docs/wrapper_usage.png?raw=true)

# Contribute

Fork, then clone the repo:

```bash
git clone https://github.com/ZEISS/acme-dns-azure
```

Install Poetry if you not have it already:

```bash
curl -sSL https://install.python-poetry.org | python3 -
```

Configure the virtual environment with full example support and activate it:

## Install dependencies

```bash
poetry install --all-extras
source .venv/bin/activate
```

## Lint

```bash
poetry run black .
```

## Run unit tests

```bash
poetry run coverage run
poetry run coverage report
```

## Run integration tests

See [How to run integration tests](tests/integration/README.md)

## Release

For releasing a new version, create a PR with one of following labels:

- minor
- major
- patch
- prepatch
- preminor
- premajor
- prerelease

# Usage

## Config

The config is written in [YAML format](http://en.wikipedia.org/wiki/YAML), defined by the scheme described below.
Brackets indicate that a parameter is optional.
For non-list parameters the value is set to the specified default.

Generic placeholders are defined as follows:

- `<boolean>`: a boolean that can take the values `true` or `false`
- `<int>`: a regular integer
- `<string>`: a regular string
- `<secret>`: a regular string that is a secret, such as a password

The other placeholders are specified separately.

See [examples](examples/README.md) for configuration examples.

```yml
# Azure credentials choice section. Only one of the following flags should be set to true to indicate which credentials to use. Otherwise an exception would be raised by the validator. 
# These values are translated into ini file as specified here: https://docs.certbot-dns-azure.co.uk/en/latest/index.html#certbot-azure-workload-identity-ini
# If no flag is provided the program will try to use sp_client_* values to use service principal credentials first. If those are not both present it will try to use managed_identity_id.
[use_system_assigned_identity_credentials: <boolean>]
[use_azure_cli_credentials: <boolean>]
[use_workload_identity_credentials: <boolean>]
[use_managed_identity_credentials: <boolean>]
[use_provided_service_principal_credentials: <boolean>]

# Client ID of managed identity. Must be provided if use_managed_identity_credentials is true. Will be used even if all use_*_credentials flags are set to false, but only if sp_client_* values are not all provided.
[managed_identity_id: <string>]

# sp_client_* values must be provided if use_provided_service_principal_credentials is true. Will be used even if all use_*_credentials flags are set to false. User must specify id and either secret or certificate path. If both values (id and pwd/cert path) are provided and none of the flags is set to true it has precedence over the use of provided managed_identity_id.
[sp_client_id: <string>]
[sp_client_secret: <secret>]
[sp_certificate_path: <string>]
# End of Azure credentials choice section.

[azure_environment: <string> | default = "AzurePublicCloud"]

# Flag if existing certificates containing multiple domains should be renewed and updated based on the definition of the config file. If not set, mismatching certificates will be skipped.
[update_cert_domains: <boolean> | default = False]

# key vault uri for renewal of certifcate
key_vault_id : <string>

# ACME Certificate Authority
server : <string>

# Secret name within key vault for storing ACME Certificate authority account information
[keyvault_account_secret_name: <regex> | default "acme-account-$(network location of server)"]
# when server=https://example.com/something, then keyvault_account_secret_name="acme-account-example-com"

# config file content for certbot client
[certbot.ini : <string> | default = ""]
```

NOTE: Either **managed_identity_id** or **sp_client_id** and **sp_client_secret** must be specified.

NOTE: **certbot.ini** represents the [CERTBOT configuration file](https://eff-certbot.readthedocs.io/en/latest/using.html#configuration-file) and will be passed into certbot by the _acme_dns_azure_ library as defined. Misconfiguration will lead to failures of certbot and therefore of the renewal process.

Following values will be added to the configurataion file by the _acme_dns_azure_ library per default:

```yml
preferred-challenges: dns
authenticator: dns-azure
agree-tos: true
```

### `[<eab>]`

```yml

  # External account binding configuration for ACME, with key ID and base64encoded HMAC key
  [enabled: <boolean> |  default = false]
  [kid_secret_name : <string> | default="acme-eab-kid"]
  [hmac_key_secret_name : <secret> default="acme-eab-hmac-key"]
```

```yml
certificates:
  - <certificate>
```

### `<certificate>`

```yml
# Certbot certficate name. The name will also be used for Azure keyvault certificate name.
name: <string>
# Azure dns zone resource ID used for ACME DNS01 challenge
dns_zone_resource_id: <string>
# renewal in days before expiry for certificate to be renewed. Default is 30
[renew_before_expiry: <int>]
domains:
  - <domain>
```

### `<domain>`

```yml
# domain name this certificate is valid for. Wildcard supported.
name: <string>
# Azure dns zone resource ID used for ACME DNS01 challenge
[dns_zone_resource_id: <string>]
```

## Manual running the library

For running the module as script 'sp_client_id' and 'sp_client_secret' are required. 'managed_identity_id' is not supported.

```bash
# from config file
python acme_dns_azure/client.py --config-file-path $CONFIG_File_PATH
# from env
python acme_dns_azure/client.py --config-env-var $ENV_VAR_NAME_CONTAINING_CONFIG
```

## Permission Handling

Best follow [security recommendations from Azure](https://docs.certbot-dns-azure.co.uk/en/latest/#:~:text=Example%3A%20Delegation%20%2B%20more,%C2%B6).

When working with shared DNS Zones, one can work with DNS delegation with limited permissions:

Example:

| Record | Name                         | Value                  | Permission           |
| ------ | ---------------------------- | ---------------------- | -------------------- |
| TXT    | \_acme-dedicated             | -                      | DNS Zone Contributor |
| CNAME  | \_acme-challenge.mysubdomain | \_acme-dedicated.fqdn. | None                 |

The CNAME and TXT record must be created upfront to enable users to use certbot. The permissions are required on the identity triggering certbot.

With this setup, a DNS Zone owner can limit permissions and enable Users to Create/Renew certificates for their subdomain and ensuring that users cannot aquire certificates for other domains or interfer with existsing records.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ZEISS/acme-dns-azure",
    "name": "acme-dns-azure",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.8",
    "maintainer_email": null,
    "keywords": "acme, dns, azure, certbot, letsencrypt",
    "author": "ZEISS Digital Innovation Partners",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/71/26/3403d57937b37caffefa233756dc50e1dfdcd575d66f500bf27f237884d0/acme_dns_azure-0.4.0.tar.gz",
    "platform": null,
    "description": "# Introduction\n\nThis repository aims to leverage the automatic renewal of SSL certficates within Azure Cloud in a secure manner.\n\nA wrapper library is provided to automatically renew certifactes based on the [ACME DNS-01 challenge](https://letsencrypt.org/docs/challenge-types/#:~:text=all%20of%20them.-,DNS%2D01%20challenge,-This%20challenge%20asks) by using [certbot](https://certbot.eff.org/).\n\nThe library supports the usage of best practices for securely handling certificates by:\n\n- using certbot\n- removing the need of a file system for storing certificates\n- Azure Key Vault for central and only storage of secrets and certificates\n- enabling easy and flexible automation\n\n# Installing acme-dns-azure\n\nacme-dns-azure is available on PyPi:\n\n```bash\npython -m pip install acme-dns-azure\n```\n\nFor usage exampless please refer to [examples](examples)\n\n## Scope\n\nBased on the provided configuration and trigger, the wrapper library supports following flow.\n\n![architecture](https://github.com/ZEISS/acme-dns-azure/blob/main/docs/architecture_concept.png?raw=true)\n\n1. Receive certificates, receive EAB & ACME credentials (if configured), receive ACME account information (if already present) from KeyVault. Resolve DNS and setup certbot related configuration.\n2. Certbot: Init renewal process to certificate authority\n3. Certbot: DNS Challenge - create TXT record\n4. Certbot: Renew certificates\n5. Certbot: DNS Challenge - delete TXT record\n6. Upload renewed certificates, create/update ACME account information as secret within KeyVault.\n\nNote: When using [DNS delegation](https://docs.certbot-dns-azure.co.uk/en/latest/#:~:text=management.microsoftazure.de/-,DNS%20delegation,%C2%B6,-DNS%20delegation%2C%20also) step _3._ and _5._ differ as the TXT record won\u00b4t be deleted.\n\n### Features\n\nThe library handles following use cases:\n\n- Create new certificates\n- Update domain references in existing certificates\n- Renew existing certificates\n\nAuth is possible by using:\n\n- Service Principal\n- User Assigned Identity\n\n### Integration\n\nThe library can be used by:\n\n- running as script\n- Python package within your app\n\nWithin [examples](examples) you can find example implementations for running the python package:\n\n- Azure function\n- Container\n\n![usage](https://github.com/ZEISS/acme-dns-azure/blob/main/docs/wrapper_usage.png?raw=true)\n\n# Contribute\n\nFork, then clone the repo:\n\n```bash\ngit clone https://github.com/ZEISS/acme-dns-azure\n```\n\nInstall Poetry if you not have it already:\n\n```bash\ncurl -sSL https://install.python-poetry.org | python3 -\n```\n\nConfigure the virtual environment with full example support and activate it:\n\n## Install dependencies\n\n```bash\npoetry install --all-extras\nsource .venv/bin/activate\n```\n\n## Lint\n\n```bash\npoetry run black .\n```\n\n## Run unit tests\n\n```bash\npoetry run coverage run\npoetry run coverage report\n```\n\n## Run integration tests\n\nSee [How to run integration tests](tests/integration/README.md)\n\n## Release\n\nFor releasing a new version, create a PR with one of following labels:\n\n- minor\n- major\n- patch\n- prepatch\n- preminor\n- premajor\n- prerelease\n\n# Usage\n\n## Config\n\nThe config is written in [YAML format](http://en.wikipedia.org/wiki/YAML), defined by the scheme described below.\nBrackets indicate that a parameter is optional.\nFor non-list parameters the value is set to the specified default.\n\nGeneric placeholders are defined as follows:\n\n- `<boolean>`: a boolean that can take the values `true` or `false`\n- `<int>`: a regular integer\n- `<string>`: a regular string\n- `<secret>`: a regular string that is a secret, such as a password\n\nThe other placeholders are specified separately.\n\nSee [examples](examples/README.md) for configuration examples.\n\n```yml\n# Azure credentials choice section. Only one of the following flags should be set to true to indicate which credentials to use. Otherwise an exception would be raised by the validator. \n# These values are translated into ini file as specified here: https://docs.certbot-dns-azure.co.uk/en/latest/index.html#certbot-azure-workload-identity-ini\n# If no flag is provided the program will try to use sp_client_* values to use service principal credentials first. If those are not both present it will try to use managed_identity_id.\n[use_system_assigned_identity_credentials: <boolean>]\n[use_azure_cli_credentials: <boolean>]\n[use_workload_identity_credentials: <boolean>]\n[use_managed_identity_credentials: <boolean>]\n[use_provided_service_principal_credentials: <boolean>]\n\n# Client ID of managed identity. Must be provided if use_managed_identity_credentials is true. Will be used even if all use_*_credentials flags are set to false, but only if sp_client_* values are not all provided.\n[managed_identity_id: <string>]\n\n# sp_client_* values must be provided if use_provided_service_principal_credentials is true. Will be used even if all use_*_credentials flags are set to false. User must specify id and either secret or certificate path. If both values (id and pwd/cert path) are provided and none of the flags is set to true it has precedence over the use of provided managed_identity_id.\n[sp_client_id: <string>]\n[sp_client_secret: <secret>]\n[sp_certificate_path: <string>]\n# End of Azure credentials choice section.\n\n[azure_environment: <string> | default = \"AzurePublicCloud\"]\n\n# Flag if existing certificates containing multiple domains should be renewed and updated based on the definition of the config file. If not set, mismatching certificates will be skipped.\n[update_cert_domains: <boolean> | default = False]\n\n# key vault uri for renewal of certifcate\nkey_vault_id : <string>\n\n# ACME Certificate Authority\nserver : <string>\n\n# Secret name within key vault for storing ACME Certificate authority account information\n[keyvault_account_secret_name: <regex> | default \"acme-account-$(network location of server)\"]\n# when server=https://example.com/something, then keyvault_account_secret_name=\"acme-account-example-com\"\n\n# config file content for certbot client\n[certbot.ini : <string> | default = \"\"]\n```\n\nNOTE: Either **managed_identity_id** or **sp_client_id** and **sp_client_secret** must be specified.\n\nNOTE: **certbot.ini** represents the [CERTBOT configuration file](https://eff-certbot.readthedocs.io/en/latest/using.html#configuration-file) and will be passed into certbot by the _acme_dns_azure_ library as defined. Misconfiguration will lead to failures of certbot and therefore of the renewal process.\n\nFollowing values will be added to the configurataion file by the _acme_dns_azure_ library per default:\n\n```yml\npreferred-challenges: dns\nauthenticator: dns-azure\nagree-tos: true\n```\n\n### `[<eab>]`\n\n```yml\n\n  # External account binding configuration for ACME, with key ID and base64encoded HMAC key\n  [enabled: <boolean> |  default = false]\n  [kid_secret_name : <string> | default=\"acme-eab-kid\"]\n  [hmac_key_secret_name : <secret> default=\"acme-eab-hmac-key\"]\n```\n\n```yml\ncertificates:\n  - <certificate>\n```\n\n### `<certificate>`\n\n```yml\n# Certbot certficate name. The name will also be used for Azure keyvault certificate name.\nname: <string>\n# Azure dns zone resource ID used for ACME DNS01 challenge\ndns_zone_resource_id: <string>\n# renewal in days before expiry for certificate to be renewed. Default is 30\n[renew_before_expiry: <int>]\ndomains:\n  - <domain>\n```\n\n### `<domain>`\n\n```yml\n# domain name this certificate is valid for. Wildcard supported.\nname: <string>\n# Azure dns zone resource ID used for ACME DNS01 challenge\n[dns_zone_resource_id: <string>]\n```\n\n## Manual running the library\n\nFor running the module as script 'sp_client_id' and 'sp_client_secret' are required. 'managed_identity_id' is not supported.\n\n```bash\n# from config file\npython acme_dns_azure/client.py --config-file-path $CONFIG_File_PATH\n# from env\npython acme_dns_azure/client.py --config-env-var $ENV_VAR_NAME_CONTAINING_CONFIG\n```\n\n## Permission Handling\n\nBest follow [security recommendations from Azure](https://docs.certbot-dns-azure.co.uk/en/latest/#:~:text=Example%3A%20Delegation%20%2B%20more,%C2%B6).\n\nWhen working with shared DNS Zones, one can work with DNS delegation with limited permissions:\n\nExample:\n\n| Record | Name                         | Value                  | Permission           |\n| ------ | ---------------------------- | ---------------------- | -------------------- |\n| TXT    | \\_acme-dedicated             | -                      | DNS Zone Contributor |\n| CNAME  | \\_acme-challenge.mysubdomain | \\_acme-dedicated.fqdn. | None                 |\n\nThe CNAME and TXT record must be created upfront to enable users to use certbot. The permissions are required on the identity triggering certbot.\n\nWith this setup, a DNS Zone owner can limit permissions and enable Users to Create/Renew certificates for their subdomain and ensuring that users cannot aquire certificates for other domains or interfer with existsing records.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "ACME client setup based on Certbot for dns-01 challenges via Azure Cloud services",
    "version": "0.4.0",
    "project_urls": {
        "Documentation": "https://zeiss.github.io/acme-dns-azure/",
        "Homepage": "https://github.com/ZEISS/acme-dns-azure",
        "PyPI": "https://pypi.org/project/acme-dns-azure/",
        "Repository": "https://github.com/ZEISS/acme-dns-azure"
    },
    "split_keywords": [
        "acme",
        " dns",
        " azure",
        " certbot",
        " letsencrypt"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4cbfa224cb5bfaeb26a90658f6d7a6c288b3c0415ea0274a8b37a9bcfa243a17",
                "md5": "77189212566cef38dc458c319a199b54",
                "sha256": "c1f2d51c1f53a5bb174176a3e4b982e4648942e12bc18f31ba5ae9614028590d"
            },
            "downloads": -1,
            "filename": "acme_dns_azure-0.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "77189212566cef38dc458c319a199b54",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.8",
            "size": 20786,
            "upload_time": "2024-08-02T07:50:02",
            "upload_time_iso_8601": "2024-08-02T07:50:02.002241Z",
            "url": "https://files.pythonhosted.org/packages/4c/bf/a224cb5bfaeb26a90658f6d7a6c288b3c0415ea0274a8b37a9bcfa243a17/acme_dns_azure-0.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "71263403d57937b37caffefa233756dc50e1dfdcd575d66f500bf27f237884d0",
                "md5": "1db1a0f8fab6e7a15495420504e08ed2",
                "sha256": "207a681ca66e91cd4d3ba8a0da4636a5245bc2d3a1affb85f717da22224b83b6"
            },
            "downloads": -1,
            "filename": "acme_dns_azure-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "1db1a0f8fab6e7a15495420504e08ed2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.8",
            "size": 19972,
            "upload_time": "2024-08-02T07:50:03",
            "upload_time_iso_8601": "2024-08-02T07:50:03.420921Z",
            "url": "https://files.pythonhosted.org/packages/71/26/3403d57937b37caffefa233756dc50e1dfdcd575d66f500bf27f237884d0/acme_dns_azure-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-08-02 07:50:03",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ZEISS",
    "github_project": "acme-dns-azure",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "acme-dns-azure"
}
        
Elapsed time: 2.91282s