Wildcard Certificate #
Sertifikat wildcard adalah jenis sertifikat TLS yang dirancang untuk mengamankan domain induk (apex domain) beserta seluruh subdomain tingkat pertama (first-level subdomains) di bawahnya menggunakan satu sertifikat tunggal. Sebagai contoh, sertifikat untuk *.example.com secara otomatis berlaku dan valid untuk app.example.com, api.example.com, blog.example.com, maupun subdomain lainnya. Pendekatan ini sangat populer karena menyederhanakan manajemen TLS dan meminimalkan kebutuhan untuk meminta sertifikat baru setiap kali kita menambahkan subdomain baru pada infrastruktur kita.
Namun, ada satu aturan fundamental dalam spesifikasi ACME yang wajib kita pahami: sertifikat wildcard hanya dapat diperoleh melalui metode verifikasi DNS-01 challenge. Kita tidak dapat menggunakan tantangan HTTP-01 atau TLS-ALPN-01 untuk mendapatkan sertifikat wildcard. Pembatasan ini bukan merupakan limitasi dari Caddy, melainkan aturan keamanan ketat yang ditetapkan oleh seluruh penyedia Certificate Authority (CA) global untuk memastikan bahwa pemohon benar-benar mengontrol zona DNS domain secara keseluruhan, bukan sekadar mengendalikan satu server web tertentu.
Mengapa Wildcard Membutuhkan DNS-01? #
Alasan teknis di balik kewajiban penggunaan DNS-01 challenge untuk sertifikat wildcard bersifat mendasar pada aspek keamanan verifikasi:
Tantangan HTTP-01 untuk *.example.com (✗ TIDAK DAPAT DILAKUKAN):
1. CA meminta: "Taruh token di http://subdomain-acak.example.com/.well-known/acme-challenge/..."
2. Masalah: Karena ini wildcard, subdomain tersebut bisa jadi belum ada atau mengarah ke IP
yang berbeda. CA tidak mungkin menebak dan melakukan HTTP GET ke semua kemungkinan subdomain.
3. HTTP-01 hanya membuktikan kontrol atas server web di IP tertentu, bukan atas domain secara keseluruhan.
Tantangan DNS-01 untuk *.example.com (✓ BERHASIL & DISETUJUI CA):
1. CA meminta: "Buat TXT record dengan nama _acme-challenge.example.com di zona DNS domain induk."
2. Caddy membuat TXT record tersebut melalui API penyedia DNS.
3. CA melakukan kueri DNS TXT ke domain induk (apex domain).
4. Karena catatan DNS berada pada tingkat zona domain induk, keberadaan record tersebut membuktikan
secara mutlak bahwa pemohon memiliki akses administratif penuh terhadap seluruh zona DNS
domain tersebut, sehingga berhak mengamankan semua subdomain (*.example.com).
Kapan Memilih Wildcard Certificate? #
Meskipun sertifikat wildcard sangat praktis, ia tidak selalu menjadi pilihan terbaik untuk semua skenario. Tabel di bawah membandingkan kapan kita sebaiknya menggunakan wildcard dan kapan sertifikat individual (non-wildcard) lebih cocok:
| Skenario Penggunaan | Rekomendasi | Alasan Teknis |
|---|---|---|
Platform Multi-Tenant Statis (banyak subdomain yang dikelola sendiri, misal user1.app.com, user2.app.com). | Wildcard Certificate | Menghemat kuota rate limit Let’s Encrypt karena ratusan subdomain menggunakan satu file sertifikat yang sama. |
| Server dengan Port 80/443 Tertutup (internal server, LAN, di belakang firewall ketat). | DNS-01 (Wildcard atau Individual) | Tidak membutuhkan koneksi masuk (inbound traffic) dari internet ke server Caddy. |
Subdomain Statis Sedikit (hanya memiliki example.com dan api.example.com). | Sertifikat Individual (HTTP-01) | Jauh lebih mudah dikonfigurasi karena tidak membutuhkan kompilasi plugin DNS maupun kredensial API DNS. |
Domain Pihak Ketiga (klien menggunakan domain mereka sendiri, misal customer.com diarahkan ke aplikasi kita). | On-Demand TLS (ODTLS) | Sertifikat wildcard kita (*.example.com) tidak berlaku untuk domain independen milik klien. |
Kompilasi Caddy dengan Plugin DNS Provider #
Secara default, paket distribusi biner standar Caddy tidak menyertakan modul DNS API untuk berbagai provider karena banyaknya variasi penyedia DNS di seluruh dunia dan untuk menjaga ukuran biner tetap ringkas. Oleh karena itu, kita harus melakukan kompilasi kustom Caddy menggunakan perkakas xcaddy.
Langkah-Langkah Kompilasi: #
1. Menginstal xcaddy #
Pastikan kita telah menginstal bahasa pemrograman Go di sistem kita, kemudian jalankan perintah berikut untuk mengunduh xcaddy:
# Menginstal xcaddy ke folder bin Go kita
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
2. Melakukan Build Caddy dengan Plugin DNS #
Pilih plugin DNS yang sesuai dengan penyedia nama domain kita (misalnya Cloudflare):
# Kompilasi Caddy kustom dengan modul DNS Cloudflare
xcaddy build --with github.com/caddy-dns/cloudflare
Jika infrastruktur kita menggunakan beberapa penyedia DNS yang berbeda, kita dapat menyertakan beberapa plugin sekaligus dalam satu perintah kompilasi:
# Kompilasi dengan beberapa plugin DNS sekaligus
xcaddy build \
--with github.com/caddy-dns/cloudflare \
--with github.com/caddy-dns/route53 \
--with github.com/caddy-dns/digitalocean
3. Verifikasi Keberhasilan Kompilasi #
Periksa apakah modul DNS yang kita inginkan sudah terdaftar dalam biner Caddy baru kita:
# Memeriksa modul terpasang
./caddy list-modules | grep dns
# Output sukses:
# dns.providers.cloudflare
# dns.providers.digitalocean
# dns.providers.route53
4. Memasang Biner Kustom ke Sistem (Linux Systemd) #
Ganti biner Caddy bawaan sistem dengan biner kustom yang baru kita buat:
# Hentikan layanan Caddy yang sedang berjalan
sudo systemctl stop caddy
# Salin biner baru ke direktori biner sistem
sudo cp ./caddy /usr/bin/caddy
# Jalankan kembali layanan Caddy
sudo systemctl start caddy
Konfigurasi Wildcard menggunakan Cloudflare #
Cloudflare adalah salah satu penyedia DNS yang paling populer dan memiliki integrasi yang sangat baik dengan Caddy.
1. Membuat API Token Cloudflare dengan Benar #
[!CAUTION] Jangan pernah menggunakan Global API Key milik akun Cloudflare kita untuk konfigurasi Caddy. Global API Key memiliki hak akses penuh untuk melakukan perubahan apa pun (termasuk menghapus domain atau mengubah email akun). Jika kunci ini bocor, seluruh infrastruktur Cloudflare kita terancam. Gunakan API Token dengan batasan akses (least privilege).
Langkah membuat API Token di Cloudflare:
- Masuk ke dasbor Cloudflare, buka My Profile -> API Tokens.
- Klik Create Token, lalu pilih Create Custom Token.
- Atur parameter token sebagai berikut:
- Token Name:
Caddy DNS-01 Challenge - Permissions:
Zone->DNS->EditZone->Zone->Read
- Zone Resources:
Include->Specific zone-> Pilih nama domain kita (misal: example.com)
- Token Name:
- Klik Continue to summary lalu Create Token. Salin token yang ditampilkan.
2. Penulisan Caddyfile untuk Wildcard dan Apex Domain #
Sertifikat wildcard *.example.com tidak mencakup domain induk example.com itu sendiri. Oleh karena itu, kita harus mengonfigurasi Caddy untuk mengamankan kedua domain tersebut. Kita dapat menggabungkannya dalam satu blok situs di Caddyfile:
# Mengamankan apex domain dan seluruh subdomain tingkat pertama
example.com, *.example.com {
tls {
# Menggunakan plugin cloudflare dengan menyuntikkan token dari env
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
# Menentukan routing lalu lintas berdasarkan nama host menggunakan matcher
@apex host example.com
@app host app.example.com
@api host api.example.com
# Mengarahkan lalu lintas ke backend yang sesuai
handle @apex {
root * /var/www/html
file_server
}
handle @app {
reverse_proxy localhost:3000
}
handle @api {
reverse_proxy localhost:8080
}
# Penanganan fallback jika subdomain tidak dikenali
handle {
error "Subdomain tidak terdaftar" 404
}
}
Konfigurasi Wildcard menggunakan AWS Route 53 #
Jika nama domain kita dikelola menggunakan AWS Route 53, kita harus membuat kebijakan IAM (IAM Policy) khusus di konsol AWS untuk memberikan izin minimal yang dibutuhkan Caddy untuk mengelola TXT record.
1. Kebijakan IAM Minimal (Least Privilege Policy) #
Buat kebijakan IAM baru di konsol AWS dengan format JSON berikut (ganti HOSTED_ZONE_ID dengan ID zona Route 53 kita):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:GetChange",
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/HOSTED_ZONE_ID",
"arn:aws:route53:::change/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListHostedZonesByName"
],
"Resource": "*"
}
]
}
2. Caddyfile AWS Route 53 #
Jika Caddy dijalankan pada instansi AWS EC2 yang memiliki IAM Role terpasang dengan kebijakan di atas, Caddy akan mendeteksi kredensial AWS secara otomatis tanpa kita perlu menulis kunci akses di Caddyfile:
# Caddyfile untuk AWS Route 53 (Menggunakan IAM Role)
example.com, *.example.com {
tls {
dns route53 {
max_retries 10
}
}
reverse_proxy localhost:8080
}
On-Demand TLS untuk Platform Multi-Tenant #
Sertifikat wildcard sangat baik jika semua subdomain berada di bawah domain kita (*.example.com). Namun, jika kita sedang membangun platform SaaS atau multi-tenant (seperti Shopify atau WordPress) di mana pelanggan dapat mengarahkan domain kustom mereka sendiri (domain-klien.com) ke server kita via CNAME, sertifikat wildcard kita tidak akan bisa mengamankan domain kustom mereka.
Solusi terbaik untuk masalah ini adalah menggunakan fitur On-Demand TLS (ODTLS) bawaan Caddy. ODTLS memungkinkan Caddy untuk meminta sertifikat TLS secara dinamis selama jabat tangan (handshake) TLS pertama kali terjadi saat domain tersebut diakses oleh pengunjung.
flowchart TD
A["Pengunjung Mengakses https://client-domain.com"] --> B["Caddy Menerima Koneksi TLS Baru"]
B --> C{"Apakah sertifikat client-domain.com ada di storage?"}
C -- Ya --> D["Gunakan Sertifikat untuk Handshake & Selesai"]
C -- Tidak --> E["Kirim GET Request ke Endpoint 'Ask'"]
E --> F{"Apakah Endpoint 'Ask' Membalas dengan HTTP 200?"}
F -- Ya --> G["Picu Proses ACME untuk Mendapatkan Sertifikat Baru"]
F -- Tidak --> H["Tolak Handshake TLS (Koneksi Diputus)"]
G --> I["Simpan Sertifikat & Selesaikan Handshake"]Mengapa Endpoint ‘Ask’ Sangat Kritis? #
[!WARNING] Mengaktifkan On-Demand TLS tanpa mendefinisikan endpoint
askadalah celah keamanan kritis (DDoS/Resource Exhaustion). Tanpa validasi, penyerang dapat melakukan jutaan koneksi TLS ke server kita menggunakan domain acak yang mereka arahkan ke IP server kita. Hal ini akan memaksa Caddy meminta sertifikat baru untuk setiap domain sampah tersebut ke Let’s Encrypt, menyebabkan server kehabisan memori, disk penuh, dan akun ACME kita diblokir karena melebihi rate limit.
Contoh Konfigurasi Caddyfile dengan On-Demand TLS: #
# Konfigurasi On-Demand TLS yang aman
{
email [email protected]
on_demand_tls {
# Endpoint internal kita untuk validasi nama domain
ask http://localhost:5000/api/v1/validate-domain
# Batasan pembuatan sertifikat baru untuk pencegahan eksploitasi
interval 2m
burst 5
}
}
# Blok site khusus untuk menangani lalu lintas port 443 dinamis
:443 {
tls {
# Mengaktifkan pembuatan sertifikat saat diakses (On-Demand)
on_demand
}
reverse_proxy localhost:8080
}
Contoh Implementasi Endpoint Validasi ‘Ask’ (Python/FastAPI) #
Endpoint ask bertugas menerima kueri ?domain=client-domain.com dari Caddy dan harus mengembalikan status kode HTTP 200 jika domain tersebut memang terdaftar sebagai pelanggan aktif di database kita, atau mengembalikan HTTP 403 jika domain tersebut tidak dikenali:
from fastapi import FastAPI, Query, HTTPException, status
import database_helper # Contoh modul database internal kita
app = FastAPI()
@app.get("/api/v1/validate-domain")
async def validate_domain(domain: str = Query(..., description="Nama domain yang meminta TLS")):
# Bersihkan input untuk keamanan
clean_domain = domain.strip().lower()
# Periksa apakah domain terdaftar dan aktif di sistem SaaS kita
is_active_tenant = await database_helper.check_tenant_domain_exists(clean_domain)
if is_active_tenant:
# Kembalikan status HTTP 200 untuk menyetujui penerbitan sertifikat TLS
return {"status": "approved", "domain": clean_domain}
else:
# Kembalikan HTTP 403 untuk menolak jabat tangan TLS
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Domain tidak terdaftar pada platform SaaS kami"
)
Pemecahan Masalah (Troubleshooting) Wildcard & ODTLS #
1. Kesalahan “Unrecognized Module” saat Menjalankan Caddy #
- Penyebab: Konfigurasi Caddyfile menggunakan provider DNS (seperti
dns cloudflare), namun biner Caddy yang dijalankan adalah biner standar yang belum di-compile bersama plugin DNS. - Solusi: Jalankan kembali langkah kompilasi menggunakan
xcaddydan pastikan biner kustom hasil kompilasi telah disalin menggantikan biner standar di/usr/bin/caddy.
2. Kegagalan Verifikasi Akibat Delay Propagasi DNS #
- Gejala di Log: Log Caddy menampilkan error
DNS record validation failedatautxt record not found. - Penyebab: Caddy terlalu cepat meminta CA Let’s Encrypt untuk memverifikasi TXT record, sementara server nama DNS (Nameservers) provider kita belum selesai menyebarkan (propagate) record baru tersebut.
- Solusi: Tingkatkan waktu tunggu propagasi pada konfigurasi
tlsCaddyfile agar Caddy menunggu lebih lama sebelum memberi sinyal verifikasi ke CA:
example.com, *.example.com {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
# Menunggu hingga 5 menit untuk propagasi DNS (default: 2 menit)
propagation_timeout 5m
# Menambahkan jeda statis sebelum mulai memeriksa status record
propagation_delay 30s
}
reverse_proxy localhost:8080
}
Ringkasan #
- Wildcard Certificate — Sertifikat TLS (
*.domain.com) yang mengamankan domain induk beserta seluruh subdomain tingkat pertama menggunakan satu sertifikat.- Kewajiban DNS-01 — Tantangan verifikasi DNS-01 adalah satu-satunya metode yang diperbolehkan protokol ACME untuk mendapatkan sertifikat wildcard.
- Kompilasi xcaddy — Kita harus menggunakan perkakas
xcaddyuntuk melakukan kompilasi biner Caddy kustom yang menyertakan plugin API DNS provider kita.- Apex Domain Terpisah — Sertifikat wildcard
*.domain.comtidak mencakup domain indukdomain.com; keduanya harus dicantumkan bersama pada konfigurasi Caddyfile.- On-Demand TLS (ODTLS) — Solusi dinamis untuk platform multi-tenant untuk mendapatkan sertifikat TLS secara otomatis untuk domain kustom milik pelanggan saat diakses pertama kali.
- Endpoint ‘Ask’ Kritis — Wajib dikonfigurasi saat menggunakan ODTLS untuk memvalidasi domain di database internal dan mencegah serangan DDoS yang menghabiskan kuota ACME.
← Sebelumnya: Self-Signed & Internal CA Berikutnya: DNS Challenge →