> For the complete documentation index, see [llms.txt](https://docs.subsalt.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.subsalt.io/product/subsalt-managed/cluster-requirements/example-using-envoy-gateway-for-ingress.md).

# Example: Using Envoy Gateway for ingress

### Envoy Gateway

If you don't already have a Gateway implementation in your cluster, we recommend using [Envoy's](https://gateway.envoyproxy.io/). It's straightforward to install and manage.

#### Install

**1. Create the Envoy Gateway namespace**

```bash
kubectl create namespace envoy-gateway-system
```

**2. Create the registry pull secret**

Envoy Gateway runs from Subsalt's hardened wrapper image in `subsaltprod.azurecr.io`. Create a pull secret in the Envoy Gateway namespace using the registry credentials Subsalt provided:

```bash
kubectl create secret docker-registry subsalt-registry-auth \
  --namespace envoy-gateway-system \
  --docker-server=subsaltprod.azurecr.io \
  --docker-username='<your-subsaltprod-username>' \
  --docker-password='<your-subsaltprod-password>'
```

**3. Install the Envoy Gateway control plane**

Install the upstream chart from its OCI registry, pinned to the version that matches your Subsalt release, and point the control-plane image at Subsalt's hardened image. Replace `<subsalt-version>` with the version tag of your Subsalt platform (the Envoy Gateway image is published under the same tag as the rest of your Subsalt images).

```bash
helm install envoy-gateway oci://docker.io/envoyproxy/gateway-helm \
  --version v1.8.2 \
  --namespace envoy-gateway-system \
  --set fullnameOverride=envoy-gateway \
  --set deployment.envoyGateway.image.repository=subsaltprod.azurecr.io/envoy-gateway \
  --set deployment.envoyGateway.image.tag=v1.0.0 \
  --set deployment.envoyGateway.imagePullSecrets[0].name=subsalt-registry-auth \
  --wait
```

**4. Create the GatewayClass**

The `GatewayClass` binds `Gateway`s to the Envoy Gateway controller. It is operator-managed (the analog of an `IngressClass`) and is not created by the chart.

```bash
kubectl apply -f - <<'EOF'
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: envoy-gateway
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
EOF
```

**5. Create the Gateway**

Create the Gateway in the **same namespace as the Subsalt services and TLS secrets** (`subsalt` here). Choose one option only. Both examples declare `subsalt-frontend-gateway`.

{% tabs %}
{% tab title="Public Gateway" %}
Use a public Gateway when the portal, authentication, and MCP hostnames resolve publicly. Replace each example hostname and secret name with your own values.

```bash
kubectl apply -f - <<'EOF'
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: subsalt-frontend-gateway
  namespace: subsalt
spec:
  gatewayClassName: envoy-gateway
  listeners:
    - name: portal-https
      protocol: HTTPS
      port: 443
      hostname: portal.example.com
      tls:
        mode: Terminate
        certificateRefs:
          - kind: Secret
            name: portal-tls
      allowedRoutes:
        namespaces:
          from: Same
    - name: auth-https
      protocol: HTTPS
      port: 443
      hostname: auth.example.com
      tls:
        mode: Terminate
        certificateRefs:
          - kind: Secret
            name: auth-tls
      allowedRoutes:
        namespaces:
          from: Same
    - name: mcp-https
      protocol: HTTPS
      port: 443
      hostname: mcp.example.com
      tls:
        mode: Terminate
        certificateRefs:
          - kind: Secret
            name: mcp-tls
      allowedRoutes:
        namespaces:
          from: Same
EOF
```

{% endtab %}

{% tab title="Private Gateway (Azure)" %}
Use a private Gateway when these hostnames must resolve to an RFC 1918 address within your VNet. It is reachable through your private network, such as VPN, ExpressRoute, a peered VNet, or a jump host.

```bash
kubectl apply -f - <<'EOF'
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: internal-frontend
  namespace: subsalt
spec:
  provider:
    type: Kubernetes
    kubernetes:
      envoyService:
        type: LoadBalancer
        annotations:
          service.beta.kubernetes.io/azure-load-balancer-internal: "true"
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: subsalt-frontend-gateway
  namespace: subsalt
spec:
  gatewayClassName: envoy-gateway
  infrastructure:
    parametersRef:
      group: gateway.envoyproxy.io
      kind: EnvoyProxy
      name: internal-frontend
  listeners:
    - name: portal-https
      protocol: HTTPS
      port: 443
      hostname: portal.example.com
      tls:
        mode: Terminate
        certificateRefs:
          - kind: Secret
            name: portal-tls
      allowedRoutes:
        namespaces:
          from: Same
    - name: auth-https
      protocol: HTTPS
      port: 443
      hostname: auth.example.com
      tls:
        mode: Terminate
        certificateRefs:
          - kind: Secret
            name: auth-tls
      allowedRoutes:
        namespaces:
          from: Same
    - name: mcp-https
      protocol: HTTPS
      port: 443
      hostname: mcp.example.com
      tls:
        mode: Terminate
        certificateRefs:
          - kind: Secret
            name: mcp-tls
      allowedRoutes:
        namespaces:
          from: Same
EOF
```

The `EnvoyProxy` configuration applies to this Gateway only. Azure provisions one internal load balancer for Envoy. The listeners share port `443` and route by hostname.
{% endtab %}
{% endtabs %}

**6. Create the HTTPRoutes**

These routes send the three frontend hostnames to their Subsalt services. Use the same hostnames configured in the Gateway.

```bash
kubectl apply -f - <<'EOF'
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: subsalt-portal
  namespace: subsalt
spec:
  parentRefs:
    - name: subsalt-frontend-gateway
      sectionName: portal-https
  hostnames:
    - portal.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: subsalt-portal-http
          port: 80
      # Extended timeout for long-running query operations.
      timeouts:
        request: "3600s"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: subsalt-auth
  namespace: subsalt
spec:
  parentRefs:
    - name: subsalt-frontend-gateway
      sectionName: auth-https
  hostnames:
    - auth.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: subsalt-keycloak
          port: 80
      timeouts:
        request: "3600s"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: subsalt-mcp
  namespace: subsalt
spec:
  parentRefs:
    - name: subsalt-frontend-gateway
      sectionName: mcp-https
  hostnames:
    - mcp.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: subsalt-mcp-server
          port: 80
      timeouts:
        request: "3600s"
EOF
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.subsalt.io/product/subsalt-managed/cluster-requirements/example-using-envoy-gateway-for-ingress.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
