Certificate Management
This section covers TLS certificate strategy for the global DR hostname and why DNS-01 is typically required.
Certificate Architecture for DR Failover
The external ingress certificate is issued for the global DR FQDN
(logscale-dr.oci-dr.humio.net), not for
cluster-specific names. This is correct for DR failover.
| Component | Primary Cluster | Secondary Cluster |
|---|---|---|
| Ingress Host | logscale-dr.oci-dr.humio.net | logscale-dr.oci-dr.humio.net |
| TLS Secret Name | logscale-dr.oci-dr.humio.net | logscale-dr.oci-dr.humio.net |
| Certificate CN | CN=logscale-dr.oci-dr.humio.net | CN=logscale-dr.oci-dr.humio.net |
| Issuer | Let's Encrypt | Let's Encrypt |
1. Internal HumioCluster Certificates (managed by humio-operator)
For internal pod-to-pod TLS communication:
Certificate name: dr-secondary
DNS names:
- dr-secondary.logging
- dr-secondary-headless.logging
- dr-secondary-internal.logging
Issuer: dr-secondary (self-signed CA created by humio-operator)2. External Ingress Certificate (managed by cert-manager)
For external HTTPS traffic from users/clients:
Secret name: logscale-dr.oci-dr.humio.net
DNS names:
- logscale-dr.oci-dr.humio.net
Issuer: letsencrypt-cluster-issuer (Let's Encrypt via DNS-01 or HTTP-01)
Same hostname across clusters: Both primary and secondary use
logscale-dr.oci-dr.humio.netEach cluster has its own certificate: Independently issued by Let's Encrypt
DNS-based failover works seamlessly: When DNS steering policy switches to secondary, the certificate matches
No certificate changes during failover: The hostname users access remains constant
Hostname Configuration
The ingress hostname is configured using logscale_public_fqdn:
# tfvars - set to global hostname for DR failover
logscale_public_fqdn = "logscale-dr.oci-dr.humio.net"
Cluster-specific aliases are configured via
primary_logscale_hostname and
secondary_logscale_hostname:
# Global DNS hostnames (when dr != "")
global_logscale_hostname = "logscale-dr" # logscale-dr.oci-dr.humio.net
primary_logscale_hostname = "logscale-primary" # logscale-primary.oci-dr.humio.net
secondary_logscale_hostname = "logscale-secondary" # logscale-secondary.oci-dr.humio.netWith this configuration:
Global FQDN (
logscale-dr.oci-dr.humio.net): Used by clients, routes to healthy cluster via DNS steeringCluster-specific aliases: Direct access for debugging/validation (bypasses DR steering)
Automatic Hostname Selection for DR Mode
When using DR mode (dr="active" or dr="standby"), the effective
LogScale hostname is automatically determined from global_logscale_hostname
and dns_zone_name. You do not need to manually set
logscale_public_fqdn to the global hostname.
Important
Both primary and secondary clusters must use the same
global_logscale_hostname value. If the values differ, the ingress on
each cluster will respond to different hostnames, and DR failover will fail with HTTP 404
errors because the ingress won't match the requested hostname.
| DR Mode | tfvars logscale_public_fqdn | Effective Hostname Used | Why |
|---|---|---|---|
dr="" (non-DR) | logscale-single.example.com | logscale-single.example.com | Direct cluster access, no failover |
dr="active" | logscale-single.example.com | logscale-global.example.com | Auto-uses ${global_logscale_hostname}.${dns_zone_name} |
dr="standby" | logscale-single.example.com | logscale-global.example.com | Same global hostname for steering policy |
Example configuration:
# Cluster-specific hostname (used when dr="")
logscale_public_fqdn = "logscale-single.oci-dr.humio.net"
# DR hostnames (used when dr="active" or "standby")
global_logscale_hostname = "logscale-oci" # โ logscale-oci.oci-dr.humio.net
primary_logscale_hostname = "logscale-single" # โ A record for direct access
secondary_logscale_hostname = "logscale-secondary" # โ A record for direct access
dns_zone_name = "oci-dr.humio.net"
dr = "active" # Triggers automatic use of global hostnameResult: The HumioCluster hostname,
PUBLIC_URL, and ingress rules automatically use
logscale-oci.oci-dr.humio.net, allowing the DNS steering policy to route
traffic to the healthy cluster.
Note
You do not need to change logscale_public_fqdn when switching between
DR modes. The system automatically selects the appropriate hostname based on the
dr variable.
# Check ingress hostname and TLS configuration
kubectl --context oci-secondary get ingress -n logging -o jsonpath='{.items[0].spec.tls[0]}'
# Output: {"hosts":["logscale-dr.oci-dr.humio.net"],"secretName":"logscale-dr.oci-dr.humio.net"}
# Verify certificate CN matches global FQDN
kubectl --context oci-secondary get secret logscale-dr.oci-dr.humio.net -n logging \
-o jsonpath='{.data.tls.crt}' | base64 -d | openssl x509 -noout -subject
# Output: subject=CN=logscale-dr.oci-dr.humio.net
# Check certificate issuer and validity
kubectl --context oci-secondary get secret logscale-dr.oci-dr.humio.net -n logging \
-o jsonpath='{.data.tls.crt}' | base64 -d | openssl x509 -noout -issuer -dates
# Confirm ingress annotations include cert-manager
kubectl --context oci-secondary get ingress -n logging \
-o jsonpath='{.items[0].metadata.annotations.cert-manager.io/cluster-issuer}'
# Output: letsencrypt-cluster-issuerDNS-01 Certificate Issuance
DNS-01 certificate validation is recommended when HTTP-01 validation is blocked by
firewall rules (e.g., public_lb_cidrs restricts access to specific IP
ranges). DNS-01 validates ownership via _acme-challenge TXT records in OCI
DNS, allowing certificate issuance regardless of firewall configuration.
When to use DNS-01:
Primary cluster with firewall-restricted load balancer (HTTP-01 blocked)
Standby cluster (HTTP-01 may fail during DNS failover)
Any cluster where Let's Encrypt cannot reach port 80
Implementation Summary
cert-manager is installed by the shared
../logscale-kubernetesmoduleThe OCI repo deploys cert-manager-webhook-oci and a DNS-01 ClusterIssuer when DNS-01 is enabled and needed (
cert_dns01_provider="oci",cert_dns01_webhook_enabled=true, andcert_dns01_webhook_modeallows deployment)When DNS-01 is enabled,
../logscale-kubernetesskips creating its default HTTP-01 ClusterIssuer (skip_cluster_issuer = true)
For detailed architecture, key components, and step-by-step flow diagrams, see
module.cert-manager-oci-webhook In the Architecture Considerations section.
Enable DNS-01 on any workspace where HTTP-01 is blocked:
cert_dns01_provider = "oci"
cert_dns01_webhook_enabled = true
cert_dns01_webhook_mode = "auto" # or "always" DNS-01 reuses the same OCI API key inputs already required by this repo
(tenancy_ocid, user_ocid,
user_fingerprint, private_key_path,
region).
| File | Change |
|---|---|
oci/modules/kubernetes/cert-manager-oci-webhook/main.tf | Webhook Service + Deployment + APIService + ClusterIssuer |
oci/modules/kubernetes/cert-manager-oci-webhook/pki.tf | Webhook TLS PKI (Issuer/Certificate) |
oci/modules/kubernetes/cert-manager-oci-webhook/rbac.tf | Webhook RBAC + ServiceAccount |
oci/modules/kubernetes/cert-manager-oci-webhook/variables.tf | Webhook + DNS-01 inputs |
oci/main.tf | Installs webhook module (when DNS-01 is enabled/needed) and sets
skip_cluster_issuer=true |
# Verify on primary cluster (when DNS-01 enabled)
kubectl --context oci-primary get clusterissuer letsencrypt-cluster-issuer -o yaml
kubectl --context oci-primary get secret oci-dns-credentials -n logging-cert
kubectl --context oci-primary get apiservice v1alpha1.acme.d-n.be
kubectl --context oci-primary get certificates -n logging
kubectl --context oci-primary get secret logscale-dr.oci-dr.humio.net -n logging \
-o jsonpath='{.data.tls.crt}' | base64 -d | openssl x509 -noout -subject -issuer -dates
# Verify on secondary cluster (when DNS-01 enabled)
kubectl --context oci-secondary get clusterissuer letsencrypt-cluster-issuer -o yaml
kubectl --context oci-secondary get secret oci-dns-credentials -n logging-cert
kubectl --context oci-secondary get apiservice v1alpha1.acme.d-n.be
kubectl --context oci-secondary get certificates -n logging
kubectl --context oci-secondary get secret logscale-dr.oci-dr.humio.net -n logging \
-o jsonpath='{.data.tls.crt}' | base64 -d | openssl x509 -noout -subject -issuer -dates