Istio Addon
The Istio Addon ships the platform-curated Istio service mesh, packaged as the p6m-istio-gateway-api wrapper Helm chart. It runs Istio in ambient mode (no sidecars), bundles the Kubernetes Gateway API CRDs that istiod is built against, and wires some of the platform Gateways to oauth2-proxy for external authorization.
For background on what an Installable / Installation actually does at the platform layer, see Installation. For how traffic moves through the mesh once it's running, see Istio Ambient Mode Architecture.
What Lands on the Cluster
When the addon is enabled, ArgoCD reconciles a Helm release that produces:
| Resource | Purpose |
|---|---|
| Gateway API CRDs | GatewayClass, Gateway, HTTPRoute, GRPCRoute, ReferenceGrant, BackendTLSPolicy from the Gateway API v1.4.1 standard channel. |
istio/base | The Istio CRDs and cluster-wide resources. |
istiod | The control plane, with the ambient profile and a minimum of 2 replicas (autoscaleMin: 2). |
istio-cni DaemonSet | Redirects pod traffic into the mesh on every node. Ambient mode is on. |
ztunnel DaemonSet | The per-node layer-4 proxy that carries mTLS traffic between ambient workloads. |
AuthorizationPolicy istio-system/ext-authz | Sends requests for *.<cluster domain> through the oauth2-proxy extension provider. Targets the ingress-gateway, public-oidc, and internal-oidc Gateways. Always rendered. |
Telemetry opentelemetry | Only when observability.tracing.enabled: true. Samples 5% of requests to the otel-tracing provider. |
| Prometheus | Only when observability.prometheus.enabled: true. Deployment + Service in istio-system. |
| Kiali | Only when observability.kiali.enabled: true. Deployment + Service in istio-system. |
The chart doesn't create any Gateway resources. The ingress-gateway, public-oidc, and internal-oidc Gateways that the AuthorizationPolicy targets are managed by the platform-operator.
The ext-authz policy targets those three Gateways by name. A Gateway you create yourself isn't covered, so requests through it skip oauth2-proxy. To put a custom Gateway behind oauth2-proxy, add your own AuthorizationPolicy in the Gateway's namespace that uses the oauth2-proxy extension provider:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: <your-gateway-name>-ext-authz
namespace: <gateway-namespace>
spec:
action: CUSTOM
provider:
name: oauth2-proxy
rules:
- to:
- operation:
hosts:
- "<your-host>"
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: <your-gateway-name>
Each targetRefs entry must name a Gateway in the policy's own namespace. Don't name the policy ext-authz: in istio-system it would replace the chart's policy and drop oauth2-proxy from the platform Gateways.
Extension providers
istiod's meshConfig registers two extension providers that other resources reference by name:
| Provider | Type | Backend |
|---|---|---|
oauth2-proxy | envoyExtAuthzHttp | oauth2-proxy.oauth2-proxy.svc.cluster.local:80 |
otel-tracing | opentelemetry | alloy.alloy.svc.cluster.local:4317 |
On an allowed request, oauth2-proxy forwards path, x-auth-request-email, and x-auth-request-preferred-username to the upstream service. Your app can read the signed-in user from those headers.
Add the Installation
Cluster enablement happens in the org's .platform repo. Create installations/istio-gateway-api.yaml:
apiVersion: p6m.dev/v1alpha1
kind: Installation
metadata:
name: istio-gateway-api
spec:
cd:
enabled: true
autoPromote: true
installableRef:
kind: Installable
name: istio-gateway-api
namespace: installables
destinations:
- clusterRef:
name: <your-cluster-name>
Push and merge.
The release installs into the istio-system namespace. Chart defaults apply, so the Installation needs no overrides unless you turn on observability. To change a setting, add overrides.source.template to the destination with the keys from the Settings Reference below:
destinations:
- clusterRef:
name: <your-cluster-name>
overrides:
source:
template: |
observability:
tracing:
enabled: true
To enable on multiple clusters in the same org, add additional destinations[].clusterRef.name entries. Each destination can have its own overrides.
Set from cluster context
The Installable fills these from the cluster's context — you don't set them on the Installation:
p6m.cluster.domainName, from the cluster's DNS domain. Theext-authzpolicy builds its*.<domainName>host match from it.- The cloud, environment name, cluster unique name, and cloud-specific identity details (AWS region and account, or Azure location and subscription).
- On Azure, istiod is pinned to the AKS system node pool (
kubernetes.azure.com/mode: system) and tolerates theCriticalAddonsOnlytaint.
Settings Reference
The chart exposes its own observability block. Everything else is passed through to the upstream Istio subcharts under their subchart key (istiod, cni, ztunnel, base).
The "Override snippet" column shows the minimal values needed to change a setting. Paste it under template: | in the Installation above.
observability
All three are off by default.
| Setting | Override snippet | Notes |
|---|---|---|
prometheus.enabled (bool)default: false | | In-cluster Prometheus at prometheus.istio-system:9090. Stores data in an emptyDir with 15-day retention, so metrics are lost when the pod restarts. |
kiali.enabled (bool)default: false | | Kiali mesh console at kiali.istio-system:20001, path /kiali. Kiali reads mesh metrics from Prometheus, so enable both. |
tracing.enabled (bool)default: false | | Renders a mesh-wide Telemetry that samples 5% of requests to Alloy over OTLP. Requires Alloy in the alloy namespace. |
Upstream subchart values
The wrapper sets these on the Istio subcharts:
| Setting | Value | Why |
|---|---|---|
istiod.profile | ambient | Ambient mesh, no sidecar injection. |
istiod.autoscaleMin | 2 | Keeps the control plane available through node drains. |
istiod.meshConfig.extensionProviders | otel-tracing, oauth2-proxy | See Extension providers. |
cni.ambient.enabled | true | Required for ambient mode. |
cni.affinity, ztunnel.affinity | Not on eks.amazonaws.com/compute-type: fargate | Fargate nodes can't run node-level DaemonSets. |
*.global.hub | p6m.jfrog.io/p6m-dev-docker-remote/istio | Pull through the platform's Artifactory mirror. |
For any other subchart setting, see the upstream chart values for istiod, cni, and ztunnel. If you need one changed, mention it on the rollout ticket so the chart can be extended; don't edit the rendered resources directly on the cluster.
Upgrading
Istio's components have strict version compatibility, so the wrapper chart ships a minor upgrade as two releases so that you can manage the upgrade properly.
Process
Scenario:
To go from addon version a.b.c to a.b+1.d:
- Perform any manual patches and updates to the CRDs and their resources as needed.
- Upgrade the addon to
a.b+1.0. This will upgrade all CRDs and the istiod component to the desired version. - istiod and all Gateway pods will be restarted as part of the previous step. Pause upgrades until they are stable.
- Upgrade the addon to
a.b+1.d. This will upgrade CNI and Ztunnel and could result in an outage of a few seconds to a few minutes depending on the number of nodes you have on your cluster.
The version of the addon is usually not the same as the version of istio that will be installed. See the appropriate upgrade runbook for specifics on which exact version of each component is being installed.
Runbooks for specific versions: COMING SOON
- istiod upgrades restart every Gateway. A Gateway with a single replica goes down during the restart. Run 2 or more replicas on every Gateway before taking an
a.b+1.0release. - CNI and ztunnel upgrades cause a short outage. Both are
DaemonSets, so every node restarts a pod. Schedule thea.b+1.drelease in an upgrade window.
Verification
After ArgoCD syncs, expect the following on the target cluster:
# Control plane: at least 2 Running pods
kubectl --context=<your-cluster> -n istio-system get pods -l app=istiod
# Data plane: one pod per non-Fargate node for each DaemonSet
kubectl --context=<your-cluster> -n istio-system get daemonset istio-cni-node ztunnel
# Gateway API CRDs at the bundled version
kubectl --context=<your-cluster> get crd gateways.gateway.networking.k8s.io \
-o jsonpath='{.metadata.annotations.gateway\.networking\.k8s\.io/bundle-version}'
# ext-authz policy
kubectl --context=<your-cluster> -n istio-system get authorizationpolicy ext-authz
For symptoms and diagnostics once the mesh is running, see Istio Issues.
Gotchas
- ext-authz depends on oauth2-proxy. The
ext-authzpolicy callsoauth2-proxy.oauth2-proxy.svc.cluster.local:80. If oauth2-proxy is missing or unhealthy, requests through the targeted Gateways fail authorization. - ext-authz only matches
*.<cluster domain>. Requests to a host outside the cluster'sdomainName, such as a custom hostname, don't match this policy's rule. - Tracing needs Alloy.
observability.tracing.enabled: truesends spans toalloy.alloy.svc.cluster.local:4317. Without Alloy in thealloynamespace, spans are dropped. - The bundled Prometheus is not durable. It stores data in an
emptyDir, so a pod restart loses all metrics. Use it for short-term mesh debugging, not as the cluster's metrics store. - Kiali uses anonymous auth. Anyone who can reach the
kialiService can use the console. The chart creates no ingress for it; reach it withkubectl port-forward. - Fargate nodes aren't in the mesh. CNI and ztunnel don't schedule on EKS Fargate, so pods on Fargate nodes run outside ambient mode.