-
Notifications
You must be signed in to change notification settings - Fork 1
Dynamic TLS Certificates
This document describes how dynamic TLS certificates can be used in the system and the structure of the certificates storage in the deployments bucket.
TLS certificates are used to secure connections to the proxy service. The system supports dynamic TLS certificates, which can be added to and removed from the deployments bucket at runtime. The proxy service will automatically discover and use these certificates based on the requested domain name.
Note that Deno Deploy does not currently provide a system for provisioning TLS certificates.
In order for dynamic TLS certificates to work, TLS termination must happen in the proxy service itself, not in the (AWS) Network Load Balancer.
When using our Terraform module, this is controlled by setting:
module "mycluster" {
source = "../modules/aws_region"
enable_loadbalancer_tls_termination = false
// etc...
}
When this setting is false
, the NLB connects to port 8443 on the proxy (which
expects HTTPS), rather than port 8080 (which expects HTTP).
Certificates are stored in the S3 deployment bucket in a structured format. The
bucket name is determined by the APPCONFIG_BUCKET
environment variable.
Note: The S3 bucket used for TLS certificates is the same bucket used for storing AppConfig deployment configurations. See AppConfig for more information about the shared bucket structure and its use for managing deployments.
certificates/
├── by-domain/
│ ├── example.com # JSON file with certificate pointers
│ ├── *.example.com # Wildcard certificate pointers
│ └── ...
└── by-uid/
├── {certificate-uid}/
│ ├── cert.pem # Certificate chain in PEM format
│ └── key.pem # Private key in PEM format
└── ...
The by-domain
directory contains JSON files that map domain names to
certificate UIDs. Each file is named after the domain it covers and contains a
list of certificate pointers.
Example of a certificate pointer file (certificates/by-domain/example.com
):
[
{
"uid": "certificate-uid-123",
"names": ["example.com", "www.example.com"],
"validFrom": "2023-01-01T00:00:00Z",
"validUntil": "2024-01-01T00:00:00Z",
"keyAlgo": "ec"
}
]
The pointer includes:
-
uid
: Unique identifier for the certificate -
names
: List of domain names covered by this certificate -
validFrom
: Certificate validity start date (ISO 8601) -
validUntil
: Certificate validity end date (ISO 8601) -
keyAlgo
: Key algorithm type ("ec" for ECDSA or "rsa" for RSA)
The actual certificate files are stored in the by-uid
directory, organized by
certificate UID:
-
cert.pem
: The full certificate chain in PEM format -
key.pem
: The private key in PEM format
When a TLS connection is established:
- The proxy extracts the requested domain name from the SNI extension in the ClientHello
- It checks its in-memory cache for a matching certificate
- If not found, it looks for an exact domain match in
certificates/by-domain/{domain}
- If no exact match, it looks for a wildcard match in
certificates/by-domain/*.{base-domain}
- The certificate is loaded, validated, and cached for future connections
The system prioritizes ECDSA certificates over RSA when both are available and the client supports both.
To add a new certificate:
- Generate or obtain a certificate and private key for your domain
- Create a unique identifier (UID) for the certificate
- Store the certificate and key in the appropriate locations:
certificates/by-uid/{uid}/cert.pem
certificates/by-uid/{uid}/key.pem
- Create or update the domain pointer file:
certificates/by-domain/{domain}
Certificates can be invalidated by:
- Modifying the pointer file to remove the certificate UID
- The system also periodically checks certificate validity and will stop using expired certificates