From 4dcfb86864aad873a6d9de03acb413aba812ac88 Mon Sep 17 00:00:00 2001 From: sghosh23 Date: Fri, 22 May 2026 12:15:25 +0200 Subject: [PATCH 1/7] add: how to enable client EKU for dtls coturn federation --- src/how-to/administrate/README.md | 70 +- .../administrate/coturn-client-certificate.md | 710 ++++++++++++++++++ 2 files changed, 753 insertions(+), 27 deletions(-) create mode 100644 src/how-to/administrate/coturn-client-certificate.md diff --git a/src/how-to/administrate/README.md b/src/how-to/administrate/README.md index fba57e5..5e033f2 100644 --- a/src/how-to/administrate/README.md +++ b/src/how-to/administrate/README.md @@ -68,46 +68,62 @@ ## 9. Restund (TURN) - [Restund (TURN)](restund.md) - - [Wire-Server Configuration](restund.md#wire-server-configuration) - - [How to see how many people are currently connected to the restund server](restund.md#how-to-see-how-many-people-are-currently-connected-to-the-restund-server) - - [How to restart restund (with downtime)](restund.md#how-to-restart-restund-with-downtime) - - [Rebooting a Restund node](restund.md#rebooting-a-restund-node) - - [How to restart restund without having downtime](restund.md#how-to-restart-restund-without-having-downtime) - - [How to renew a certificate for restund](restund.md#how-to-renew-a-certificate-for-restund) - - [How to check which restund/TURN servers will be used by clients](restund.md#how-to-check-which-restund-turn-servers-will-be-used-by-clients) - -## 10. Investigative Tasks + - [Wire-Server Configuration](restund.md#wire-server-configuration) + - [How to see how many people are currently connected to the restund server](restund.md#how-to-see-how-many-people-are-currently-connected-to-the-restund-server) + - [How to restart restund (with downtime)](restund.md#how-to-restart-restund-with-downtime) + - [Rebooting a Restund node](restund.md#rebooting-a-restund-node) + - [How to restart restund without having downtime](restund.md#how-to-restart-restund-without-having-downtime) + - [How to renew a certificate for restund](restund.md#how-to-renew-a-certificate-for-restund) + - [How to check which restund/TURN servers will be used by clients](restund.md#how-to-check-which-restund-turn-servers-will-be-used-by-clients) + +## 10. Coturn Client Certificate with Extended Key Usage (EKU) + +- [Coturn Client Certificate with Extended Key Usage (EKU)](coturn-client-certificate.md) + - [Overview](coturn-client-certificate.md#overview) + - [Prerequisites](coturn-client-certificate.md#prerequisites) + - [Step 1: Create a Certificate Signing Request (CSR)](coturn-client-certificate.md#step-1-create-a-certificate-signing-request-csr) + - [Step 2: Sign the Certificate with Your CA](coturn-client-certificate.md#step-2-sign-the-certificate-with-your-ca) + - [Step 3: Verify Certificate Has Correct EKU](coturn-client-certificate.md#step-3-verify-certificate-has-correct-eku) + - [Step 4: Encode Certificate and Key as Base64](coturn-client-certificate.md#step-4-encode-certificate-and-key-as-base64) + - [Step 5: Update Coturn Helm Values](coturn-client-certificate.md#step-5-update-coturn-helm-values) + - [Step 6: Deploy Coturn with Updated Configuration](coturn-client-certificate.md#step-6-deploy-coturn-with-updated-configuration) + - [Step 7: Verify Certificate is Deployed](coturn-client-certificate.md#step-7-verify-certificate-is-deployed) + - [Step 8: Test Federation DTLS Connection](coturn-client-certificate.md#step-8-test-federation-dtls-connection) + - [Troubleshooting](coturn-client-certificate.md#troubleshooting) + - [Certificate Renewal](coturn-client-certificate.md#certificate-renewal) + +## 11. Investigative Tasks - [Investigative tasks (e.g. searching for users as server admin)](users.md) - - [Manually searching for users in Cassandra](users.md#manually-searching-for-users-in-cassandra) - - [Deleting a user which is not a team user](users.md#deleting-a-user-which-is-not-a-team-user) - - [Searching and deleting users with no team](users.md#searching-and-deleting-users-with-no-team) - - [Manual search on Elasticsearch (via brig, recommended)](users.md#manual-search-on-elasticsearch-via-brig-recommended) - - [How to manually search for a user on Elasticsearch directly (not recommended)](users.md#how-to-manually-search-for-a-user-on-elasticsearch-directly-not-recommended) - - [How to manually delete a user from Elasticsearch only](users.md#how-to-manually-delete-a-user-from-elasticsearch-only) - - [Mass-invite users to a team](users.md#mass-invite-users-to-a-team) - - [How to obtain logs from an Android client to investigate issues](users.md#how-to-obtain-logs-from-an-android-client-to-investigate-issues) - - [How to obtain logs from an iOS client to investigate issues](users.md#how-to-obtain-logs-from-an-ios-client-to-investigate-issues) - - [How to retrieve metric values manually](users.md#how-to-retrieve-metric-values-manually) - - [Reset session cookies](users.md#reset-session-cookies) - - [Identify all users using SSO](users.md#identify-sso-users) - - [Create a team using the SCIM API](users.md#create-a-team-using-the-scim-api) - -## 11. Manuals + - [Manually searching for users in Cassandra](users.md#manually-searching-for-users-in-cassandra) + - [Deleting a user which is not a team user](users.md#deleting-a-user-which-is-not-a-team-user) + - [Searching and deleting users with no team](users.md#searching-and-deleting-users-with-no-team) + - [Manual search on Elasticsearch (via brig, recommended)](users.md#manual-search-on-elasticsearch-via-brig-recommended) + - [How to manually search for a user on Elasticsearch directly (not recommended)](users.md#how-to-manually-search-for-a-user-on-elasticsearch-directly-not-recommended) + - [How to manually delete a user from Elasticsearch only](users.md#how-to-manually-delete-a-user-from-elasticsearch-only) + - [Mass-invite users to a team](users.md#mass-invite-users-to-a-team) + - [How to obtain logs from an Android client to investigate issues](users.md#how-to-obtain-logs-from-an-android-client-to-investigate-issues) + - [How to obtain logs from an iOS client to investigate issues](users.md#how-to-obtain-logs-from-an-ios-client-to-investigate-issues) + - [How to retrieve metric values manually](users.md#how-to-retrieve-metric-values-manually) + - [Reset session cookies](users.md#reset-session-cookies) + - [Identify all users using SSO](users.md#identify-sso-users) + - [Create a team using the SCIM API](users.md#create-a-team-using-the-scim-api) + +## 12. Manuals - [Test an ingress is working from inside the cluster](manuals.md#test-an-ingress-is-working-from-inside-the-cluster) - [Load an image into containerd in an offline/airgapped environment](manuals.md#load-an-image-into-containerd-in-an-offlineairgapped-environment) -## 12. Migration +## 13. Migration - [Migrate team features](migrate-team-features.md) - [Migrate to postgresql](migrate-to-postgresql.md) -## 13. Wire-utility +## 14. Wire-utility - [Wire utility tool](wire-utility-tool.md) -## 14. PostgreSQL +## 15. PostgreSQL - [PostgreSQL](postgresql.md) - [PostgreSQL Connection Budget](postgresql.md#postgresql-connection-budget) diff --git a/src/how-to/administrate/coturn-client-certificate.md b/src/how-to/administrate/coturn-client-certificate.md new file mode 100644 index 0000000..ebee053 --- /dev/null +++ b/src/how-to/administrate/coturn-client-certificate.md @@ -0,0 +1,710 @@ +# Coturn Client Certificate with Extended Key Usage (EKU) + +This section is about **how to perform a specific task**. If you want to **understand how a certain component works, please see** [Reference](../../understand/README.md#understand) + +This guide explains how to create and deploy a coturn client certificate with Extended Key Usage (EKU) support for federation DTLS connections. When coturn needs to authenticate with federation partner servers over DTLS on port 9191, the certificate must include both server and client authentication capabilities. + +## Overview + +Coturn federation DTLS connections (port 9191) require mutual TLS authentication. Your coturn certificate must be signed by a Certificate Authority (CA) that Wire Cloud trusts. The certificate must include both serverAuth and clientAuth Extended Key Usage (EKU) extensions. + +**Before you start**: If you don't have a CA certificate yet, create a self-signed CA, send it to Wire Cloud to add to their federation trust store, and then use that CA to sign your coturn certificates. Once Wire Cloud trusts your CA, you can issue multiple coturn certificates from it. + +### Prerequisites + +- Coturn deployment via Helm in Kubernetes +- Access to the coturn Helm values configuration +- `openssl` command-line tool installed locally +- `kubectl` access to your cluster +- **CA certificate** and **CA private key** (either create new or from your organization) +- Wire Cloud has added your CA certificate to their federation trust store +- FQDN for your coturn deployment (e.g., `coturn.example.com`) + +### Deployment Model + +The typical workflow for a self-managed coturn deployment: + +1. **Create a self-signed CA** (long validity, e.g. 10 years): `my-ca.pem` +2. **Send your CA** to Wire Cloud to add to their federation trust store +3. **Generate a coturn certificate** signed by that CA with serverAuth+clientAuth EKU +4. **Deploy coturn** with the certificate in Helm values +5. **Renew annually** by signing a new certificate with the same CA — no need to contact Wire Cloud again + +## Step 1: Create a Certificate Signing Request (CSR) + +First, generate a private key and create a signing request for your coturn certificate. + +```bash +# Create a coturn private key (2048-bit RSA) +openssl genrsa -out coturn-key.pem 2048 + +# OR use ECDSA if your organization prefers (recommended for modern deployments) +openssl ecparam -name secp256r1 -genkey -noout -out coturn-key.pem + +# Create a certificate signing request with both server and client authentication EKU +# Replace coturn.example.com with your actual coturn FQDN +openssl req -new \ + -key coturn-key.pem \ + -out coturn.csr \ + -subj "/C=US/ST=State/L=City/O=Your Organization/CN=coturn.example.com" \ + -addext "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local" \ + -addext "extendedKeyUsage=serverAuth,clientAuth" \ + -addext "keyUsage=digitalSignature" +``` + +Verify the CSR: + +```bash +openssl req -in coturn.csr -text -noout +``` + +## Step 2: Sign the Certificate with Your CA + +Using your CA certificate and private key, sign the coturn certificate. This certificate will be valid for 365 days. + +```bash +# Sign the CSR with your CA certificate and key +openssl x509 -req -days 365 \ + -in coturn.csr \ + -CA ca-cert.pem \ + -CAkey ca-key.pem \ + -CAcreateserial \ + -out coturn-cert.pem \ + -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth,clientAuth") +``` + +Verify the signed certificate: + +```bash +openssl x509 -in coturn-cert.pem -text -noout | head -40 +``` + +## Step 3: Verify Certificate Has Correct EKU + +Before deploying, verify that your certificate includes both serverAuth and clientAuth extensions, and is signed by your CA: + +```bash +# Check Extended Key Usage +openssl x509 -in coturn-cert.pem -text -noout | grep -A 3 "Extended Key Usage" +``` + +Expected output: + +``` +X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication +``` + +Verify the certificate issuer: + +```bash +openssl x509 -in coturn-cert.pem -noout -issuer +# Output should show: issuer=CN=Wire Federation CA (or your organization's CA name) +``` + +Verify the validity dates: + +```bash +openssl x509 -in coturn-cert.pem -noout -dates +# Output should show: notBefore=... and notAfter=... (365 days from now) +``` + +## Step 4: Encode Certificate and Key as Base64 + +Encode your certificate and private key as single-line base64 strings for embedding in Helm values. + +```bash +# Encode coturn certificate (single line, no wrapping — works on Linux and macOS) +echo "=== Coturn Certificate (base64) ===" +base64 < coturn-cert.pem | tr -d '\n' +echo "" + +# Encode coturn private key +echo "=== Coturn Private Key (base64) ===" +base64 < coturn-key.pem | tr -d '\n' +echo "" +``` + +Copy both base64 strings for the next step. + +## Step 5: Update Coturn Helm Values + +Update your coturn Helm values file (`values/coturn/values.yaml`) with the base64-encoded certificate and key: + +```yaml +# Existing coturn configuration +nodeSelector: + wire.com/role: coturn + +replicaCount: 3 +coturnTurnListenIP: "__COTURN_POD_IP__" +coturnTurnExternalIP: "__COTURN_EXT_IP__" +coturnTurnRelayIP: "__COTURN_POD_IP__" + +# DTLS Federation certificate configuration +federate: + dtls: + tls: + key: + crt: + +# Existing secrets configuration +secrets: + zrestSecrets: + - "" + +# Rate limiting allowlist for federation. +# Add all IPs that coturn must accept connections from without rate limiting: +# +# 1. Internal node IPs — the Kubernetes node IPs where coturn pods are scheduled. +# Add one entry per node. +# +# 2. Cluster gateway / NAT IP — if your cluster routes outgoing traffic through +# a single gateway or NAT IP, add that IP too (coturn sees it as the source). +# +# 3. Public (external) IPs of each coturn replica — the IPs advertised externally +# for each StatefulSet pod (coturn-0, coturn-1, coturn-2, ...). +# +# 4. Federation partner IPs — IP addresses or CIDR ranges of Wire Cloud or other +# federation partners that connect to coturn on port 9191. +# +# Example: +config: + verboseLogging: false + ratelimit: + allowlist: + - "192.168.1.10" # node-1 internal IP + - "192.168.1.11" # node-2 internal IP + - "192.168.1.12" # node-3 internal IP + - "192.168.1.1" # cluster gateway / NAT IP (if applicable) + - "203.0.113.10" # coturn-0 external/public IP + - "203.0.113.11" # coturn-1 external/public IP + - "203.0.113.12" # coturn-2 external/public IP + - "198.51.100.0/24" # federation partner IP range +``` + +### Example YAML Values + +The values are single-line base64 strings (no PEM headers): + +```yaml +federate: + dtls: + tls: + key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7W8z1K2... + crt: MIIDazCCAlOgAwIBAgIUfQ2Z7x8zV0Q8JvZ0Q0Q0Q0Q0Q0AwDQYJKoZIhvcNAQEL... +``` + +## Step 6: Deploy Coturn with Updated Configuration + +**Prerequisite**: The coturn chart must be at version `4.6.2-federation-wireapp.44` or later. Earlier versions do not support the `federate.dtls.tls.key`/`crt` values fields. Verify your chart version: + +```bash +helm show chart ./charts/coturn | grep '^version:' +``` + +Apply the updated Helm values: + +```bash +# Navigate to wire-server-deploy directory +cd /path/to/wire-server-deploy + +# Deploy or upgrade the coturn Helm chart with the updated values +helm upgrade --install coturn ./charts/coturn \ + -n default \ + -f values/coturn/values.yaml \ + --wait \ + --timeout 5m +``` + +Or if using helmfile: + +```bash +helmfile sync +``` + +Monitor the rollout: + +```bash +kubectl rollout status statefulset/coturn -n default +``` + +The Helm chart will automatically: +1. Create a Kubernetes Secret with the certificate and key data +2. Mount the certificate in each coturn pod +3. Restart all coturn pods to pick up the new certificate +4. Update Helm release history for tracking and potential rollbacks + +## Step 7: Verify Certificate is Deployed + +After the Helm upgrade completes, verify that the certificate is properly mounted in the coturn pods: + +```bash +# Get the coturn pod name +COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') + +# Verify the Kubernetes Secret was created +kubectl get secret coturn-dtls-certificate -n default -o yaml + +# Check if certificate files exist in the pod +kubectl exec -it $COTURN_POD -n default -- ls -la /coturn-dtls-certificate/ + +# Verify the certificate content and EKU from the pod +kubectl exec -it $COTURN_POD -n default -- openssl x509 -in /coturn-dtls-certificate/tls.crt -text -noout | grep -A 3 "Extended Key Usage" +``` + +Expected output showing both serverAuth and clientAuth: + +``` +X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication +``` + +## Step 8: Test Federation DTLS Connection + +To verify that coturn can now authenticate with federation partners, check the coturn logs: + +```bash +# Get the coturn pod name (if not already set) +COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') + +# Stream coturn logs to watch for DTLS connections +kubectl logs -f $COTURN_POD -n default + +# Or retrieve recent logs and filter for DTLS-related messages +kubectl logs $COTURN_POD -n default --tail=100 | grep -iE 'dtls|tls|certificate|federation' +``` + +Look for successful DTLS connection messages or client authentication confirmations in the logs. + +### Check Helm Release History + +To verify the chart was updated with your changes: + +```bash +# View Helm release history +helm history coturn -n default + +# Get current Helm values +helm get values coturn -n default | grep -A 10 "federate" +``` + +## Troubleshooting + +### Certificate Not Loaded in Pod + +**Symptom**: Coturn pod starts but certificate files are missing or old certificate is still in use. + +**Solution**: + +1. Verify the values file has the correct base64-encoded certificate: + ```bash + grep -A 5 "federate:" values/coturn/values.yaml + ``` + +2. Check if Helm Secret was created: + ```bash + kubectl get secret coturn-dtls-certificate -n default -o yaml + ``` + +3. Verify pod is using the new certificate: + ```bash + COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') + kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -noout -dates + ``` + +4. If pod still has old certificate, restart it: + ```bash + kubectl delete pod $COTURN_POD -n default + kubectl wait --for=condition=ready pod -l app=coturn -n default --timeout=300s + ``` + +### Certificate Missing Client EKU + +**Symptom**: Coturn connects to federation partners but DTLS authentication fails. + +**Solution**: + +1. Verify the certificate has both serverAuth and clientAuth: + ```bash + openssl x509 -in coturn-cert.pem -text -noout | grep -A 3 "Extended Key Usage" + ``` + +2. If output doesn't show both `TLS Web Server Authentication` and `TLS Web Client Authentication`, regenerate the certificate: + - Follow Step 1 to create a new CSR with proper EKU flags + - Follow Step 2 to sign it with your CA + - Continue with Steps 4-6 to deploy + +### Coturn Pod Fails to Start + +**Symptom**: Pod enters `CrashLoopBackOff` after Helm upgrade. + +**Solution**: + +1. Check pod events: + ```bash + COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') + kubectl describe pod $COTURN_POD -n default + ``` + +2. Check pod logs: + ```bash + kubectl logs $COTURN_POD -n default --previous + ``` + +3. Verify the Secret data is valid: + ```bash + kubectl get secret coturn-dtls-certificate -n default -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout | head -5 + ``` + +4. Check for YAML syntax errors in values file: + ```bash + helm lint ./charts/coturn -f values/coturn/values.yaml + ``` + +5. If issues persist, rollback to previous Helm revision: + ```bash + helm rollback coturn -n default + kubectl rollout status statefulset/coturn -n default + ``` + +### Helm Upgrade Stuck or Slow + +**Symptom**: `helm upgrade` command takes a long time or appears hung. + +**Solution**: + +1. Check pod restart status: + ```bash + kubectl get pods -n default | grep coturn + ``` + +2. Increase timeout if needed: + ```bash + helm upgrade coturn ./charts/coturn -f values/coturn/values.yaml -n default --wait --timeout 10m + ``` + +3. Check StatefulSet rollout status: + ```bash + kubectl rollout status statefulset/coturn -n default + ``` + +### Certificate Signed by Wrong CA + +**Symptom**: Certificate looks valid locally but federation partners can't authenticate. + +**Solution**: + +1. Verify certificate issuer matches your CA: + ```bash + openssl x509 -in coturn-cert.pem -noout -issuer + ``` + +2. Verify the CA that signed the certificate: + ```bash + openssl x509 -in coturn-cert.pem -noout -text | grep -A 2 "Issuer:" + ``` + +3. If wrong CA was used, regenerate the certificate using the correct CA: + ```bash + # Follow Step 1 to create a new CSR + # Follow Step 2 to sign it with the CORRECT CA + # Verify in Step 3 that issuer matches your trusted CA + # Continue with Steps 4-6 to deploy + ``` + +## Complete Example + +This example shows the full end-to-end workflow. Replace `coturn.example.com`, the subject fields, and the replica SANs with your actual FQDN and organization details. + +### Step 1: Create Your Self-Signed CA (One-Time Setup) + +Create your own CA to manage federation independently: + +```bash +# Generate CA private key (2048-bit RSA) +openssl genrsa -out my-ca-key.pem 2048 + +# Create CA certificate signing request +openssl req -new \ + -key my-ca-key.pem \ + -out my-ca.csr \ + -subj "/C=XX/O=Your Organization/CN=Your Organization CA" + +# Self-sign CA certificate (valid 10 years = 3650 days) +openssl x509 -req \ + -in my-ca.csr \ + -signkey my-ca-key.pem \ + -out my-ca.pem \ + -days 3650 \ + -extfile <(printf "basicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign") +``` + +**Result**: Three files +- `my-ca.pem` - CA certificate (send this to Wire Cloud) +- `my-ca-key.pem` - CA private key (keep secure, needed for renewals) +- `my-ca.csr` - Can be deleted + +**Next**: Send `my-ca.pem` to Wire Cloud to add to their federation trust store. + +### Step 2: Create Coturn Certificate Signed by Your CA + +Once Wire Cloud has added your CA to their trust store, create the coturn certificate: + +```bash +# Generate coturn private key and CSR in one command +openssl req -noenc -newkey rsa:2048 \ + -keyout coturn-federation-key.pem \ + -out coturn-federation.csr \ + -subj "/C=XX/O=Your Organization/CN=coturn.example.com" + +# Sign with your CA (valid 1 year) +openssl x509 -req -days 365 \ + -in coturn-federation.csr \ + -CA my-ca.pem \ + -CAkey my-ca-key.pem \ + -CAcreateserial \ + -out coturn-federation-cert.pem \ + -sha256 \ + -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com\nextendedKeyUsage=serverAuth,clientAuth") +``` + +**Result**: Three files +- `coturn-federation-cert.pem` - Signed coturn certificate +- `coturn-federation-key.pem` - Coturn private key +- `coturn-federation.csr` - Can be deleted + +### Step 3: Verify the Certificate + +```bash +# Verify it's signed by your CA +openssl verify -CAfile my-ca.pem coturn-federation-cert.pem +# Output: coturn-federation-cert.pem: OK + +# Check Extended Key Usage +openssl x509 -in coturn-federation-cert.pem -noout -text | grep -A 3 "Extended Key Usage" +# Output should show: TLS Web Server Authentication, TLS Web Client Authentication + +# Check Subject Alternative Names +openssl x509 -in coturn-federation-cert.pem -noout -text | grep -A 1 "Subject Alternative Name" +# Output should show: DNS:coturn.example.com, DNS:coturn-0/1/2.example.com + +# Check validity dates +openssl x509 -in coturn-federation-cert.pem -noout -dates +# Output: notBefore=... notAfter=... (1 year from now) +``` + +### Step 4: Encode and Deploy + +```bash +# Encode as single-line base64 (works on Linux and macOS) +echo "=== Certificate (base64) ===" +base64 < coturn-federation-cert.pem | tr -d '\n' +echo "" +echo "=== Private Key (base64) ===" +base64 < coturn-federation-key.pem | tr -d '\n' +echo "" +``` + +Update `values/coturn/values.yaml`: + +```yaml +federate: + dtls: + tls: + key: + crt: +``` + +Deploy: + +```bash +helm upgrade coturn ./charts/coturn \ + -n default \ + -f values/coturn/values.yaml \ + --wait \ + --timeout 5m +``` + +### Step 5: Verify in Kubernetes + +```bash +# Get pod name +COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') + +# Verify certificate is deployed +kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -noout -dates + +# Verify EKU +kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -text -noout | grep -A 3 "Extended Key Usage" +``` + +### Annual Certificate Renewal + +When the certificate expires: + +```bash +# Generate new private key and CSR +openssl req -noenc -newkey rsa:2048 \ + -keyout coturn-federation-key.pem \ + -out coturn-federation.csr \ + -subj "/C=XX/O=Your Organization/CN=coturn.example.com" + +# Sign with EXISTING CA (same CA, already trusted by Wire Cloud) +openssl x509 -req -days 365 \ + -in coturn-federation.csr \ + -CA my-ca.pem \ + -CAkey my-ca-key.pem \ + -CAcreateserial \ + -out coturn-federation-cert.pem \ + -sha256 \ + -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com\nextendedKeyUsage=serverAuth,clientAuth") + +# Encode new certificate and key +echo "=== New Certificate (base64) ===" +base64 < coturn-federation-cert.pem | tr -d '\n' +echo "" +echo "=== New Private Key (base64) ===" +base64 < coturn-federation-key.pem | tr -d '\n' +echo "" + +# Update values/coturn/values.yaml with the new base64 strings, then redeploy +helm upgrade coturn ./charts/coturn \ + -n default \ + -f values/coturn/values.yaml \ + --wait +``` + +**Key point**: No need to contact Wire Cloud again for renewal — the CA is already trusted. Just generate a new certificate signed by the same CA and deploy it. + +--- + +## Certificate Renewal + +When your coturn certificate approaches expiration (typically 365 days), you need to generate and deploy a new certificate signed by your CA before the old one expires. + +### Renewal Process + +1. **Generate a new CSR** (follow Step 1): + ```bash + # Create a new private key + openssl genrsa -out coturn-key-new.pem 2048 + + # Create a new certificate signing request + openssl req -new \ + -key coturn-key-new.pem \ + -out coturn-new.csr \ + -subj "/C=US/ST=State/L=City/O=Your Organization/CN=coturn.example.com" \ + -addext "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local" \ + -addext "extendedKeyUsage=serverAuth,clientAuth" \ + -addext "keyUsage=digitalSignature" + ``` + +2. **Sign the new certificate with your CA** (follow Step 2): + ```bash + openssl x509 -req -days 365 \ + -in coturn-new.csr \ + -CA ca-cert.pem \ + -CAkey ca-key.pem \ + -CAcreateserial \ + -out coturn-cert-new.pem \ + -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth,clientAuth") + ``` + +3. **Verify the new certificate** (follow Step 3): + ```bash + openssl x509 -in coturn-cert-new.pem -text -noout | grep -A 3 "Extended Key Usage" + openssl x509 -in coturn-cert-new.pem -noout -dates + ``` + +4. **Encode the new certificate and key as base64** (follow Step 4): + ```bash + echo "=== New Certificate (base64) ===" + base64 < coturn-cert-new.pem | tr -d '\n' + echo "" + echo "=== New Private Key (base64) ===" + base64 < coturn-key-new.pem | tr -d '\n' + echo "" + ``` + +5. **Backup current values file**: + ```bash + cp values/coturn/values.yaml values/coturn/values.yaml.backup.$(date +%Y%m%d-%H%M%S) + ``` + +6. **Update values file** with the new base64-encoded certificate and key: + ```yaml + federate: + dtls: + tls: + key: + crt: + ``` + +7. **Verify YAML syntax**: + ```bash + helm lint ./charts/coturn -f values/coturn/values.yaml + ``` + +8. **Redeploy coturn** with the new certificate (follow Step 6): + ```bash + helm upgrade coturn ./charts/coturn \ + -n default \ + -f values/coturn/values.yaml \ + --wait \ + --timeout 5m + ``` + +9. **Verify deployment** (follow Step 7): + ```bash + COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') + + # Check new certificate is deployed + kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -noout -dates + + # Verify Extended Key Usage + kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -text -noout | grep -A 3 "Extended Key Usage" + ``` + +10. **Check Helm release history**: + ```bash + helm history coturn -n default + ``` + +### Renewal Checklist + +- [ ] Calculate expiration date: `openssl x509 -in coturn-cert.pem -noout -dates` +- [ ] Plan renewal at least 30 days before expiration +- [ ] Generate new CSR with same FQDN and EKU extensions +- [ ] Sign with your CA certificate +- [ ] Verify new certificate has correct EKU and issuer +- [ ] Backup current values file +- [ ] Encode new certificate and key as base64 +- [ ] Update values file with new base64 strings +- [ ] Run `helm lint` to verify YAML syntax +- [ ] Run `helm upgrade` with `--wait` flag +- [ ] Verify pod restart completed successfully +- [ ] Verify new certificate in pod +- [ ] Test federation DTLS connections +- [ ] Document renewal date in your records + +### Rollback to Previous Certificate + +If something goes wrong during renewal, rollback to the previous certificate: + +```bash +# View Helm release history +helm history coturn -n default + +# Rollback to the previous release (e.g., revision 5) +helm rollback coturn 5 -n default + +# Verify rollback +kubectl rollout status statefulset/coturn -n default +``` + +## Related Documentation + +- [Coturn Installation](../install/) - General coturn setup in wire-server-deploy +- [Wire-Server TLS Configuration](tls.md) - TLS certificate management +- [Federation Configuration](../../understand/federation.md) - Understanding federation in Wire From 05b84567b7a1932c48f5b16c7491457a57287852 Mon Sep 17 00:00:00 2001 From: sghosh23 Date: Fri, 22 May 2026 13:55:26 +0200 Subject: [PATCH 2/7] update instructions --- src/how-to/administrate/README.md | 17 +- .../administrate/coturn-client-certificate.md | 205 +++++++++++------- 2 files changed, 130 insertions(+), 92 deletions(-) diff --git a/src/how-to/administrate/README.md b/src/how-to/administrate/README.md index 5e033f2..83b60d4 100644 --- a/src/how-to/administrate/README.md +++ b/src/how-to/administrate/README.md @@ -81,14 +81,15 @@ - [Coturn Client Certificate with Extended Key Usage (EKU)](coturn-client-certificate.md) - [Overview](coturn-client-certificate.md#overview) - [Prerequisites](coturn-client-certificate.md#prerequisites) - - [Step 1: Create a Certificate Signing Request (CSR)](coturn-client-certificate.md#step-1-create-a-certificate-signing-request-csr) - - [Step 2: Sign the Certificate with Your CA](coturn-client-certificate.md#step-2-sign-the-certificate-with-your-ca) - - [Step 3: Verify Certificate Has Correct EKU](coturn-client-certificate.md#step-3-verify-certificate-has-correct-eku) - - [Step 4: Encode Certificate and Key as Base64](coturn-client-certificate.md#step-4-encode-certificate-and-key-as-base64) - - [Step 5: Update Coturn Helm Values](coturn-client-certificate.md#step-5-update-coturn-helm-values) - - [Step 6: Deploy Coturn with Updated Configuration](coturn-client-certificate.md#step-6-deploy-coturn-with-updated-configuration) - - [Step 7: Verify Certificate is Deployed](coturn-client-certificate.md#step-7-verify-certificate-is-deployed) - - [Step 8: Test Federation DTLS Connection](coturn-client-certificate.md#step-8-test-federation-dtls-connection) + - [Step 1: Create a Self-Signed CA](coturn-client-certificate.md#step-1-create-a-self-signed-ca-skip-if-you-already-have-one) + - [Step 2: Create a Certificate Signing Request (CSR)](coturn-client-certificate.md#step-2-create-a-certificate-signing-request-csr) + - [Step 3: Sign the Certificate with Your CA](coturn-client-certificate.md#step-3-sign-the-certificate-with-your-ca) + - [Step 4: Verify Certificate Has Correct EKU](coturn-client-certificate.md#step-4-verify-certificate-has-correct-eku) + - [Step 5: Prepare Certificate Files](coturn-client-certificate.md#step-5-prepare-certificate-files) + - [Step 6: Update Coturn Helm Values](coturn-client-certificate.md#step-6-update-coturn-helm-values) + - [Step 7: Deploy Coturn with Updated Configuration](coturn-client-certificate.md#step-7-deploy-coturn-with-updated-configuration) + - [Step 8: Verify Certificate is Deployed](coturn-client-certificate.md#step-8-verify-certificate-is-deployed) + - [Step 9: Test Federation DTLS Connection](coturn-client-certificate.md#step-9-test-federation-dtls-connection) - [Troubleshooting](coturn-client-certificate.md#troubleshooting) - [Certificate Renewal](coturn-client-certificate.md#certificate-renewal) diff --git a/src/how-to/administrate/coturn-client-certificate.md b/src/how-to/administrate/coturn-client-certificate.md index ebee053..995ffdf 100644 --- a/src/how-to/administrate/coturn-client-certificate.md +++ b/src/how-to/administrate/coturn-client-certificate.md @@ -8,17 +8,14 @@ This guide explains how to create and deploy a coturn client certificate with Ex Coturn federation DTLS connections (port 9191) require mutual TLS authentication. Your coturn certificate must be signed by a Certificate Authority (CA) that Wire Cloud trusts. The certificate must include both serverAuth and clientAuth Extended Key Usage (EKU) extensions. -**Before you start**: If you don't have a CA certificate yet, create a self-signed CA, send it to Wire Cloud to add to their federation trust store, and then use that CA to sign your coturn certificates. Once Wire Cloud trusts your CA, you can issue multiple coturn certificates from it. - ### Prerequisites - Coturn deployment via Helm in Kubernetes - Access to the coturn Helm values configuration - `openssl` command-line tool installed locally - `kubectl` access to your cluster -- **CA certificate** and **CA private key** (either create new or from your organization) -- Wire Cloud has added your CA certificate to their federation trust store - FQDN for your coturn deployment (e.g., `coturn.example.com`) +- **CA certificate** and **CA private key** — create one in Step 1 if you don't have one yet; once Wire Cloud trusts your CA you can reuse it for all future renewals ### Deployment Model @@ -30,7 +27,39 @@ The typical workflow for a self-managed coturn deployment: 4. **Deploy coturn** with the certificate in Helm values 5. **Renew annually** by signing a new certificate with the same CA — no need to contact Wire Cloud again -## Step 1: Create a Certificate Signing Request (CSR) +## Step 1: Create a Self-Signed CA (skip if you already have one) + +If your organization already has a CA and Wire Cloud already trusts it, skip to Step 2. + +Otherwise, create a self-signed CA. You do this **once** — the CA is long-lived (10 years) and is reused for all future coturn certificate renewals without needing to contact Wire Cloud again. + +```bash +# Generate CA private key (2048-bit RSA) +openssl genrsa -out my-ca-key.pem 2048 + +# Create CA certificate signing request +openssl req -new \ + -key my-ca-key.pem \ + -out my-ca.csr \ + -subj "/C=XX/O=Your Organization/CN=Your Organization CA" + +# Self-sign the CA certificate (valid 10 years = 3650 days) +openssl x509 -req \ + -in my-ca.csr \ + -signkey my-ca-key.pem \ + -out my-ca.pem \ + -days 3650 \ + -extfile <(printf "basicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always,issuer:always") +``` + +**Result**: +- `my-ca.pem` — CA certificate; send this to Wire Cloud to add to their federation trust store +- `my-ca-key.pem` — CA private key; keep this secure, it is needed for all future renewals +- `my-ca.csr` — can be deleted + +**Important**: Wait until Wire Cloud confirms your CA is in their trust store before proceeding. + +## Step 2: Create a Certificate Signing Request (CSR) First, generate a private key and create a signing request for your coturn certificate. @@ -58,7 +87,7 @@ Verify the CSR: openssl req -in coturn.csr -text -noout ``` -## Step 2: Sign the Certificate with Your CA +## Step 3: Sign the Certificate with Your CA Using your CA certificate and private key, sign the coturn certificate. This certificate will be valid for 365 days. @@ -66,8 +95,8 @@ Using your CA certificate and private key, sign the coturn certificate. This cer # Sign the CSR with your CA certificate and key openssl x509 -req -days 365 \ -in coturn.csr \ - -CA ca-cert.pem \ - -CAkey ca-key.pem \ + -CA my-ca.pem \ + -CAkey my-ca-key.pem \ -CAcreateserial \ -out coturn-cert.pem \ -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth,clientAuth") @@ -76,10 +105,10 @@ openssl x509 -req -days 365 \ Verify the signed certificate: ```bash -openssl x509 -in coturn-cert.pem -text -noout | head -40 +openssl x509 -in coturn-cert.pem -text -noout ``` -## Step 3: Verify Certificate Has Correct EKU +## Step 4: Verify Certificate Has Correct EKU Before deploying, verify that your certificate includes both serverAuth and clientAuth extensions, and is signed by your CA: @@ -99,7 +128,7 @@ Verify the certificate issuer: ```bash openssl x509 -in coturn-cert.pem -noout -issuer -# Output should show: issuer=CN=Wire Federation CA (or your organization's CA name) +# Output should show your CA's CN, e.g.: issuer=C=XX, O=Your Organization, CN=Your Organization CA ``` Verify the validity dates: @@ -109,27 +138,23 @@ openssl x509 -in coturn-cert.pem -noout -dates # Output should show: notBefore=... and notAfter=... (365 days from now) ``` -## Step 4: Encode Certificate and Key as Base64 +## Step 5: Prepare Certificate Files -Encode your certificate and private key as single-line base64 strings for embedding in Helm values. +Display the PEM content of your certificate and private key, ready to copy into the Helm values file. The Helm chart encodes them automatically — paste the raw PEM including the `-----BEGIN`/`-----END` headers. ```bash -# Encode coturn certificate (single line, no wrapping — works on Linux and macOS) -echo "=== Coturn Certificate (base64) ===" -base64 < coturn-cert.pem | tr -d '\n' -echo "" - -# Encode coturn private key -echo "=== Coturn Private Key (base64) ===" -base64 < coturn-key.pem | tr -d '\n' +echo "=== Coturn Certificate ===" +cat coturn-cert.pem echo "" +echo "=== Coturn Private Key ===" +cat coturn-key.pem ``` -Copy both base64 strings for the next step. +Copy both PEM strings for the next step. -## Step 5: Update Coturn Helm Values +## Step 6: Update Coturn Helm Values -Update your coturn Helm values file (`values/coturn/values.yaml`) with the base64-encoded certificate and key: +Update your coturn Helm values file (`values/coturn/values.yaml`) with the PEM certificate and key. Use YAML block scalars (`|`) to preserve the multi-line PEM format: ```yaml # Existing coturn configuration @@ -145,8 +170,14 @@ coturnTurnRelayIP: "__COTURN_POD_IP__" federate: dtls: tls: - key: - crt: + key: | + -----BEGIN PRIVATE KEY----- + + -----END PRIVATE KEY----- + crt: | + -----BEGIN CERTIFICATE----- + + -----END CERTIFICATE----- # Existing secrets configuration secrets: @@ -185,19 +216,23 @@ config: ### Example YAML Values -The values are single-line base64 strings (no PEM headers): - ```yaml federate: dtls: tls: - key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7W8z1K2... - crt: MIIDazCCAlOgAwIBAgIUfQ2Z7x8zV0Q8JvZ0Q0Q0Q0Q0Q0AwDQYJKoZIhvcNAQEL... + key: | + -----BEGIN PRIVATE KEY----- + MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7W8z1K2... + -----END PRIVATE KEY----- + crt: | + -----BEGIN CERTIFICATE----- + MIIDazCCAlOgAwIBAgIUfQ2Z7x8zV0Q8JvZ0Q0Q0Q0Q0Q0AwDQYJKoZIhvcNAQEL... + -----END CERTIFICATE----- ``` -## Step 6: Deploy Coturn with Updated Configuration +## Step 7: Deploy Coturn with Updated Configuration -**Prerequisite**: The coturn chart must be at version `4.6.2-federation-wireapp.44` or later. Earlier versions do not support the `federate.dtls.tls.key`/`crt` values fields. Verify your chart version: +**Prerequisite**: The coturn chart must be at version `0.0.44` or later. Support for manually providing a self-signed certificate via `federate.dtls.tls.key`/`crt` was added in this version — earlier versions only support cert-manager-managed certificates. Verify your chart version: ```bash helm show chart ./charts/coturn | grep '^version:' @@ -235,7 +270,7 @@ The Helm chart will automatically: 3. Restart all coturn pods to pick up the new certificate 4. Update Helm release history for tracking and potential rollbacks -## Step 7: Verify Certificate is Deployed +## Step 8: Verify Certificate is Deployed After the Helm upgrade completes, verify that the certificate is properly mounted in the coturn pods: @@ -260,7 +295,7 @@ X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication ``` -## Step 8: Test Federation DTLS Connection +## Step 9: Test Federation DTLS Connection To verify that coturn can now authenticate with federation partners, check the coturn logs: @@ -297,7 +332,7 @@ helm get values coturn -n default | grep -A 10 "federate" **Solution**: -1. Verify the values file has the correct base64-encoded certificate: +1. Verify the values file has the correct PEM certificate: ```bash grep -A 5 "federate:" values/coturn/values.yaml ``` @@ -331,9 +366,9 @@ helm get values coturn -n default | grep -A 10 "federate" ``` 2. If output doesn't show both `TLS Web Server Authentication` and `TLS Web Client Authentication`, regenerate the certificate: - - Follow Step 1 to create a new CSR with proper EKU flags - - Follow Step 2 to sign it with your CA - - Continue with Steps 4-6 to deploy + - Follow Step 2 to create a new CSR with proper EKU flags + - Follow Step 3 to sign it with your CA + - Continue with Steps 5-7 to deploy ### Coturn Pod Fails to Start @@ -407,10 +442,10 @@ helm get values coturn -n default | grep -A 10 "federate" 3. If wrong CA was used, regenerate the certificate using the correct CA: ```bash - # Follow Step 1 to create a new CSR - # Follow Step 2 to sign it with the CORRECT CA - # Verify in Step 3 that issuer matches your trusted CA - # Continue with Steps 4-6 to deploy + # Follow Step 2 to create a new CSR + # Follow Step 3 to sign it with the CORRECT CA + # Verify in Step 4 that issuer matches your trusted CA + # Continue with Steps 5-7 to deploy ``` ## Complete Example @@ -437,7 +472,7 @@ openssl x509 -req \ -signkey my-ca-key.pem \ -out my-ca.pem \ -days 3650 \ - -extfile <(printf "basicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign") + -extfile <(printf "basicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always,issuer:always") ``` **Result**: Three files @@ -494,26 +529,22 @@ openssl x509 -in coturn-federation-cert.pem -noout -dates # Output: notBefore=... notAfter=... (1 year from now) ``` -### Step 4: Encode and Deploy - -```bash -# Encode as single-line base64 (works on Linux and macOS) -echo "=== Certificate (base64) ===" -base64 < coturn-federation-cert.pem | tr -d '\n' -echo "" -echo "=== Private Key (base64) ===" -base64 < coturn-federation-key.pem | tr -d '\n' -echo "" -``` +### Step 4: Deploy -Update `values/coturn/values.yaml`: +Update `values/coturn/values.yaml` with the PEM content: ```yaml federate: dtls: tls: - key: - crt: + key: | + -----BEGIN PRIVATE KEY----- + + -----END PRIVATE KEY----- + crt: | + -----BEGIN CERTIFICATE----- + + -----END CERTIFICATE----- ``` Deploy: @@ -560,15 +591,19 @@ openssl x509 -req -days 365 \ -sha256 \ -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com\nextendedKeyUsage=serverAuth,clientAuth") -# Encode new certificate and key -echo "=== New Certificate (base64) ===" -base64 < coturn-federation-cert.pem | tr -d '\n' -echo "" -echo "=== New Private Key (base64) ===" -base64 < coturn-federation-key.pem | tr -d '\n' -echo "" +# Update values/coturn/values.yaml — replace the key/crt block scalars with the new PEM content: +# federate: +# dtls: +# tls: +# key: | +# -----BEGIN PRIVATE KEY----- +# +# -----END PRIVATE KEY----- +# crt: | +# -----BEGIN CERTIFICATE----- +# +# -----END CERTIFICATE----- -# Update values/coturn/values.yaml with the new base64 strings, then redeploy helm upgrade coturn ./charts/coturn \ -n default \ -f values/coturn/values.yaml \ @@ -585,7 +620,7 @@ When your coturn certificate approaches expiration (typically 365 days), you nee ### Renewal Process -1. **Generate a new CSR** (follow Step 1): +1. **Generate a new CSR** (follow Step 2): ```bash # Create a new private key openssl genrsa -out coturn-key-new.pem 2048 @@ -600,31 +635,27 @@ When your coturn certificate approaches expiration (typically 365 days), you nee -addext "keyUsage=digitalSignature" ``` -2. **Sign the new certificate with your CA** (follow Step 2): +2. **Sign the new certificate with your CA** (follow Step 3): ```bash openssl x509 -req -days 365 \ -in coturn-new.csr \ - -CA ca-cert.pem \ - -CAkey ca-key.pem \ + -CA my-ca.pem \ + -CAkey my-ca-key.pem \ -CAcreateserial \ -out coturn-cert-new.pem \ -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth,clientAuth") ``` -3. **Verify the new certificate** (follow Step 3): +3. **Verify the new certificate** (follow Step 4): ```bash openssl x509 -in coturn-cert-new.pem -text -noout | grep -A 3 "Extended Key Usage" openssl x509 -in coturn-cert-new.pem -noout -dates ``` -4. **Encode the new certificate and key as base64** (follow Step 4): +4. **Prepare the new certificate and key** (follow Step 5): ```bash - echo "=== New Certificate (base64) ===" - base64 < coturn-cert-new.pem | tr -d '\n' - echo "" - echo "=== New Private Key (base64) ===" - base64 < coturn-key-new.pem | tr -d '\n' - echo "" + cat coturn-cert-new.pem + cat coturn-key-new.pem ``` 5. **Backup current values file**: @@ -632,13 +663,19 @@ When your coturn certificate approaches expiration (typically 365 days), you nee cp values/coturn/values.yaml values/coturn/values.yaml.backup.$(date +%Y%m%d-%H%M%S) ``` -6. **Update values file** with the new base64-encoded certificate and key: +6. **Update values file** with the new PEM certificate and key: ```yaml federate: dtls: tls: - key: - crt: + key: | + -----BEGIN PRIVATE KEY----- + + -----END PRIVATE KEY----- + crt: | + -----BEGIN CERTIFICATE----- + + -----END CERTIFICATE----- ``` 7. **Verify YAML syntax**: @@ -646,7 +683,7 @@ When your coturn certificate approaches expiration (typically 365 days), you nee helm lint ./charts/coturn -f values/coturn/values.yaml ``` -8. **Redeploy coturn** with the new certificate (follow Step 6): +8. **Redeploy coturn** with the new certificate (follow Step 7): ```bash helm upgrade coturn ./charts/coturn \ -n default \ @@ -655,7 +692,7 @@ When your coturn certificate approaches expiration (typically 365 days), you nee --timeout 5m ``` -9. **Verify deployment** (follow Step 7): +9. **Verify deployment** (follow Step 8): ```bash COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') @@ -679,8 +716,8 @@ When your coturn certificate approaches expiration (typically 365 days), you nee - [ ] Sign with your CA certificate - [ ] Verify new certificate has correct EKU and issuer - [ ] Backup current values file -- [ ] Encode new certificate and key as base64 -- [ ] Update values file with new base64 strings +- [ ] Prepare new PEM certificate and key files +- [ ] Update values file with new PEM content - [ ] Run `helm lint` to verify YAML syntax - [ ] Run `helm upgrade` with `--wait` flag - [ ] Verify pod restart completed successfully From 13bb71da2c60eb7e6d2d349db2601177833f4c46 Mon Sep 17 00:00:00 2001 From: Sukanta Date: Fri, 22 May 2026 16:09:00 +0200 Subject: [PATCH 3/7] Apply suggestions from code review Co-authored-by: Mathias Staab <71255223+mastaab@users.noreply.github.com> --- src/how-to/administrate/coturn-client-certificate.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/how-to/administrate/coturn-client-certificate.md b/src/how-to/administrate/coturn-client-certificate.md index 995ffdf..dda5064 100644 --- a/src/how-to/administrate/coturn-client-certificate.md +++ b/src/how-to/administrate/coturn-client-certificate.md @@ -15,23 +15,23 @@ Coturn federation DTLS connections (port 9191) require mutual TLS authentication - `openssl` command-line tool installed locally - `kubectl` access to your cluster - FQDN for your coturn deployment (e.g., `coturn.example.com`) -- **CA certificate** and **CA private key** — create one in Step 1 if you don't have one yet; once Wire Cloud trusts your CA you can reuse it for all future renewals +- **CA certificate** and **CA private key** — create one in Step 1 if you don't have one yet; once your federation partner (e.g. Wire Cloud) trusts your CA you can reuse it for all future renewals ### Deployment Model The typical workflow for a self-managed coturn deployment: -1. **Create a self-signed CA** (long validity, e.g. 10 years): `my-ca.pem` +1. **Select issuing CA** (create self-signed or use existing private CA) 2. **Send your CA** to Wire Cloud to add to their federation trust store 3. **Generate a coturn certificate** signed by that CA with serverAuth+clientAuth EKU 4. **Deploy coturn** with the certificate in Helm values -5. **Renew annually** by signing a new certificate with the same CA — no need to contact Wire Cloud again +5. **Renew annually** by signing a new certificate with the same CA — no need to contact your federation partner again ## Step 1: Create a Self-Signed CA (skip if you already have one) -If your organization already has a CA and Wire Cloud already trusts it, skip to Step 2. +If your organization already has a CA and your federation partners already trusts it, skip to Step 2. -Otherwise, create a self-signed CA. You do this **once** — the CA is long-lived (10 years) and is reused for all future coturn certificate renewals without needing to contact Wire Cloud again. +Otherwise, create a self-signed CA. You do this **once** — the CA is long-lived (10 years) and is reused for all future coturn certificate renewals without needing to contact your federation partners again. ```bash # Generate CA private key (2048-bit RSA) @@ -57,7 +57,7 @@ openssl x509 -req \ - `my-ca-key.pem` — CA private key; keep this secure, it is needed for all future renewals - `my-ca.csr` — can be deleted -**Important**: Wait until Wire Cloud confirms your CA is in their trust store before proceeding. +**Important**: Wait until your federation partner confirms your CA is in their trust store before proceeding. ## Step 2: Create a Certificate Signing Request (CSR) From 03dac6cae5cb45d81d623b028ba966671caa98c4 Mon Sep 17 00:00:00 2001 From: sghosh23 Date: Fri, 22 May 2026 16:30:44 +0200 Subject: [PATCH 4/7] update based on code review --- .../administrate/coturn-client-certificate.md | 129 +++--------------- 1 file changed, 16 insertions(+), 113 deletions(-) diff --git a/src/how-to/administrate/coturn-client-certificate.md b/src/how-to/administrate/coturn-client-certificate.md index dda5064..d99d9ab 100644 --- a/src/how-to/administrate/coturn-client-certificate.md +++ b/src/how-to/administrate/coturn-client-certificate.md @@ -76,7 +76,7 @@ openssl req -new \ -key coturn-key.pem \ -out coturn.csr \ -subj "/C=US/ST=State/L=City/O=Your Organization/CN=coturn.example.com" \ - -addext "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local" \ + -addext "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com" \ -addext "extendedKeyUsage=serverAuth,clientAuth" \ -addext "keyUsage=digitalSignature" ``` @@ -99,7 +99,7 @@ openssl x509 -req -days 365 \ -CAkey my-ca-key.pem \ -CAcreateserial \ -out coturn-cert.pem \ - -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth,clientAuth") + -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth,clientAuth") ``` Verify the signed certificate: @@ -158,14 +158,6 @@ Update your coturn Helm values file (`values/coturn/values.yaml`) with the PEM c ```yaml # Existing coturn configuration -nodeSelector: - wire.com/role: coturn - -replicaCount: 3 -coturnTurnListenIP: "__COTURN_POD_IP__" -coturnTurnExternalIP: "__COTURN_EXT_IP__" -coturnTurnRelayIP: "__COTURN_POD_IP__" - # DTLS Federation certificate configuration federate: dtls: @@ -179,64 +171,10 @@ federate: -----END CERTIFICATE----- -# Existing secrets configuration -secrets: - zrestSecrets: - - "" - -# Rate limiting allowlist for federation. -# Add all IPs that coturn must accept connections from without rate limiting: -# -# 1. Internal node IPs — the Kubernetes node IPs where coturn pods are scheduled. -# Add one entry per node. -# -# 2. Cluster gateway / NAT IP — if your cluster routes outgoing traffic through -# a single gateway or NAT IP, add that IP too (coturn sees it as the source). -# -# 3. Public (external) IPs of each coturn replica — the IPs advertised externally -# for each StatefulSet pod (coturn-0, coturn-1, coturn-2, ...). -# -# 4. Federation partner IPs — IP addresses or CIDR ranges of Wire Cloud or other -# federation partners that connect to coturn on port 9191. -# -# Example: -config: - verboseLogging: false - ratelimit: - allowlist: - - "192.168.1.10" # node-1 internal IP - - "192.168.1.11" # node-2 internal IP - - "192.168.1.12" # node-3 internal IP - - "192.168.1.1" # cluster gateway / NAT IP (if applicable) - - "203.0.113.10" # coturn-0 external/public IP - - "203.0.113.11" # coturn-1 external/public IP - - "203.0.113.12" # coturn-2 external/public IP - - "198.51.100.0/24" # federation partner IP range -``` - -### Example YAML Values - -```yaml -federate: - dtls: - tls: - key: | - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7W8z1K2... - -----END PRIVATE KEY----- - crt: | - -----BEGIN CERTIFICATE----- - MIIDazCCAlOgAwIBAgIUfQ2Z7x8zV0Q8JvZ0Q0Q0Q0Q0Q0AwDQYJKoZIhvcNAQEL... - -----END CERTIFICATE----- -``` ## Step 7: Deploy Coturn with Updated Configuration -**Prerequisite**: The coturn chart must be at version `0.0.44` or later. Support for manually providing a self-signed certificate via `federate.dtls.tls.key`/`crt` was added in this version — earlier versions only support cert-manager-managed certificates. Verify your chart version: - -```bash -helm show chart ./charts/coturn | grep '^version:' -``` +**Prerequisite**: Requires coturn chart version `4.6.2-federation-wireapp.44` or later — earlier versions only support cert-manager-managed certificates and will reject `federate.dtls.tls.key`/`crt` values. Apply the updated Helm values: @@ -252,11 +190,6 @@ helm upgrade --install coturn ./charts/coturn \ --timeout 5m ``` -Or if using helmfile: - -```bash -helmfile sync -``` Monitor the rollout: @@ -332,23 +265,18 @@ helm get values coturn -n default | grep -A 10 "federate" **Solution**: -1. Verify the values file has the correct PEM certificate: - ```bash - grep -A 5 "federate:" values/coturn/values.yaml - ``` - -2. Check if Helm Secret was created: +1. Check if Helm Secret was created: ```bash kubectl get secret coturn-dtls-certificate -n default -o yaml ``` -3. Verify pod is using the new certificate: +2. Verify pod is using the new certificate: ```bash COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -noout -dates ``` -4. If pod still has old certificate, restart it: +3. If pod still has old certificate, restart it: ```bash kubectl delete pod $COTURN_POD -n default kubectl wait --for=condition=ready pod -l app=coturn -n default --timeout=300s @@ -376,28 +304,19 @@ helm get values coturn -n default | grep -A 10 "federate" **Solution**: -1. Check pod events: +1. Check pod events and logs: ```bash COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') kubectl describe pod $COTURN_POD -n default - ``` - -2. Check pod logs: - ```bash kubectl logs $COTURN_POD -n default --previous ``` -3. Verify the Secret data is valid: - ```bash - kubectl get secret coturn-dtls-certificate -n default -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout | head -5 - ``` - -4. Check for YAML syntax errors in values file: +2. Check for YAML syntax errors in values file: ```bash helm lint ./charts/coturn -f values/coturn/values.yaml ``` -5. If issues persist, rollback to previous Helm revision: +3. If issues persist, rollback to previous Helm revision: ```bash helm rollback coturn -n default kubectl rollout status statefulset/coturn -n default @@ -419,34 +338,18 @@ helm get values coturn -n default | grep -A 10 "federate" helm upgrade coturn ./charts/coturn -f values/coturn/values.yaml -n default --wait --timeout 10m ``` -3. Check StatefulSet rollout status: - ```bash - kubectl rollout status statefulset/coturn -n default - ``` - ### Certificate Signed by Wrong CA **Symptom**: Certificate looks valid locally but federation partners can't authenticate. **Solution**: -1. Verify certificate issuer matches your CA: - ```bash - openssl x509 -in coturn-cert.pem -noout -issuer - ``` - -2. Verify the CA that signed the certificate: +1. Verify certificate issuer: ```bash openssl x509 -in coturn-cert.pem -noout -text | grep -A 2 "Issuer:" ``` -3. If wrong CA was used, regenerate the certificate using the correct CA: - ```bash - # Follow Step 2 to create a new CSR - # Follow Step 3 to sign it with the CORRECT CA - # Verify in Step 4 that issuer matches your trusted CA - # Continue with Steps 5-7 to deploy - ``` +2. If the wrong CA was used, regenerate the certificate following Steps 2–3 with the correct CA, then redeploy via Steps 5–7. ## Complete Example @@ -624,13 +527,13 @@ When your coturn certificate approaches expiration (typically 365 days), you nee ```bash # Create a new private key openssl genrsa -out coturn-key-new.pem 2048 - + # Create a new certificate signing request openssl req -new \ -key coturn-key-new.pem \ -out coturn-new.csr \ -subj "/C=US/ST=State/L=City/O=Your Organization/CN=coturn.example.com" \ - -addext "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local" \ + -addext "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com" \ -addext "extendedKeyUsage=serverAuth,clientAuth" \ -addext "keyUsage=digitalSignature" ``` @@ -643,7 +546,7 @@ When your coturn certificate approaches expiration (typically 365 days), you nee -CAkey my-ca-key.pem \ -CAcreateserial \ -out coturn-cert-new.pem \ - -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.coturn.default.svc.cluster.local,DNS:coturn-1.coturn.default.svc.cluster.local\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth,clientAuth") + -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth,clientAuth") ``` 3. **Verify the new certificate** (follow Step 4): @@ -695,10 +598,10 @@ When your coturn certificate approaches expiration (typically 365 days), you nee 9. **Verify deployment** (follow Step 8): ```bash COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') - + # Check new certificate is deployed kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -noout -dates - + # Verify Extended Key Usage kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -text -noout | grep -A 3 "Extended Key Usage" ``` From cdc1f0feac3fc753012b686877a8ad447048fe80 Mon Sep 17 00:00:00 2001 From: sghosh23 Date: Fri, 22 May 2026 16:41:51 +0200 Subject: [PATCH 5/7] make the doc less verbose --- .../administrate/coturn-client-certificate.md | 331 +++--------------- 1 file changed, 44 insertions(+), 287 deletions(-) diff --git a/src/how-to/administrate/coturn-client-certificate.md b/src/how-to/administrate/coturn-client-certificate.md index d99d9ab..1cad0df 100644 --- a/src/how-to/administrate/coturn-client-certificate.md +++ b/src/how-to/administrate/coturn-client-certificate.md @@ -174,8 +174,7 @@ federate: ## Step 7: Deploy Coturn with Updated Configuration -**Prerequisite**: Requires coturn chart version `4.6.2-federation-wireapp.44` or later — earlier versions only support cert-manager-managed certificates and will reject `federate.dtls.tls.key`/`crt` values. - +**Prerequisite**: Requires coturn chart version `4.6.2-federation-wireapp.44` or later. Apply the updated Helm values: ```bash @@ -265,18 +264,23 @@ helm get values coturn -n default | grep -A 10 "federate" **Solution**: -1. Check if Helm Secret was created: +1. Verify the values file has the correct PEM certificate: + ```bash + grep -A 5 "federate:" values/coturn/values.yaml + ``` + +2. Check if Helm Secret was created: ```bash kubectl get secret coturn-dtls-certificate -n default -o yaml ``` -2. Verify pod is using the new certificate: +3. Verify pod is using the new certificate: ```bash COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -noout -dates ``` -3. If pod still has old certificate, restart it: +4. If pod still has old certificate, restart it: ```bash kubectl delete pod $COTURN_POD -n default kubectl wait --for=condition=ready pod -l app=coturn -n default --timeout=300s @@ -304,19 +308,28 @@ helm get values coturn -n default | grep -A 10 "federate" **Solution**: -1. Check pod events and logs: +1. Check pod events: ```bash COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') kubectl describe pod $COTURN_POD -n default + ``` + +2. Check pod logs: + ```bash kubectl logs $COTURN_POD -n default --previous ``` -2. Check for YAML syntax errors in values file: +3. Verify the Secret data is valid: + ```bash + kubectl get secret coturn-dtls-certificate -n default -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout | head -5 + ``` + +4. Check for YAML syntax errors in values file: ```bash helm lint ./charts/coturn -f values/coturn/values.yaml ``` -3. If issues persist, rollback to previous Helm revision: +5. If issues persist, rollback to previous Helm revision: ```bash helm rollback coturn -n default kubectl rollout status statefulset/coturn -n default @@ -338,308 +351,52 @@ helm get values coturn -n default | grep -A 10 "federate" helm upgrade coturn ./charts/coturn -f values/coturn/values.yaml -n default --wait --timeout 10m ``` -### Certificate Signed by Wrong CA - -**Symptom**: Certificate looks valid locally but federation partners can't authenticate. - -**Solution**: - -1. Verify certificate issuer: - ```bash - openssl x509 -in coturn-cert.pem -noout -text | grep -A 2 "Issuer:" - ``` - -2. If the wrong CA was used, regenerate the certificate following Steps 2–3 with the correct CA, then redeploy via Steps 5–7. - -## Complete Example - -This example shows the full end-to-end workflow. Replace `coturn.example.com`, the subject fields, and the replica SANs with your actual FQDN and organization details. - -### Step 1: Create Your Self-Signed CA (One-Time Setup) - -Create your own CA to manage federation independently: - -```bash -# Generate CA private key (2048-bit RSA) -openssl genrsa -out my-ca-key.pem 2048 - -# Create CA certificate signing request -openssl req -new \ - -key my-ca-key.pem \ - -out my-ca.csr \ - -subj "/C=XX/O=Your Organization/CN=Your Organization CA" - -# Self-sign CA certificate (valid 10 years = 3650 days) -openssl x509 -req \ - -in my-ca.csr \ - -signkey my-ca-key.pem \ - -out my-ca.pem \ - -days 3650 \ - -extfile <(printf "basicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always,issuer:always") -``` - -**Result**: Three files -- `my-ca.pem` - CA certificate (send this to Wire Cloud) -- `my-ca-key.pem` - CA private key (keep secure, needed for renewals) -- `my-ca.csr` - Can be deleted - -**Next**: Send `my-ca.pem` to Wire Cloud to add to their federation trust store. - -### Step 2: Create Coturn Certificate Signed by Your CA - -Once Wire Cloud has added your CA to their trust store, create the coturn certificate: - -```bash -# Generate coturn private key and CSR in one command -openssl req -noenc -newkey rsa:2048 \ - -keyout coturn-federation-key.pem \ - -out coturn-federation.csr \ - -subj "/C=XX/O=Your Organization/CN=coturn.example.com" - -# Sign with your CA (valid 1 year) -openssl x509 -req -days 365 \ - -in coturn-federation.csr \ - -CA my-ca.pem \ - -CAkey my-ca-key.pem \ - -CAcreateserial \ - -out coturn-federation-cert.pem \ - -sha256 \ - -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com\nextendedKeyUsage=serverAuth,clientAuth") -``` - -**Result**: Three files -- `coturn-federation-cert.pem` - Signed coturn certificate -- `coturn-federation-key.pem` - Coturn private key -- `coturn-federation.csr` - Can be deleted - -### Step 3: Verify the Certificate - -```bash -# Verify it's signed by your CA -openssl verify -CAfile my-ca.pem coturn-federation-cert.pem -# Output: coturn-federation-cert.pem: OK - -# Check Extended Key Usage -openssl x509 -in coturn-federation-cert.pem -noout -text | grep -A 3 "Extended Key Usage" -# Output should show: TLS Web Server Authentication, TLS Web Client Authentication - -# Check Subject Alternative Names -openssl x509 -in coturn-federation-cert.pem -noout -text | grep -A 1 "Subject Alternative Name" -# Output should show: DNS:coturn.example.com, DNS:coturn-0/1/2.example.com - -# Check validity dates -openssl x509 -in coturn-federation-cert.pem -noout -dates -# Output: notBefore=... notAfter=... (1 year from now) -``` - -### Step 4: Deploy - -Update `values/coturn/values.yaml` with the PEM content: - -```yaml -federate: - dtls: - tls: - key: | - -----BEGIN PRIVATE KEY----- - - -----END PRIVATE KEY----- - crt: | - -----BEGIN CERTIFICATE----- - - -----END CERTIFICATE----- -``` - -Deploy: - -```bash -helm upgrade coturn ./charts/coturn \ - -n default \ - -f values/coturn/values.yaml \ - --wait \ - --timeout 5m -``` - -### Step 5: Verify in Kubernetes - -```bash -# Get pod name -COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') - -# Verify certificate is deployed -kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -noout -dates - -# Verify EKU -kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -text -noout | grep -A 3 "Extended Key Usage" -``` - -### Annual Certificate Renewal - -When the certificate expires: - -```bash -# Generate new private key and CSR -openssl req -noenc -newkey rsa:2048 \ - -keyout coturn-federation-key.pem \ - -out coturn-federation.csr \ - -subj "/C=XX/O=Your Organization/CN=coturn.example.com" - -# Sign with EXISTING CA (same CA, already trusted by Wire Cloud) -openssl x509 -req -days 365 \ - -in coturn-federation.csr \ - -CA my-ca.pem \ - -CAkey my-ca-key.pem \ - -CAcreateserial \ - -out coturn-federation-cert.pem \ - -sha256 \ - -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com\nextendedKeyUsage=serverAuth,clientAuth") - -# Update values/coturn/values.yaml — replace the key/crt block scalars with the new PEM content: -# federate: -# dtls: -# tls: -# key: | -# -----BEGIN PRIVATE KEY----- -# -# -----END PRIVATE KEY----- -# crt: | -# -----BEGIN CERTIFICATE----- -# -# -----END CERTIFICATE----- - -helm upgrade coturn ./charts/coturn \ - -n default \ - -f values/coturn/values.yaml \ - --wait -``` - -**Key point**: No need to contact Wire Cloud again for renewal — the CA is already trusted. Just generate a new certificate signed by the same CA and deploy it. - ---- - -## Certificate Renewal - -When your coturn certificate approaches expiration (typically 365 days), you need to generate and deploy a new certificate signed by your CA before the old one expires. - -### Renewal Process - -1. **Generate a new CSR** (follow Step 2): +3. Check StatefulSet rollout status: ```bash - # Create a new private key - openssl genrsa -out coturn-key-new.pem 2048 - - # Create a new certificate signing request - openssl req -new \ - -key coturn-key-new.pem \ - -out coturn-new.csr \ - -subj "/C=US/ST=State/L=City/O=Your Organization/CN=coturn.example.com" \ - -addext "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com" \ - -addext "extendedKeyUsage=serverAuth,clientAuth" \ - -addext "keyUsage=digitalSignature" + kubectl rollout status statefulset/coturn -n default ``` -2. **Sign the new certificate with your CA** (follow Step 3): - ```bash - openssl x509 -req -days 365 \ - -in coturn-new.csr \ - -CA my-ca.pem \ - -CAkey my-ca-key.pem \ - -CAcreateserial \ - -out coturn-cert-new.pem \ - -extfile <(printf "subjectAltName=DNS:coturn.example.com,DNS:coturn-0.example.com,DNS:coturn-1.example.com,DNS:coturn-2.example.com\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth,clientAuth") - ``` +### Certificate Signed by Wrong CA -3. **Verify the new certificate** (follow Step 4): - ```bash - openssl x509 -in coturn-cert-new.pem -text -noout | grep -A 3 "Extended Key Usage" - openssl x509 -in coturn-cert-new.pem -noout -dates - ``` +**Symptom**: Certificate looks valid locally but federation partners can't authenticate. -4. **Prepare the new certificate and key** (follow Step 5): - ```bash - cat coturn-cert-new.pem - cat coturn-key-new.pem - ``` +**Solution**: -5. **Backup current values file**: +1. Verify certificate issuer matches your CA: ```bash - cp values/coturn/values.yaml values/coturn/values.yaml.backup.$(date +%Y%m%d-%H%M%S) + openssl x509 -in coturn-cert.pem -noout -issuer ``` -6. **Update values file** with the new PEM certificate and key: - ```yaml - federate: - dtls: - tls: - key: | - -----BEGIN PRIVATE KEY----- - - -----END PRIVATE KEY----- - crt: | - -----BEGIN CERTIFICATE----- - - -----END CERTIFICATE----- - ``` - -7. **Verify YAML syntax**: +2. Verify the CA that signed the certificate: ```bash - helm lint ./charts/coturn -f values/coturn/values.yaml + openssl x509 -in coturn-cert.pem -noout -text | grep -A 2 "Issuer:" ``` -8. **Redeploy coturn** with the new certificate (follow Step 7): +3. If wrong CA was used, regenerate the certificate using the correct CA: ```bash - helm upgrade coturn ./charts/coturn \ - -n default \ - -f values/coturn/values.yaml \ - --wait \ - --timeout 5m + # Follow Step 2 to create a new CSR + # Follow Step 3 to sign it with the CORRECT CA + # Verify in Step 4 that issuer matches your trusted CA + # Continue with Steps 5-7 to deploy ``` -9. **Verify deployment** (follow Step 8): - ```bash - COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') - - # Check new certificate is deployed - kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -noout -dates - - # Verify Extended Key Usage - kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -text -noout | grep -A 3 "Extended Key Usage" - ``` +## Certificate Renewal -10. **Check Helm release history**: - ```bash - helm history coturn -n default - ``` +Renewal follows the same process as initial deployment (Steps 2–8). Your CA is already trusted by Wire Cloud — no need to notify them again. Plan renewal at least 30 days before expiry: -### Renewal Checklist +```bash +openssl x509 -in coturn-cert.pem -noout -dates +``` -- [ ] Calculate expiration date: `openssl x509 -in coturn-cert.pem -noout -dates` -- [ ] Plan renewal at least 30 days before expiration -- [ ] Generate new CSR with same FQDN and EKU extensions -- [ ] Sign with your CA certificate -- [ ] Verify new certificate has correct EKU and issuer -- [ ] Backup current values file -- [ ] Prepare new PEM certificate and key files -- [ ] Update values file with new PEM content -- [ ] Run `helm lint` to verify YAML syntax -- [ ] Run `helm upgrade` with `--wait` flag -- [ ] Verify pod restart completed successfully -- [ ] Verify new certificate in pod -- [ ] Test federation DTLS connections -- [ ] Document renewal date in your records +Then follow Steps 2–8 using your existing `my-ca.pem` and `my-ca-key.pem`. -### Rollback to Previous Certificate +### Rollback -If something goes wrong during renewal, rollback to the previous certificate: +If something goes wrong, rollback to the previous Helm release: ```bash -# View Helm release history helm history coturn -n default - -# Rollback to the previous release (e.g., revision 5) -helm rollback coturn 5 -n default - -# Verify rollback +helm rollback coturn -n default kubectl rollout status statefulset/coturn -n default ``` From 95a7b5e0fa14ae79e0f0d747c796ae4fd0803aa5 Mon Sep 17 00:00:00 2001 From: sghosh23 Date: Tue, 26 May 2026 09:07:13 +0200 Subject: [PATCH 6/7] reduce more verbosity --- .../administrate/coturn-client-certificate.md | 142 +++++++----------- 1 file changed, 51 insertions(+), 91 deletions(-) diff --git a/src/how-to/administrate/coturn-client-certificate.md b/src/how-to/administrate/coturn-client-certificate.md index 1cad0df..42ad841 100644 --- a/src/how-to/administrate/coturn-client-certificate.md +++ b/src/how-to/administrate/coturn-client-certificate.md @@ -178,9 +178,6 @@ federate: Apply the updated Helm values: ```bash -# Navigate to wire-server-deploy directory -cd /path/to/wire-server-deploy - # Deploy or upgrade the coturn Helm chart with the updated values helm upgrade --install coturn ./charts/coturn \ -n default \ @@ -208,16 +205,16 @@ After the Helm upgrade completes, verify that the certificate is properly mounte ```bash # Get the coturn pod name -COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') +COTURN_POD=$(kubectl get pods -l app=coturn -n -o jsonpath='{.items[0].metadata.name}') # Verify the Kubernetes Secret was created -kubectl get secret coturn-dtls-certificate -n default -o yaml +kubectl get secret coturn-dtls-certificate -n -o yaml # Check if certificate files exist in the pod -kubectl exec -it $COTURN_POD -n default -- ls -la /coturn-dtls-certificate/ +kubectl exec -it $COTURN_POD -n -- ls -la /coturn-dtls-certificate/ # Verify the certificate content and EKU from the pod -kubectl exec -it $COTURN_POD -n default -- openssl x509 -in /coturn-dtls-certificate/tls.crt -text -noout | grep -A 3 "Extended Key Usage" +kubectl exec -it $COTURN_POD -n -- openssl x509 -in /coturn-dtls-certificate/tls.crt -text -noout | grep -A 3 "Extended Key Usage" ``` Expected output showing both serverAuth and clientAuth: @@ -233,13 +230,13 @@ To verify that coturn can now authenticate with federation partners, check the c ```bash # Get the coturn pod name (if not already set) -COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') +COTURN_POD=$(kubectl get pods -l app=coturn -n -o jsonpath='{.items[0].metadata.name}') # Stream coturn logs to watch for DTLS connections -kubectl logs -f $COTURN_POD -n default +kubectl logs -f $COTURN_POD -n # Or retrieve recent logs and filter for DTLS-related messages -kubectl logs $COTURN_POD -n default --tail=100 | grep -iE 'dtls|tls|certificate|federation' +kubectl logs $COTURN_POD -n --tail=100 | grep -iE 'dtls|tls|certificate|federation' ``` Look for successful DTLS connection messages or client authentication confirmations in the logs. @@ -258,127 +255,90 @@ helm get values coturn -n default | grep -A 10 "federate" ## Troubleshooting -### Certificate Not Loaded in Pod +### Common Diagnostics -**Symptom**: Coturn pod starts but certificate files are missing or old certificate is still in use. +Commands referenced by multiple sections below: -**Solution**: +```bash +# Get coturn pod name +COTURN_POD=$(kubectl get pods -l app=coturn -n -o jsonpath='{.items[0].metadata.name}') -1. Verify the values file has the correct PEM certificate: - ```bash - grep -A 5 "federate:" values/coturn/values.yaml - ``` +# Check pod events and logs +kubectl describe pod $COTURN_POD -n +kubectl logs $COTURN_POD -n --previous -2. Check if Helm Secret was created: - ```bash - kubectl get secret coturn-dtls-certificate -n default -o yaml - ``` +# Check Helm secret +kubectl get secret coturn-dtls-certificate -n -o yaml + +# Check rollout status +kubectl rollout status statefulset/coturn -n +``` + +### Certificate Not Loaded in Pod -3. Verify pod is using the new certificate: +**Symptom**: Pod starts but certificate is missing or stale. + +1. Check the Helm secret exists and has data (see Common Diagnostics). +2. Inspect the certificate in the pod: ```bash - COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') kubectl exec $COTURN_POD -- openssl x509 -in /coturn-dtls-certificate/tls.crt -noout -dates ``` - -4. If pod still has old certificate, restart it: +3. If the pod still has the old certificate, restart it: ```bash - kubectl delete pod $COTURN_POD -n default - kubectl wait --for=condition=ready pod -l app=coturn -n default --timeout=300s + kubectl delete pod $COTURN_POD -n + kubectl wait --for=condition=ready pod -l app=coturn -n --timeout=300s ``` ### Certificate Missing Client EKU -**Symptom**: Coturn connects to federation partners but DTLS authentication fails. +**Symptom**: DTLS authentication fails with federation partners. -**Solution**: +Verify both EKU values are present: -1. Verify the certificate has both serverAuth and clientAuth: - ```bash - openssl x509 -in coturn-cert.pem -text -noout | grep -A 3 "Extended Key Usage" - ``` +```bash +openssl x509 -in coturn-cert.pem -text -noout | grep -A 3 "Extended Key Usage" +``` -2. If output doesn't show both `TLS Web Server Authentication` and `TLS Web Client Authentication`, regenerate the certificate: - - Follow Step 2 to create a new CSR with proper EKU flags - - Follow Step 3 to sign it with your CA - - Continue with Steps 5-7 to deploy +Output must show `TLS Web Server Authentication` and `TLS Web Client Authentication`. If not, regenerate following Steps 2–3 and redeploy via Steps 5–7. -### Coturn Pod Fails to Start +### Pod Fails to Start (CrashLoopBackOff) **Symptom**: Pod enters `CrashLoopBackOff` after Helm upgrade. -**Solution**: - -1. Check pod events: - ```bash - COTURN_POD=$(kubectl get pods -l app=coturn -n default -o jsonpath='{.items[0].metadata.name}') - kubectl describe pod $COTURN_POD -n default - ``` - -2. Check pod logs: - ```bash - kubectl logs $COTURN_POD -n default --previous - ``` - -3. Verify the Secret data is valid: - ```bash - kubectl get secret coturn-dtls-certificate -n default -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout | head -5 - ``` - -4. Check for YAML syntax errors in values file: +1. Check pod events and logs (see Common Diagnostics). +2. Check for YAML syntax errors: ```bash helm lint ./charts/coturn -f values/coturn/values.yaml ``` - -5. If issues persist, rollback to previous Helm revision: +3. If issues persist, rollback: ```bash - helm rollback coturn -n default - kubectl rollout status statefulset/coturn -n default + helm rollback coturn -n ``` ### Helm Upgrade Stuck or Slow -**Symptom**: `helm upgrade` command takes a long time or appears hung. - -**Solution**: - -1. Check pod restart status: - ```bash - kubectl get pods -n default | grep coturn - ``` +**Symptom**: `helm upgrade` hangs. -2. Increase timeout if needed: +1. Check pod status: ```bash - helm upgrade coturn ./charts/coturn -f values/coturn/values.yaml -n default --wait --timeout 10m + kubectl get pods -n | grep coturn ``` - -3. Check StatefulSet rollout status: +2. Re-run with a longer timeout: ```bash - kubectl rollout status statefulset/coturn -n default + helm upgrade coturn ./charts/coturn -f values/coturn/values.yaml -n --wait --timeout 10m ``` ### Certificate Signed by Wrong CA **Symptom**: Certificate looks valid locally but federation partners can't authenticate. -**Solution**: - -1. Verify certificate issuer matches your CA: - ```bash - openssl x509 -in coturn-cert.pem -noout -issuer - ``` +Check the issuer: -2. Verify the CA that signed the certificate: - ```bash - openssl x509 -in coturn-cert.pem -noout -text | grep -A 2 "Issuer:" - ``` +```bash +openssl x509 -in coturn-cert.pem -noout -issuer +``` -3. If wrong CA was used, regenerate the certificate using the correct CA: - ```bash - # Follow Step 2 to create a new CSR - # Follow Step 3 to sign it with the CORRECT CA - # Verify in Step 4 that issuer matches your trusted CA - # Continue with Steps 5-7 to deploy - ``` +If it doesn't match your CA, regenerate following Steps 2–3 with the correct CA and redeploy via Steps 5–7. ## Certificate Renewal From 43b44b52ffebbffe76348e417290ef27b6631749 Mon Sep 17 00:00:00 2001 From: sghosh23 Date: Tue, 26 May 2026 09:12:13 +0200 Subject: [PATCH 7/7] fix broken link --- src/how-to/administrate/coturn-client-certificate.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/how-to/administrate/coturn-client-certificate.md b/src/how-to/administrate/coturn-client-certificate.md index 42ad841..76d9b62 100644 --- a/src/how-to/administrate/coturn-client-certificate.md +++ b/src/how-to/administrate/coturn-client-certificate.md @@ -363,5 +363,5 @@ kubectl rollout status statefulset/coturn -n default ## Related Documentation - [Coturn Installation](../install/) - General coturn setup in wire-server-deploy -- [Wire-Server TLS Configuration](tls.md) - TLS certificate management -- [Federation Configuration](../../understand/federation.md) - Understanding federation in Wire +- [Wire-Server TLS Configuration](../install/tls.md) - TLS certificate management +- [Federation Configuration](../../understand/federation/README.md) - Understanding federation in Wire