Skip to content

Kubernetes TLS Certificate Guide

Overview

This document outlines different approaches to obtain and deploy TLS certificates for Call Telemetry webhook services running on Kubernetes. We cover two main methods:

  1. Automated Method: Using Let's Encrypt with cert-manager for automatic certificate issuance and renewal
  2. Manual Method: Generating certificates manually, either using an Enterprise CA (for production) or self-signed certificates (for testing)

This guide uses domain naming patterns like ct-teams-webhook-dev.example.com and ct-teams-webhook-prod.example.com for development and production environments, respectively, and demonstrates implementation in both development (ct-dev) and production (ct-prod) namespaces.

Namespace and Resource Naming Conventions

For clarity and consistency, we recommend using namespace prefixes for all certificate-related resources:

EnvironmentNamespaceCertificate Name PrefixSecret Name Prefix
Developmentct-devct-dev-ct-dev-
Productionct-prodct-prod-ct-prod-

For example:

  • Development certificate: ct-dev-teams-webhook-tls
  • Production certificate: ct-prod-teams-webhook-tls

Method 1: Automated Certificates with Let's Encrypt

Let's Encrypt provides free, automated certificates that are trusted by all major browsers. When combined with cert-manager in Kubernetes, this provides a fully automated solution for certificate management.

Prerequisites

RequirementDetails
cert-managerInstalled in your Kubernetes cluster
kubectlCluster admin access to the target namespace
Public DNS recordct-teams-webhook-prod.example.com -> public LoadBalancer/Ingress IP
Internet accessLet's Encrypt servers must be able to reach your service for validation

Prerequisites and Assumptions

This guide assumes:

  1. cert-manager is already installed in your cluster
  2. ClusterIssuers or Issuers are already configured via Helm charts
  3. You have the necessary permissions to create Certificate resources

Creating Certificate Resources

Request Certificates for Development and Production

Create Certificate resources for both environments:

Development Environment
yaml
# ct-dev-teams-webhook-cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: ct-dev-teams-webhook-tls
  namespace: ct-dev
spec:
  secretName: ct-dev-teams-webhook-tls
  issuerRef:
    name: letsencrypt-prod  # This should match your pre-configured issuer
    kind: ClusterIssuer
  dnsNames:
  - ct-teams-webhook-dev.example.com
  - ct-teams-webhook.ct-dev.svc.cluster.local

Apply the development certificate request:

bash
kubectl apply -f ct-dev-teams-webhook-cert.yaml
Production Environment
yaml
# ct-prod-teams-webhook-cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: ct-prod-teams-webhook-tls
  namespace: ct-prod
spec:
  secretName: ct-prod-teams-webhook-tls
  issuerRef:
    name: letsencrypt-prod  # This should match your pre-configured issuer
    kind: ClusterIssuer
  dnsNames:
  - ct-teams-webhook-prod.example.com
  - ct-teams-webhook.ct-prod.svc.cluster.local

Apply the production certificate request:

bash
kubectl apply -f ct-prod-teams-webhook-cert.yaml

Verify Certificate Status

Check if the certificates were issued successfully:

Development Environment
bash
kubectl get certificate -n ct-dev
kubectl get certificaterequest -n ct-dev
kubectl describe certificate ct-dev-teams-webhook-tls -n ct-dev
Production Environment
bash
kubectl get certificate -n ct-prod
kubectl get certificaterequest -n ct-prod
kubectl describe certificate ct-prod-teams-webhook-tls -n ct-prod

Once the certificates are issued, cert-manager will store them in the specified Secrets, which can be used by your Helm charts for Ingress or Gateway resources.

Method 2: Manual Certificate Generation

For environments where automated certificate management is not possible or when you need more control over the certificate issuance process, you can manually generate certificates.

Option A: Enterprise CA Certificates (Production)

This option is suitable for production environments where certificates need to be trusted by clients without additional configuration.

Prerequisites

RequirementDetails
Enterprise CAe.g. Microsoft AD CS, DigiCert Private CA, Entrust, etc.
opensslInstalled on a workstation, jump-box, or Kubernetes Job image
kubectlCluster admin access to the target namespace
DNS recordct-teams-webhook-prod.example.com -> public or internal LoadBalancer/Ingress IP

Certificate Generation Process

The following examples show how to generate certificates for both development and production environments.

Development Environment
1. Generate the Private Key & CSR
bash
# === 1.1  Private key ===
openssl genrsa -out ct-dev-teams-webhook.key 4096

# === 1.2  CSR configuration ===
cat > ct-dev-csr.conf <<'EOF'
[ req ]
default_bits       = 4096
prompt             = no
default_md         = sha256
req_extensions     = req_ext

[ req_distinguished_name ]
CN  = ct-teams-webhook-dev.example.com
O   = CallTelemetry

[ req_ext ]
subjectAltName = @alts

[ alts ]
DNS.1 = ct-teams-webhook-dev.example.com
DNS.2 = ct-teams-webhook.ct-dev.svc.cluster.local
EOF

# === 1.3  CSR ===
openssl req -new -key ct-dev-teams-webhook.key \
  -config ct-dev-csr.conf \
  -out ct-dev-teams-webhook.csr
2. Submit the CSR to the Enterprise CA
  1. Open your CA's enrollment portal (e.g. https://ca.example.local/certsrv/).
  2. Choose Request a certificate → Advanced certificate request.
  3. Paste the content of ct-dev-teams-webhook.csr.
  4. Select a Web Server template (allows Server Auth EKU).
  5. Download the signed certificate—often certnew.cer.
3. Bundle the Certificate Chain
bash
cat ct-dev-teams-webhook.crt intermed-ca.crt enterprise-root.crt \
  > ct-dev-teams-webhook.fullchain.crt
4. Create the Kubernetes TLS Secret
bash
kubectl create secret tls ct-dev-teams-webhook-tls \
  --cert=ct-dev-teams-webhook.fullchain.crt \
  --key=ct-dev-teams-webhook.key \
  -n ct-dev
Production Environment
1. Generate the Private Key & CSR
bash
# === 1.1  Private key ===
openssl genrsa -out ct-prod-teams-webhook.key 4096

# === 1.2  CSR configuration ===
cat > ct-prod-csr.conf <<'EOF'
[ req ]
default_bits       = 4096
prompt             = no
default_md         = sha256
req_extensions     = req_ext

[ req_distinguished_name ]
CN  = ct-teams-webhook-prod.example.com
O   = CallTelemetry

[ req_ext ]
subjectAltName = @alts

[ alts ]
DNS.1 = ct-teams-webhook-prod.example.com
DNS.2 = ct-teams-webhook.ct-prod.svc.cluster.local
EOF

# === 1.3  CSR ===
openssl req -new -key ct-prod-teams-webhook.key \
  -config ct-prod-csr.conf \
  -out ct-prod-teams-webhook.csr
2. Submit the CSR to the Enterprise CA
  1. Open your CA's enrollment portal (e.g. https://ca.example.local/certsrv/).
  2. Choose Request a certificate → Advanced certificate request.
  3. Paste the content of ct-prod-teams-webhook.csr.
  4. Select a Web Server template (allows Server Auth EKU).
  5. Download the signed certificate—often certnew.cer.
3. Bundle the Certificate Chain
bash
cat ct-prod-teams-webhook.crt intermed-ca.crt enterprise-root.crt \
  > ct-prod-teams-webhook.fullchain.crt
4. Create the Kubernetes TLS Secret
bash
kubectl create secret tls ct-prod-teams-webhook-tls \
  --cert=ct-prod-teams-webhook.fullchain.crt \
  --key=ct-prod-teams-webhook.key \
  -n ct-prod

Option B: Self-Signed Certificates (Testing/Development)

For testing or internal use, you can generate a self-signed certificate. This option is quick but requires clients to trust the certificate explicitly.

Prerequisites

RequirementDetails
opensslInstalled on a workstation or jump-box
kubectlCluster admin access to the target namespace

Certificate Generation Process

Development Environment
bash
# Generate private key
openssl genrsa -out ct-dev-teams-webhook.key 4096

# Create a configuration file for the certificate
cat > ct-dev-cert.conf <<'EOF'
[req]
default_bits       = 4096
prompt             = no
default_md         = sha256
distinguished_name = dn
req_extensions     = req_ext
x509_extensions    = v3_ca

[dn]
CN = ct-teams-webhook-dev.example.com
O  = CallTelemetry

[req_ext]
subjectAltName = @alt_names

[v3_ca]
subjectAltName = @alt_names
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[alt_names]
DNS.1 = ct-teams-webhook-dev.example.com
DNS.2 = ct-teams-webhook.ct-dev.svc.cluster.local
EOF

# Generate self-signed certificate
openssl req -new -x509 -key ct-dev-teams-webhook.key \
  -out ct-dev-teams-webhook.crt \
  -config ct-dev-cert.conf \
  -days 365

# Create the Kubernetes TLS Secret
kubectl create secret tls ct-dev-teams-webhook-tls \
  --cert=ct-dev-teams-webhook.crt \
  --key=ct-dev-teams-webhook.key \
  -n ct-dev

Next Steps

After generating the certificates using either method, the resulting Kubernetes Secrets (ct-dev-teams-webhook-tls and ct-prod-teams-webhook-tls) will be used by your Helm charts to configure TLS for Ingress or Gateway resources. The actual usage of these certificates in Ingress or Gateway resources is handled by the Helm charts and is not covered in this document.

Certificate Renewal and Maintenance

  • Let's Encrypt: cert-manager automatically renews certificates before they expire (every 90 days)
  • Enterprise CA: Manually renew before expiration (typically 1-2 years)
  • Self-Signed: Manually regenerate and update the secret before expiration