Connecting multiple Kubernetes clusters with Istio multicluster isn’t about magically making them talk; it’s about building a unified, secure, and observable network fabric across distributed environments, treating them as a single logical unit.

Let’s see this in action. Imagine we have two clusters, cluster-a and cluster-b, and we want a service deployed in cluster-a to be accessible from cluster-b as if it were local.

First, we need to establish trust. This means having a shared root Certificate Authority (CA) that both clusters trust. If you’re using a managed Kubernetes service, you might use their default CA, or you’ll generate a new one and distribute its public key.

In our example, let’s assume we have a root CA certificate root-cert.pem.

Cluster A Setup:

We’ll install Istio on cluster-a with a configuration that designates it as a primary cluster and enables remote cluster joining.

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: default
  meshConfig:
    trustDomain: cluster.local # Your chosen trust domain
    accessLogFile: /dev/stdout
    defaultConfig:
      proxyMetadata:
        # Enable Istio agent to fetch SDS from remote clusters
        ISTIO_META_DNS_CAPTURE: "true"
        ISTIO_META_DNS_INSECURE: "true" # For simplicity in demo, use proper CA in prod
  values:
    pilot:
      env:
        # Enable remote cluster discovery
        EXTERNAL_ISTIOD: "true"

Apply this with istioctl install -f cluster-a-istio.yaml --context cluster-a.

Then, we create a eastwest-gateway for traffic to and from other clusters.

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  # This configuration is applied on top of the base Istio installation
  components:
    ingressGateways:
    - name: istio-eastwestgateway
      enabled: true
      k8s:
        env:
        - name: ISTIO_META_ROUTER_MODE
          value: "sni" # Or "tcp" if you prefer
        overlays:
          # Enable mTLS on the eastwest gateway
          certs:
          - secretName: cacerts # This secret should contain your root CA
            items:
            - key: ca-cert.pem
              path: cacerts/root-cert.pem
            - key: cert-chain.pem
              path: cacerts/cert-chain.pem
            - key: key.pem
              path: cacerts/key.pem

Apply this with istioctl install -f cluster-a-eastwest.yaml --context cluster-a.

We also need to expose this gateway.

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: cross-network-gateway
  namespace: istio-system
spec:
  selector:
    istio: eastwestgateway
  servers:
  - port:
      number: 15443
      name: tls
      protocol: TLS
    tls:
      mode: AUTO_PASSTHROUGH
    hosts:
    - "*.local" # Or your specific domains

Cluster B Setup:

On cluster-b, we do a similar Istio installation but configure it to join a remote cluster.

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: default
  meshConfig:
    trustDomain: cluster.local # Must match cluster-a
    accessLogFile: /dev/stdout
    defaultConfig:
      proxyMetadata:
        ISTIO_META_DNS_CAPTURE: "true"
        ISTIO_META_DNS_INSECURE: "true" # Use proper CA in prod
  values:
    pilot:
      env:
        # Enable remote cluster discovery
        EXTERNAL_ISTIOD: "true"

Apply with istioctl install -f cluster-b-istio.yaml --context cluster-b.

Now, we configure cluster-b to connect to cluster-a’s Istiod. This is done by creating a RemoteCluster resource.

apiVersion: networking.istio.io/v1beta1
kind: RemoteCluster
metadata:
  name: cluster-a
spec:
  # The address of Istiod in cluster-a, accessible from cluster-b
  # This will be the Kubernetes API server address of cluster-a
  network: "network1" # A logical network name
  serviceAccountToken: <token_from_cluster_a> # Token for cluster-b to authenticate to cluster-a's API server
  discoveryAddress: <cluster_a_api_server_address> # e.g., https://1.2.3.4:6443
  secretName: cacerts # This secret must contain the root CA for cluster-a

The serviceAccountToken and discoveryAddress are crucial. The discoveryAddress is the public endpoint of cluster-a’s Kubernetes API server. The serviceAccountToken is a Service Account token from cluster-a that cluster-b will use to authenticate with cluster-a’s API server for discovery. You can get this token from cluster-a by creating a Service Account and then a Secret of type kubernetes.io/service-account-token for it.

The secretName: cacerts on cluster-b must contain the root CA certificate that cluster-a trusts (and that cluster-b will use to verify cluster-a’s control plane).

What’s Happening:

  1. Trust Establishment: Both clusters share the same root CA. This is the foundation for secure communication.
  2. Istiod Discovery: Istio’s control plane (istiod) in cluster-b uses the provided discoveryAddress and serviceAccountToken to connect to cluster-a’s Kubernetes API server. It watches for resources in cluster-a.
  3. Network Registration: The RemoteCluster resource tells cluster-b about cluster-a and assigns it to a logical network (e.g., "network1"). This allows Istio to differentiate traffic originating from different networks.
  4. East-West Gateway: The eastwest-gateway in cluster-a is configured to accept TLS traffic on port 15443. This gateway acts as the entry point for services from cluster-b into cluster-a.
  5. Service Exposure: When you deploy a service in cluster-a (e.g., myservice.default.svc.cluster.local), Istio on cluster-b discovers this service through the API server. It then configures the Envoy proxies in cluster-b to route traffic for myservice.default.svc.cluster.local to the eastwest-gateway in cluster-a. The istio-eastwestgateway will then route it to the actual service pod in cluster-a.

Common Pitfalls & Fixes:

  • Trust Domain Mismatch: If meshConfig.trustDomain differs between clusters, mTLS will fail. Ensure it’s identical.
    • Diagnosis: Check istio-proxy logs on any pod. Look for tls: bad certificate or permission denied during mTLS handshake.
    • Fix: Update the trustDomain in the IstioOperator configuration for affected clusters and re-install Istio or apply the MeshConfig changes.
  • Network Reachability: cluster-b’s istiod must be able to reach cluster-a’s Kubernetes API server (discoveryAddress). The eastwest-gateway in cluster-a must be reachable from cluster-b.
    • Diagnosis: Use kubectl exec into a pod in cluster-b and curl <cluster_a_api_server_address>:6443. From cluster-b, curl -v telnet://<cluster_a_eastwest_gateway_ip>:15443.
    • Fix: Ensure firewalls allow traffic, or configure Istio’s Network resources if using distinct networks. For the East-West Gateway, ensure its Service is of type LoadBalancer or NodePort, and that the IP is accessible.
  • Incorrect Service Account Token/API Server Address: The token used by cluster-b to authenticate to cluster-a must be valid and have sufficient permissions. The discoveryAddress must be the correct, publicly accessible API server endpoint.
    • Diagnosis: Check istiod logs on cluster-b for API authentication errors or connection refused messages.
    • Fix: Generate a new Service Account and token in cluster-a. Ensure the discoveryAddress is correct and accessible from cluster-b. Grant the Service Account in cluster-a appropriate RBAC permissions (e.g., cluster-admin or a more restricted role to view pods, services, endpoints).
  • Missing or Incorrect CA Certificates: The cacerts secret on both clusters (especially the remote cluster joining) must contain the correct root CA certificate.
    • Diagnosis: istio-proxy logs will show tls: bad certificate errors when attempting to connect to the remote cluster’s istiod or east-west gateway.
    • Fix: Create a Kubernetes Secret named cacerts in the istio-system namespace of the remote cluster containing ca-cert.pem (the root CA) and cert-chain.pem (if applicable, intermediate CAs). Ensure the istio-eastwestgateway on the primary cluster also has access to the CA secrets for its own identity.
  • East-West Gateway Configuration: The istio-eastwestgateway needs to be properly configured for SNI passthrough or TCP, and its Service exposed.
    • Diagnosis: Services in cluster-a are unreachable from cluster-b. Check the logs of the istio-eastwestgateway pod.
    • Fix: Ensure the Gateway resource for the east-west gateway is correctly applied, the selector matches the gateway deployment, and the port and protocol are set for TLS. The associated Kubernetes Service must expose the gateway.
  • Remote Cluster Network: If you have multiple logical networks, ensure the RemoteCluster resource correctly specifies the network field.
    • Diagnosis: Services can be reached, but performance is poor, or specific cross-network policies don’t work.
    • Fix: Define custom Network resources in Istio’s MeshConfig to map logical network names to CIDR ranges if needed, and ensure the RemoteCluster resource uses the correct logical network name.

After successfully connecting your clusters, the next hurdle you’ll likely encounter is managing traffic policies and ensuring consistent security configurations across them.

Want structured learning?

Take the full Istio course →