Terraform ACME Provider

repository·main·Indexed 42 days ago

https://github.com/vancluever/terraform-provider-acme

A Terraform provider for automated SSL/TLS certificate management via the ACME v2 protocol, supporting Certificate Authorities like Let's Encrypt. It includes support for various DNS-01 challenge providers such as Alibaba Cloud DNS, Active24, Abion, and acmedns, and allows for the implementation of custom DNS plugins via gRPC.

Tokens
111.4K
Snippets
400
Records
530
Agent score
50%

What's inside Terraform ACME Provider

  1. Overview of the Terraform ACME Provider

    main

    The Terraform ACME Provider allows you to manage and generate SSL/TLS certificates using an ACME (Automated Certificate Management Environment) Certificate Authority (CA), such as Let's Encrypt, directly within your Terraform workflows.

    Key Constraints:

    • ACME Version: This provider supports ACME v2 only.
    • Maintenance Status: The provider is currently in long-term maintenance mode.
  2. Manage ACME TLS certificates with acme_certificate

    main

    The acme_certificate resource is used to create and manage ACME TLS certificates. It can be configured using either a common name and subject alternative names (SANs) or by providing an external Certificate Signing Request (CSR).

    resource "acme_certificate" "certificate" {
      account_key_pem           = acme_registration.reg.account_key_pem
      common_name               = "www.example.com"
      subject_alternative_names = ["www2.example.com"]
    
      dns_challenge {
        provider = "route53"
      }
    }
  3. Understand the ACME Provider maintenance status

    main

    The ACME provider is in long-term maintenance mode. This means:

    • What is maintained: The current feature set will receive maintenance, including necessary bug fixes. The provider will also attempt to keep up to date with the latest lego versions for as long as possible.
    • What is NOT maintained: No new major features will be added. This includes support for new ACME specification extensions, new features implemented by lego, or new Terraform features (such as write-only arguments).

    When submitting issues, please consider this maintenance status.

  4. How AWS credentials and regions are detected

    main

    The Route 53 provider automatically detects AWS credentials and regions using the standard AWS SDK logic.

    Credential Priority Order:

    1. Environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN.
    2. Shared credentials file (defaults to ~/.aws/credentials; use AWS_PROFILE to select a profile).
    3. Amazon EC2 IAM role.

    Region Priority Order:

    1. Environment variable: AWS_REGION.
    2. Shared configuration file (defaults to ~/.aws/config if AWS_SDK_LOAD_CONFIG is set; use AWS_PROFILE to select a profile).
  5. Understand the `exec` command-line interface and argument modes

    main

    The external program is called with specific arguments depending on the EXEC_MODE setting. The first argument is always the action: present (to add the record) or cleanup (to remove the record).

    Default Mode (EXEC_MODE=none)

    In the default mode, the program receives the action, the fully-qualified domain name (FQDN), and the record value.

    Command Pattern:

    • Present: myprogram present <FQDN> <record>
    • Cleanup: myprogram cleanup <FQDN> <record>

    RAW Mode (EXEC_MODE=RAW)

    When EXEC_MODE is set to RAW, the program receives the action, a -- delimiter (to prevent tokens starting with - from being parsed as flags), the raw domain, the token, and the key-auth value.

    Command Pattern:

    • Present: myprogram present -- <domain> <token> <key_auth>
    • Cleanup: myprogram cleanup -- <domain> <token> <key_auth>

    Note: The program must return a non-zero exit code to signal an error, which will cause the ACME process to abort.

    ### Default Mode Example
    # Command: ./update-dns.sh "present" "_acme-challenge.my.example.org." "MsijOYZxqyjGnFGwhjrhfg-Xgbl5r68WPda0J9EgqqI"
    
    ### RAW Mode Example
    # Command: ./update-dns.sh "present" "--" "my.example.org." "some-token" "KxAy-J3NwUmg9ZQuM-gP_Mq1nStaYSaP9tYQs5_-YsE.ksT-qywTd8058G-SHHWA3RAN72Pr0yWtPYmmY5UBpQ8"
  6. Configure httpreq modes and payload formats

    main

    The httpreq provider supports two modes via the mode argument (or HTTPREQ_MODE environment variable). The mode determines the JSON structure sent to the server during the challenge.

    Default Mode

    In the default mode, the provider sends a JSON payload containing the FQDN and the challenge value:

    {
      "fqdn": "_acme-challenge.domain.",
      "value": "LHDhK3oGRvkiefQnx7OOczTY5Tic_xZ6HcMOc_gmtoM"
    }

    RAW Mode

    When mode is set to RAW, the provider sends a different JSON structure:

    {
      "domain": "domain",
      "token": "token",
      "keyAuth": "key"
    }
  7. How Akamai credentials are detected and prioritized

    main

    The provider automatically detects Akamai credentials using the following priority order:

    1. Section-specific environment variables: If AKAMAI_EDGERC_SECTION is set to a value (e.g., PROD), the provider looks for:
      • AKAMAI_{SECTION}_HOST
      • AKAMAI_{SECTION}_ACCESS_TOKEN
      • AKAMAI_{SECTION}_CLIENT_TOKEN
      • AKAMAI_{SECTION}_CLIENT_SECRET
    2. Standard environment variables: If AKAMAI_EDGERC_SECTION is not defined or is set to default:
      • AKAMAI_HOST
      • AKAMAI_ACCESS_TOKEN
      • AKAMAI_CLIENT_TOKEN
      • AKAMAI_CLIENT_SECRET
    3. .edgerc file: The file path specified by AKAMAI_EDGERC (defaults to ~/.edgerc). The section can be specified via AKAMAI_EDGERC_SECTION.
    4. Fallback environment variables: The standard AKAMAI_HOST, AKAMAI_ACCESS_TOKEN, AKAMAI_CLIENT_TOKEN, and AKAMAI_CLIENT_SECRET variables.
  8. Configure certificate renewal behavior

    main

    The acme_certificate resource manages automatic certificate renewal based on the remaining lifetime of the certificate.

    Static Renewal

    Use min_days_remaining to specify a fixed number of days before expiry when a renewal should be triggered. If Terraform detects the certificate is within this range or already expired during a refresh, it will mark it for renewal on the next apply.

    • Note: Setting min_days_remaining to a value less than 0 bypasses renewal checks entirely.

    Dynamic Renewal

    For short-lived certificates (configured via validity_days or ACME profiles) or when using ACME Renewal Info (ARI) via use_renewal_info, use min_days_dynamic instead of min_days_remaining. This automatically calculates the renewal threshold:

    • 1/3 of the certificate's lifetime if the lifetime is greater than 10 days.
    • 1/2 of the certificate's lifetime if the lifetime is 10 days or less.
  9. Configure Azure DNS Service Discovery with Kusto filters

    main

    Lego automatically discovers Azure DNS zones using Azure ResourceGraph. You can limit discovery using AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP. To apply advanced filtering, use the AZURE_SERVICEDISCOVERY_FILTER environment variable to provide a Kusto query condition.

    Example filter logic:

    resources
    | where type =~ "microsoft.network/dnszones"
    | ${AZURE_SERVICEDISCOVERY_FILTER}
    | project subscriptionId, resourceGroup, name
  10. Configure DNS propagation checks

    main

    The provider performs DNS propagation checks to ensure TXT records are visible before requesting the certificate.

    Available Settings:

    • recursive_namesvers: A list of host:port resolvers to use for checking propagation (overrides system defaults). Useful for split-horizon DNS.
    • disable_authoritative_propagation: If true, bypasses the check against authoritative DNS servers. Use this in air-gapped environments or when the Terraform runner lacks outbound access to authoritative servers.
    • propagation_wait: A fixed delay (in seconds) applied per-domain. This skips all propagation checks and simply waits for the specified time. This conflicts with pre_check_delay and recursive_nameservers.
    • pre_check_delay: A delay (in seconds) inserted after every DNS challenge record. This is applied per-domain.
    resource "acme_certificate" "certificate" {
      recursive_nameservers             = ["8.8.8.8:53"]
      disable_authoritative_propagation = true
    
      dns_challenge {
        provider = "route53"
      }
    }