Certificate Leaf
The certificate_leaf resource generates leaf certificates signed by a Certificate Authority (CA). These are end-entity certificates used for servers, clients, or other applications that require TLS/SSL certificates signed by a trusted authority.
Use Cases
Section titled “Use Cases”As a lab author, you can use certificate_leaf resources to:
- Server Certificate Generation: Create TLS certificates for web servers, APIs, and other network services
- Client Certificate Authentication: Generate client certificates for mutual TLS authentication scenarios
- Service-to-Service Communication: Enable secure communication between microservices using signed certificates
Certificate leaf resources provide signed certificates for specific services while maintaining the certificate chain of trust.
HCL Syntax
Section titled “HCL Syntax”Basic Syntax
Section titled “Basic Syntax”resource "certificate_leaf" "name" { ca_key = resource.certificate_ca.root.private_key.path ca_cert = resource.certificate_ca.root.certificate.path output = "./server-certs"}
Full Syntax
Section titled “Full Syntax”resource "certificate_leaf" "name" { ca_key = resource.certificate_ca.root.private_key.path ca_cert = resource.certificate_ca.root.certificate.path output = "./server-certs"
dns_names = [ "localhost", "api.example.com", "www.example.com" ]
ip_addresses = [ "127.0.0.1", "192.168.1.100", "10.0.0.5" ]}
Fields
Section titled “Fields”Field | Required | Type | Description |
---|---|---|---|
ca_ | ✓ | string | Path to the CA private key file used for signing |
ca_ | ✓ | string | Path to the CA certificate file |
output | ✓ | string | Output directory where certificate and key files will be written |
dns_ | list(string) | DNS names to include in the certificate’s Subject Alternative Names (SAN) | |
ip_ | list(string) | IP addresses to include in the certificate’s Subject Alternative Names (SAN) |
Computed Attributes
Section titled “Computed Attributes”These attributes are set by the system after certificate generation:
Field | Type | Description |
---|---|---|
private_key |
File | The private key of the generated leaf certificate |
public_key_pem |
File | The PEM-formatted public key |
public_key_ssh |
File | The SSH-formatted public key |
certificate |
File | The generated leaf certificate signed by the CA |
File Object Structure
Section titled “File Object Structure”The File object contains information about generated certificate files:
Field | Type | Description |
---|---|---|
filename | string | The name of the generated file |
directory | string | The directory where the file is written |
path | string | The full absolute path to the file |
contents | string | The contents of the generated file |
Validation Rules
Section titled “Validation Rules”- CA key and certificate files must exist and be valid
- Output directory must be a valid path
- DNS names must be valid domain names or hostnames
- IP addresses must be valid IPv4 or IPv6 addresses
- Generated files are written with appropriate permissions for certificate files
- Certificate generation is idempotent - same configuration produces same output
- Directory structure is created automatically if it doesn’t exist
Examples
Section titled “Examples”Simple Server Certificate
Section titled “Simple Server Certificate”resource "certificate_ca" "root" { output = "./ca"}
resource "certificate_leaf" "server" { ca_key = resource.certificate_ca.root.private_key.path # e.g., "./ca/private_key.pem" ca_cert = resource.certificate_ca.root.certificate.path # e.g., "./ca/certificate.pem" output = "./server-certs"
dns_names = ["localhost"] ip_addresses = ["127.0.0.1"]}
output "server_cert_path" { value = resource.certificate_leaf.server.certificate.path # e.g., "./server-certs/certificate.pem"}
Multi-Domain Web Certificate
Section titled “Multi-Domain Web Certificate”resource "certificate_leaf" "web" { ca_key = resource.certificate_ca.root.private_key.path ca_cert = resource.certificate_ca.root.certificate.path output = "./web-certs"
dns_names = [ "example.com", "www.example.com", "api.example.com", "admin.example.com" ]
ip_addresses = [ "192.168.1.10", "10.0.0.100" ]}
resource "container" "web_server" { image { name = "nginx:alpine" }
volume { source = resource.certificate_leaf.web.certificate.path # e.g., "./web-certs/certificate.pem" destination = "/etc/ssl/certs/server.crt" type = "bind" read_only = true }
volume { source = resource.certificate_leaf.web.private_key.path # e.g., "./web-certs/private_key.pem" destination = "/etc/ssl/private/server.key" type = "bind" read_only = true }
port { local = "443" host = "8443" }}
Client Certificate Authentication
Section titled “Client Certificate Authentication”resource "certificate_leaf" "client" { ca_key = resource.certificate_ca.root.private_key.path ca_cert = resource.certificate_ca.root.certificate.path output = "./client-certs"
dns_names = ["client.internal"]}
resource "template" "client_config" { source = <<-EOF client: certificate: ${resource.certificate_leaf.client.certificate.path} # e.g., "./client-certs/certificate.pem" private_key: ${resource.certificate_leaf.client.private_key.path} # e.g., "./client-certs/private_key.pem" ca_certificate: ${resource.certificate_ca.root.certificate.path} # e.g., "./ca/certificate.pem"
tls: verify_peer: true verify_host: true EOF
destination = "./client-config.yaml"}
Service Mesh Certificates
Section titled “Service Mesh Certificates”resource "certificate_ca" "service_mesh_ca" { output = "./mesh-ca"}
# API service certificateresource "certificate_leaf" "api_service" { ca_key = resource.certificate_ca.service_mesh_ca.private_key.path ca_cert = resource.certificate_ca.service_mesh_ca.certificate.path output = "./api-service-certs"
dns_names = [ "api-service", "api-service.default.svc.cluster.local" ]}
# Database service certificateresource "certificate_leaf" "database_service" { ca_key = resource.certificate_ca.service_mesh_ca.private_key.path ca_cert = resource.certificate_ca.service_mesh_ca.certificate.path output = "./database-service-certs"
dns_names = [ "database-service", "database-service.default.svc.cluster.local" ]}
resource "container" "api" { image { name = "api:latest" }
environment = { TLS_CERT_FILE = resource.certificate_leaf.api_service.certificate.path # e.g., "./api-service-certs/certificate.pem" TLS_KEY_FILE = resource.certificate_leaf.api_service.private_key.path # e.g., "./api-service-certs/private_key.pem" CA_CERT_FILE = resource.certificate_ca.service_mesh_ca.certificate.path # e.g., "./mesh-ca/certificate.pem" }}
Load Balancer Certificate
Section titled “Load Balancer Certificate”resource "certificate_leaf" "load_balancer" { ca_key = resource.certificate_ca.root.private_key.path ca_cert = resource.certificate_ca.root.certificate.path output = "./lb-certs"
dns_names = [ "lb.example.com", "loadbalancer.internal", "*.apps.example.com" # Wildcard certificate ]
ip_addresses = [ "192.168.1.50", # Load balancer IP "10.0.0.50" # Internal IP ]}
resource "template" "nginx_ssl_config" { source = <<-EOF server { listen 443 ssl; server_name lb.example.com *.apps.example.com;
ssl_certificate ${resource.certificate_leaf.load_balancer.certificate.path}; # e.g., "./lb-certs/certificate.pem" ssl_certificate_key ${resource.certificate_leaf.load_balancer.private_key.path}; # e.g., "./lb-certs/private_key.pem"
ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5;
location / { proxy_pass http://backend; } } EOF
destination = "./nginx-ssl.conf"}
Certificate Contents Usage
Section titled “Certificate Contents Usage”resource "certificate_leaf" "app_cert" { ca_key = resource.certificate_ca.root.private_key.path ca_cert = resource.certificate_ca.root.certificate.path output = "./app-certs"
dns_names = ["app.local"]}
resource "container" "secure_app" { image { name = "myapp:latest" }
environment = { # Pass certificate contents directly as environment variables TLS_CERTIFICATE = resource.certificate_leaf.app_cert.certificate.contents TLS_PRIVATE_KEY = resource.certificate_leaf.app_cert.private_key.contents TLS_CA_CERT = resource.certificate_ca.root.certificate.contents
# Certificate metadata CERT_FILENAME = resource.certificate_leaf.app_cert.certificate.filename # e.g., "certificate.pem" CERT_DIRECTORY = resource.certificate_leaf.app_cert.certificate.directory # e.g., "./app-certs" }}
Best Practices
Section titled “Best Practices”- Subject Alternative Names: Always include relevant DNS names and IP addresses for proper certificate validation
- Certificate Organization: Use descriptive output directories to organize certificates by service or purpose
- File References: Use
.path
for file system operations and.contents
for inline certificate data - Security: Protect private keys and limit access to certificate files
- Validation: Include all hostnames and IPs that clients will use to connect to your services
- Certificate Chain: Ensure CA certificates are properly distributed to clients for validation
- Naming Conventions: Use clear naming that indicates the certificate’s purpose and scope
- Environment Separation: Generate separate certificates for different environments (dev, staging, prod)