Configure Istio ingress gateway with SSL certificates and custom domains for Kubernetes service mesh

Advanced 35 min Apr 21, 2026 112 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up Istio ingress gateway with automated SSL certificate management using cert-manager, configure custom domain routing with VirtualService, and implement TLS termination for secure service mesh traffic.

Prerequisites

  • Kubernetes cluster with admin access
  • Istio installed and configured
  • kubectl configured
  • Domain name with DNS management access

What this solves

This tutorial configures Istio ingress gateway to handle external traffic entering your Kubernetes service mesh with SSL certificates and custom domains. You'll set up cert-manager for automated certificate provisioning, configure Gateway resources for TLS termination, and create VirtualService rules for domain-based routing to your mesh services.

Step-by-step configuration

Update system packages

Start by updating your package manager to ensure kubectl and other tools are current.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Verify Istio installation

Check that Istio is installed and running in your cluster before configuring the ingress gateway.

kubectl get pods -n istio-system
kubectl get svc -n istio-system istio-ingressgateway
Note: If Istio isn't installed, follow our Istio installation guide first.

Install cert-manager

Deploy cert-manager to handle SSL certificate provisioning and renewal automatically.

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
kubectl wait --for=condition=Available --timeout=300s deployment/cert-manager -n cert-manager

Create ClusterIssuer for Let's Encrypt

Configure cert-manager to use Let's Encrypt for automatic SSL certificate generation.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: istio
kubectl apply -f letsencrypt-issuer.yaml

Create SSL certificate for your domain

Request a certificate for your custom domain that will be used by the Istio gateway.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com-tls
  namespace: istio-system
spec:
  secretName: example-com-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - example.com
  - www.example.com
  - api.example.com
kubectl apply -f ssl-certificate.yaml

Configure Istio Gateway with TLS termination

Create a Gateway resource to handle HTTPS traffic and terminate SSL at the ingress point.

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: example-gateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - example.com
    - www.example.com
    - api.example.com
    tls:
      httpsRedirect: true
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: example-com-tls
    hosts:
    - example.com
    - www.example.com
    - api.example.com
kubectl apply -f istio-gateway.yaml

Create sample application for testing

Deploy a simple web application to verify the ingress gateway configuration works properly.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: httpbin
  template:
    metadata:
      labels:
        app: httpbin
    spec:
      containers:
      - name: httpbin
        image: kennethreitz/httpbin
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  namespace: default
  labels:
    app: httpbin
spec:
  ports:
  - port: 8080
    targetPort: 80
    name: http
  selector:
    app: httpbin
kubectl apply -f sample-app.yaml
kubectl label namespace default istio-injection=enabled --overwrite

Configure VirtualService for custom domain routing

Create VirtualService rules to route traffic from your custom domains to specific services in the mesh.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: example-vs
  namespace: default
spec:
  hosts:
  - example.com
  - www.example.com
  gateways:
  - istio-system/example-gateway
  http:
  - match:
    - headers:
        host:
          exact: www.example.com
    redirect:
      uri: "/"
      authority: example.com
      redirectCode: 301
  - match:
    - uri:
        prefix: "/"
    route:
    - destination:
        host: httpbin
        port:
          number: 8080
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: api-vs
  namespace: default
spec:
  hosts:
  - api.example.com
  gateways:
  - istio-system/example-gateway
  http:
  - match:
    - uri:
        prefix: "/v1"
    route:
    - destination:
        host: httpbin
        port:
          number: 8080
    headers:
      request:
        add:
          x-api-version: "v1"
  - match:
    - uri:
        prefix: "/"
    route:
    - destination:
        host: httpbin
        port:
          number: 8080
kubectl apply -f virtual-service.yaml

Configure DNS records

Point your domain names to the Istio ingress gateway's external IP address.

kubectl get svc -n istio-system istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
Note: Create A records in your DNS provider pointing example.com, www.example.com, and api.example.com to this IP address.

Configure advanced routing with path-based rules

Add more sophisticated routing rules for different paths and HTTP methods.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: advanced-routing
  namespace: default
spec:
  hosts:
  - api.example.com
  gateways:
  - istio-system/example-gateway
  http:
  - match:
    - uri:
        exact: "/health"
    route:
    - destination:
        host: httpbin
        port:
          number: 8080
        subset: v1
    timeout: 5s
    retries:
      attempts: 3
      perTryTimeout: 2s
  - match:
    - uri:
        prefix: "/api/v2"
    headers:
      authorization:
        regex: "Bearer .*"
    route:
    - destination:
        host: httpbin
        port:
          number: 8080
    headers:
      request:
        add:
          x-forwarded-proto: https
      response:
        add:
          x-api-version: "v2"
  - match:
    - method:
        exact: POST
      uri:
        prefix: "/upload"
    route:
    - destination:
        host: httpbin
        port:
          number: 8080
    timeout: 30s
  - route:
    - destination:
        host: httpbin
        port:
          number: 8080
kubectl apply -f advanced-routing.yaml

Set up certificate renewal monitoring

Configure monitoring to ensure SSL certificates renew automatically and alert on failures.

apiVersion: v1
kind: ServiceMonitor
metadata:
  name: cert-manager-metrics
  namespace: cert-manager
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: cert-manager
  endpoints:
  - port: tcp-prometheus-servicemonitor
    interval: 30s
    path: /metrics
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: cert-manager-alerts
  namespace: cert-manager
spec:
  groups:
  - name: cert-manager
    rules:
    - alert: CertManagerCertificateExpiringSoon
      expr: certmanager_certificate_expiration_timestamp_seconds - time() < 86400 * 7
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "Certificate {{ $labels.name }} expires in less than 7 days"
    - alert: CertManagerCertificateNotReady
      expr: certmanager_certificate_ready_status == 0
      for: 10m
      labels:
        severity: critical
      annotations:
        summary: "Certificate {{ $labels.name }} is not ready"
kubectl apply -f cert-monitor.yaml

Verify your setup

Test the SSL certificate configuration and domain routing to ensure everything works correctly.

# Check certificate status
kubectl get certificate -n istio-system
kubectl describe certificate example-com-tls -n istio-system

Verify gateway configuration

kubectl get gateway -n istio-system kubectl describe gateway example-gateway -n istio-system

Test HTTPS connectivity

curl -v https://example.com/status/200 curl -v https://api.example.com/headers

Check certificate details

openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | openssl x509 -noout -dates

Verify HTTP to HTTPS redirect

curl -I http://example.com/
Note: SSL certificate provisioning can take 5-10 minutes. If certificates aren't ready immediately, wait and check again.

Common issues

Symptom Cause Fix
Certificate stuck in pending DNS not pointing to ingress IP Verify DNS A records point to ingress gateway external IP
502 Bad Gateway errors VirtualService routing misconfigured Check service names and ports in VirtualService match actual services
SSL certificate not found Certificate not in istio-system namespace Ensure Certificate resource is created in istio-system namespace
HTTP traffic not redirecting Gateway missing httpsRedirect: true Add httpsRedirect: true to HTTP server block in Gateway
Multiple domain routing fails VirtualService host matching issues Create separate VirtualService for each domain or use exact host matching

Next steps

Running this in production?

Want this handled for you? Running this at scale adds a second layer of work: capacity planning, failover drills, cost control, and on-call. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.