The DevOps Jedi

Taking the cloud by storm one line of code at a time....

Securing Internal Workloads With Let’s Encrypt & Azure Public DNS

2025-09-218 min readCertificatesDarren Johnson

Securing internal workloads with TLS encryption is no longer optional, even when services are only accessible from within private/on premises networks. Organisations in regulated sectors are increasingly seeking ways to ensure private services benefit from the same level of cryptographic assurance as public-facing workloads. One approach is to use Let’s Encrypt certificates, issued via the public certificate authority (CA), combined with Azure Public DNS to validate domain ownership while keeping workloads accessible only on private IP ranges.

This article explores why and how this approach works, with practical implementation details, security considerations, and best practices.

Why Use Public Certificates For Internal Services?

Traditionally, organisations have relied on internal certificate authorities (CAs) or self-signed certificates for private workloads. However, this can create several challenges:

  • Trust distribution: Internal CA root certificates must be deployed and managed across all endpoints. This approach often proves brittle, especially in hybrid or BYOD environments.
  • Modern client compatibility: Third-party applications, APIs, or mobile devices will not trust internal root certificates by default. Publicly trusted certificates solve this issue.
  • Automation and cost: Let’s Encrypt offers zero-cost, automated certificate issuance and renewal, reducing administrative overhead.
  • Compliance: Frameworks such as ISO 27001 and NCSC guidance encourage minimising reliance on custom certificate trust stores and favour industry-standard PKI practices.

By using Let’s Encrypt certificates internally, organisations can ensure trusted TLS for both end-users and machine-to-machine communication, while avoiding the complexity of managing a private PKI.

Leveraging Azure Public DNS For Domain Ownership

Let’s Encrypt validates domain ownership via challenges. The two most common are:

  • DNS-01 challenge: Prove you control the DNS for the domain name by creating a specific DNS TXT record.
  • HTTP-01 challenge: Prove you control the DNS for the domain name by serving a token at a public endpoint.

For internal workloads that are not internet-facing, the DNS-01 challenge is most appropriate, and is what I will explore today. With Azure Public DNS, terraform can use the acme_certificate resource to automate the placement of required TXT records to prove control over a domain without ever exposing the service publicly.

Options For DNS Name Resolution To Private IP Addresses Using CNAME Redirection Or Split-Horizon DNS

Once Let’s Encrypt has validated ownership of the domain via Azure Public DNS, you still need to ensure that internal users and workloads resolve the service name to a private IP rather than a public endpoint. When I say a service name, I mean a Fully Qualified Domain Name (FQDN) that does not identify the host it is running on.

There are two main design patterns to achieve this:

Option 1: Public CNAME Redirecting To An Internal-Only DNS Record

In this approach, the public DNS zone (hosted in Azure Public DNS) returns a CNAME record pointing to a host record that only exists within your internal DNS infrastructure (for example, an Azure Private DNS Zone or on-premises DNS).

  • The Let’s Encrypt validation succeeds because the _acme-challenge TXT record is published in the public zone.
  • The application record in the public zone is a CNAME that directs resolution to an internal DNS name (e.g. app.tls.internaldomain.co.uk).
  • Internal resolvers can resolve this internal DNS name to the correct private IP address (e.g. 192.168.100.50).
  • From the public internet, the CNAME target cannot be resolved, meaning the workload is unreachable externally.

Example:

# Azure Public DNS Zone
app.tls.externaldomain.co.uk.  3600  IN  CNAME  app.tls.internaldomain.co.uk.
_acme-challenge.tls.externaldomain.co.uk.  IN  TXT  "random-token"

# Azure Private DNS Zone
app.tls.internaldomain.co.uk.  IN  A  192.168.100.50

This option provides strict separation between public DNS validation and private resolution. It does require maintaining both a public DNS zone and a separate internal namespace, but this can easily be achieved using Terraform.

The private/internal namespace does not have to match your corporate namespace, it is just required to return a private IP address to the client. This design keeps your corporate namespace out of DNS queries and logs. You can even go one step further and use a neutral private/internal zone to return another CNAME record which does map to your corporate namespace, such as app.adds-domain.local..

Internal Client

Internal Client

  1. Internal client sends a request for app.tls.externaldomain.co.uk to the Azure Public DNS Zone tls.externaldomain.co.uk.
  2. Azure Public DNS Zone responds with a CNAME record for app.tls.internaldomain.co.uk.
  3. Internal client sends request for app.tls.internaldomain.co.uk to the Virtual Network linked Azure Private DNS Zone tls.internaldomain.co.uk.
  4. Azure Private DNS Zone responds with an A record with the private IP address.

Internet Client

Internet Client

  1. Internet client sends a request for app.tls.externaldomain.co.uk to the Azure Public DNS Zone tls.externaldomain.co.uk.
  2. Azure Public DNS Zone responds with a CNAME record for app.tls.internaldomain.co.uk.
  3. Internet client sends request for app.tls.internaldomain.co.uk. but this FQDN is not known to public DNS resolution, so no private IP address is returned.

Option 2: Split-Horizon DNS With A Private Azure Zone

Another common approach is to use split-horizon DNS , where the same domain (tls.externaldomain.co.uk) exists in both public and private DNS zones.

  • The public zone (in Azure Public DNS) contains only what’s necessary for Let’s Encrypt validation, such as _acme-challenge TXT records.
  • The private zone (in Azure Private DNS, linked to your Virtual Network’s) contains the same service name (e.g. app.tls.externaldomain.co.uk), but resolves directly to the private IP address of the workload.
  • Internal clients querying DNS will resolve against the private zone and reach the workload via the private IP.
  • External queries will not return the private zone results, so workloads remain unreachable from the internet.

Example:

# Azure Public DNS Zone
_acme-challenge.tls.externaldomain.co.uk.  IN  TXT  "random-token"

# Azure Private DNS Zone
app.tls.externaldomain.co.uk.  IN  A  192.168.100.50

This approach avoids the need for a separate internal namespace and keeps the service name consistent between public and private resolution. Administrators must manage identical namespaces carefully. Administrators must also create any required public IP addresses in the Azure Private DNS Zone as this will be the only zone to respond to internal network DNS requests.

Split-Horizon DNS

Split-Horizon DNS

  1. Internet client sends a request for app.tls.externaldomain.co.uk to the Azure Public DNS Zone tls.externaldomain.co.uk.
  2. Azure Public DNS Zone responds with a NXDOMAIN (Non-Existent Domain) code.
  3. Internal client sends request for app.tls.externaldomain.co.uk. to the Virtual Network linked Azure Private DNS Zone tls.externaldomain.co.uk.
  4. Azure Private DNS Zone responds with an A record with the private IP address.

Key Takeaway: Both options achieve the same outcome: Let’s Encrypt can validate ownership of the domain via the public DNS, while internal clients are seamlessly directed to private IP addresses. The choice depends largely on how the organisation controls DNS management and architecture.

Walkthrough: Issuing A Certificate

Step 1: Prepare Azure Public DNS

Create an Azure Public DNS Zone (e.g. tls.externaldomain.co.uk) and delegate it at your domain registrar to Azure’s DNS name servers .

Step 2: Automate The DNS Challenge, Certificate Request, Issuance & Storage

Terraform can be used to automate the DNS challenge and issue the certificate in a single configuration.

The high level steps involved are:

  • Create an ACME Account & Private Key
  • Create a separate dedicated Private Key for each Certificate (Best Practice)
  • Create a Certificate Signing Request (CSR)
  • Request the Certificate from Let’s Encrypt using the CSR & Private Key (this step includes the DNS challenge)
  • Convert the certificate to PKCS12/PFX format & import it to an Azure Key vault for storage and retrieval (not strictly required, but Best Practice for use within Azure)

Step 3: Redirect Internal Traffic

Ensure internal DNS (Azure Private DNS or conditional forwarders) maps the service name to a private IP. Deploy the certificate to the internal workload, ideally directly from Key Vault.

Security Considerations & Compliance

While this approach offers strong benefits, there are caveats:

  • Certificate transparency: Let’s Encrypt logs all issued certificates publicly. You can view these logs at https://crt.sh . Certificate Transparency (CT) logs may expose internal hostnames, which is why a service name should be used for the certificate. Organisations should avoid exposing sensitive naming schemes.
  • Access control: Limit who can update DNS TXT records in Azure. An attacker with compromised credentials could issue fraudulent certificates.
  • NCSC guidance: The UK NCSC encourages the use of strong, publicly trusted PKI where possible but notes risks of disclosing internal naming. Using neutral, non-sensitive service names instead of hostnames helps mitigate this.
  • ISO 27001 alignment: This approach supports Annex A.10.1 (cryptographic controls) by ensuring systems consistently apply encryption.

Best Practices For Certificate Hygiene

To maintain operational resilience and compliance, cloud security engineers should adopt the following practices:

  1. Automate renewals – Use scheduled jobs or containerised agents to handle renewals without human intervention.
  2. Monitor expiry – Integrate certificate monitoring with SIEM/SOAR to alert before expiry.
  3. Avoid sensitive hostnames – Use neutral subdomains to avoid leaking internal details into CT logs.
  4. Enforce strong cipher suites – Ensure internal workloads are hardened to modern TLS configurations.
  5. Document and audit – Keep records of certificate issuance and DNS automation as part of ISO 27001 audit trails.
  6. Regular reviews – Periodically assess whether internal CA or managed private PKI services (e.g. Azure Key Vault Certificates) may be more appropriate.

Conclusion

Let’s Encrypt, combined with Azure Public DNS, provides a practical, automated method of securing internal workloads with publicly trusted certificates. By leveraging DNS-01 challenges and carefully configuring DNS resolution, organisations can balance security, compliance, and usability across hybrid and regulated environments.

When implemented with appropriate safeguards, this approach simplifies certificate management, improves interoperability, and ensures that encryption standards are aligned with industry best practice.