|
1 | 1 | # lets-encrypt-certificates |
2 | 2 |
|
| 3 | +A Terraform module to obtain publicly trusted SSL certificates from the Let's Encrypt Certificate Authority. This module addresses the lack of a native, integrated certificate management solution in Azure, equivalent to AWS Certificate Manager. |
| 4 | + |
| 5 | +## Features |
| 6 | +- Integrates the Python [Certbot](https://github.com/certbot/certbot) package, since pip3 conveniently manages the extensive dependencies. |
| 7 | +- Wildcard certificate support. |
| 8 | +- Rolls up the configuration and log files into a persistent state. |
| 9 | +- State storage in Azure Storage Account. |
| 10 | +- Seamless certificate renewals within 30 days of expiry. |
| 11 | +- Automates the public DNS challenge TXT records via [certbot‑dns‑azure](https://docs.certbot-dns-azure.co.uk/en/latest/) plugin. |
| 12 | +- Supports DNS challenges for nested subdomains without needing to create delegated DNS zones (e.g. _www.private.domain.com_ challenge via _domain.com_) |
| 13 | +- Certificates are stored in Azure Key Vault as Certificate objects, skipped if thumbprint remains unchanged. |
| 14 | +- A fallback .pfx file is also stored as a base64-encoded secret for cases where Key Vault Certificate objects cannot be consumed directly. |
| 15 | +- Multiple subscription support (hub/spoke model). |
| 16 | +- Multiple region support. |
| 17 | + |
| 18 | +## Requirements |
| 19 | +- A Storage Account container named `certbot-state`. |
| 20 | +- Let's Encrypt does not allow concurrent certificate requests from a single account, so this module obtains all specified certificates serially in a single execution. Avoid using the for_each meta-argument or running multiple instances in parallel. |
| 21 | +- A bash shell. |
| 22 | +- This module runs as a null resource, so it needs its own authentication with Azure since it launches in the context of the shell which launched Terraform. The recommended approach for CI/CD pipelines is to launch Terraform from an authenticated shell. e.g. in Azure DevOps use [AzureCLI@2 task](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/azure-cli-v2?view=azure-pipelines) with: |
| 23 | + ```yaml |
| 24 | + addSpnToEnvironment: true |
| 25 | + scriptType: bash |
| 26 | + ``` |
| 27 | + This will result in the parent shell being authenticated with Azure (for the null resource), and Terraform will use those same session credentials exported via environment variables. |
| 28 | +
|
| 29 | +## Example Usage |
| 30 | +
|
| 31 | +```terraform |
| 32 | +module "lets_encrypt_certificates" { |
| 33 | + source = "../../dtos-devops-templates/infrastructure/modules/lets-encrypt-certificates" |
| 34 | + |
| 35 | + certificates = { |
| 36 | + nationalscreening_wildcard = "*.nationalscreening.nhs.uk" |
| 37 | + screening_wildcard = "*.screening.nhs.uk" |
| 38 | + screening_www = "www.screening.nhs.uk" |
| 39 | + } |
| 40 | + |
| 41 | + dns_zone_names = { |
| 42 | + nationalscreening = "nationalscreening.nhs.uk" |
| 43 | + screening = "screening.nhs.uk" |
| 44 | + } |
| 45 | + |
| 46 | + dns_zone_resource_group_name = var.dns_zone_rg_name_public |
| 47 | + environment = var.environment |
| 48 | + email = var.LETS_ENCRYPT_CONTACT_EMAIL |
| 49 | + key_vaults = module.key_vault # a map of Azure Key Vault objects, keyed by region name |
| 50 | + storage_account_name_hub = var.HUB_BACKEND_AZURE_STORAGE_ACCOUNT_NAME |
| 51 | + subscription_id_hub = var.SUBSCRIPTION_ID_HUB |
| 52 | + subscription_id_target = var.SUBSCRIPTION_ID_TARGET |
| 53 | +} |
| 54 | +``` |
| 55 | + |
| 56 | +## Example Output |
| 57 | + |
| 58 | +Note the compound key `${naming_key}-${region}`: |
| 59 | + |
| 60 | +```terraform |
| 61 | +key_vault_certificates = { |
| 62 | + "nationalscreening_wildcard-uksouth" = { |
| 63 | + "id" = "redacted" |
| 64 | + "location" = "uksouth" |
| 65 | + "name" = "wildcard-nationalscreening-nhs-uk" |
| 66 | + "naming_key" = "nationalscreening_wildcard" |
| 67 | + "pfx_blob_secret_name" = "pfx-wildcard-nationalscreening-nhs-uk" |
| 68 | + "subject" = "*.nationalscreening.nhs.uk" |
| 69 | + "versionless_id" = "redacted" |
| 70 | + "versionless_secret_id" = "redacted" |
| 71 | + } |
| 72 | + "screening_wildcard-uksouth" = { |
| 73 | + "id" = "redacted" |
| 74 | + "location" = "uksouth" |
| 75 | + "name" = "wildcard-screening-nhs-uk" |
| 76 | + "naming_key" = "screening_wildcard" |
| 77 | + "pfx_blob_secret_name" = "pfx-wildcard-screening-nhs-uk" |
| 78 | + "subject" = "*.screening.nhs.uk" |
| 79 | + "versionless_id" = "redacted" |
| 80 | + "versionless_secret_id" = "redacted" |
| 81 | + } |
| 82 | + "screening_www-uksouth" = { |
| 83 | + "id" = "redacted" |
| 84 | + "location" = "uksouth" |
| 85 | + "name" = "www-screening-nhs-uk" |
| 86 | + "naming_key" = "screening_www" |
| 87 | + "pfx_blob_secret_name" = "pfx-www-screening-nhs-uk" |
| 88 | + "subject" = "www.screening.nhs.uk" |
| 89 | + "versionless_id" = "redacted" |
| 90 | + "versionless_secret_id" = "redacted" |
| 91 | + } |
| 92 | +} |
| 93 | +``` |
| 94 | + |
3 | 95 | ## Terraform documentation |
4 | 96 | For the list of inputs, outputs, resources... check the [terraform module documentation](tfdocs.md). |
0 commit comments