Many developers face the challenge of programmatically managing SSL certificates for dynamically created subdomains (e.g., customer1.example.com, customer2.example.com). The traditional approach of creating individual CSRs for each subdomain and getting them signed by a CA is cumbersome, especially when dealing with non-technical end users.
There are two primary approaches to solve this:
Option 1: Wildcard Certificates
A wildcard certificate (*.example.com) covers all subdomains, but has limitations:
# Example OpenSSL command to generate wildcard CSR
openssl req -new -newkey rsa:2048 -nodes -keyout wildcard.key -out wildcard.csr -subj "/CN=*.example.com"
Option 2: Private CA with Intermediate Certificate
More flexible solution involves creating your own Certificate Authority:
# Create root CA
openssl genrsa -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt -subj "/CN=My Private CA"
# Create intermediate certificate
openssl genrsa -out intermediate.key 2048
openssl req -new -key intermediate.key -out intermediate.csr -subj "/CN=Intermediate CA"
openssl x509 -req -in intermediate.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out intermediate.crt -days 365 -sha256
Here's a Python example using cryptography library to issue certificates:
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from datetime import datetime, timedelta
def issue_certificate(subdomain, intermediate_key, intermediate_cert):
# Generate private key
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
subject = x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, f"{subdomain}.example.com")
])
builder = x509.CertificateBuilder()
builder = builder.subject_name(subject)
builder = builder.issuer_name(intermediate_cert.subject)
builder = builder.not_valid_before(datetime.utcnow())
builder = builder.not_valid_after(datetime.utcnow() + timedelta(days=90))
builder = builder.serial_number(x509.random_serial_number())
builder = builder.public_key(key.public_key())
builder = builder.add_extension(
x509.SubjectAlternativeName([x509.DNSName(f"{subdomain}.example.com")]),
critical=False
)
certificate = builder.sign(
private_key=intermediate_key,
algorithm=hashes.SHA256()
)
return key, certificate
When automating subdomain creation, you'll need to programmatically update DNS records. Here's an example using AWS Route 53 API:
import boto3
def create_subdomain(subdomain, ip_address):
client = boto3.client('route53')
response = client.change_resource_record_sets(
HostedZoneId='YOUR_ZONE_ID',
ChangeBatch={
'Changes': [{
'Action': 'CREATE',
'ResourceRecordSet': {
'Name': f'{subdomain}.example.com',
'Type': 'A',
'TTL': 300,
'ResourceRecords': [{'Value': ip_address}]
}
}]
}
)
return response
- Keep your root CA key offline
- Set appropriate certificate lifetimes (30-90 days for end-entity certs)
- Implement certificate revocation checking
- Monitor for certificate expiration
For public-facing services, consider using ACME protocol with Let's Encrypt:
from certbot import main as certbot_main
def get_letsencrypt_cert(subdomain):
certbot_main.main([
'certonly',
'--standalone',
'--non-interactive',
'--agree-tos',
'--email', 'admin@example.com',
'-d', f'{subdomain}.example.com'
])
When developing Windows applications that require SSL/TLS termination, we often face the certificate management dilemma. The ideal scenario would involve obtaining a parent certificate that can sign subordinate certificates for dynamic subdomains (customer1.example.com, customer2.example.com, etc.). This is technically possible through a proper CA hierarchy implementation.
Two primary approaches exist:
1. Wildcard Certificate (*.example.com)
- Pros: Simple implementation, single certificate
- Cons: Private key must be distributed, security risk
2. Intermediate CA Certificate
- Pros: Can issue new certificates dynamically
- Cons: More complex setup, higher cost
Here's a basic example using .NET's CertificateRequest API to create subordinate certificates:
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
public X509Certificate2 CreateSubordinateCertificate(
X509Certificate2 caCert,
string subdomain,
RSA privateKey)
{
var sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddDnsName($"{subdomain}.example.com");
var request = new CertificateRequest(
$"CN={subdomain}.example.com",
privateKey,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(sanBuilder.Build());
return request.Create(
caCert,
DateTimeOffset.Now,
DateTimeOffset.Now.AddYears(1),
new byte[] { 1, 2, 3, 4 });
}
Major CAs offer Extended Validation (EV) code signing certificates that can function as intermediate CAs, but prices vary significantly:
- DigiCert: $500-$2000/year for private CA functionality
- Sectigo: $300-$1500/year with sub-CA capabilities
- GlobalSign: Enterprise plans with custom CA features
For simpler deployments consider:
// Auto-renewing Let's Encrypt certificates
public async Task SetupLetsEncrypt(string domain)
{
using var manager = new CertificateManager();
await manager.AddCertificate(
domains: new[] { domain },
email: "admin@example.com",
keyAlgorithm: KeyAlgorithm.RSA,
keySize: 2048);
}
Combine certificate generation with DNS API calls for complete automation:
// Example using Cloudflare API
public async Task CreateDnsRecord(
string subdomain,
string ipAddress,
string zoneId)
{
var client = new CloudflareClient(API_KEY);
await client.CreateDnsRecordAsync(
zoneId,
new DnsRecord {
Type = "A",
Name = subdomain,
Content = ipAddress,
TTL = 120
});
}
Always implement proper key storage and rotation policies:
- Use Windows Certificate Store or Azure Key Vault
- Implement certificate revocation checking
- Set appropriate certificate lifetimes (30-90 days recommended)