Chapter 3. Configuring Gateway API


3.1. Understanding Gateway API

To optimize network traffic management and implement routing policies in OpenShift Container Platform, use Gateway API. By adopting this community-managed Kubernetes mechanism, you can configure advanced routing at both the transport (L4) and application (L7) layers while leveraging various vendor-supported implementations to meet your specific networking requirements.

A well-designed Gateway API deployment helps you achieve a portable, role-oriented routing infrastructure. To successfully plan your Gateway API implementation, review the following concepts:

  • Understand the benefits and limitations of Gateway API.
  • Review OpenShift Container Platform implementation specifics to avoid unsupported features.
  • Choose between shared or dedicated deployment topologies.
Important

Gateway API does not support user-defined networks (UDN).

3.1.1. Gateway API benefits and limitations

Review the benefits and limitations of Gateway API to determine if it suits your cluster. The portable API and standardized ecosystem offer broad community support, ensuring that your networking aligns with your technical and organizational needs.

3.1.1.1. Benefits

Gateway API provides the following benefits:

  • Portability: Where OpenShift Container Platform uses HAProxy to improve Ingress performance, Gateway API does not rely on vendor-specific annotations to provide certain behavior. To get comparable performance to HAProxy, the Gateway objects need to be horizontally scaled or their associated nodes need to be vertically scaled.
  • Separation of concerns: Gateway API uses a role-based approach to its resources, and more neatly fits into how a large organization structures its responsibilities and teams. Platform engineers might focus on GatewayClass resources, cluster administrators might focus on configuring Gateway resources, and application developers might focus on routing their services with HTTPRoute resources.
  • Extensibility: Additional functionality is developed as a standardized CRD.

3.1.1.2. Limitations

Gateway API has the following limitations:

  • Version incompatibilities: Gateway API ecosystem changes rapidly, and some implementations do not work with others because their featureset is based on differing versions of Gateway API.
  • Resource overhead: While more flexible, Gateway API uses multiple resource types to achieve an outcome. For smaller applications, the simplicity of traditional Ingress might be a better fit.
  • On-premise infrastructure dependencies: On-premise deployments, such as bare metal or VMware vSphere environments, do not automatically provision network load balancers or manage external DNS records. To use Gateway API on an on-premise platform, you must explicitly deploy a load balancer controller, such as MetalLB, and manually map your DNS records to the provisioned gateway address.

3.1.2. Gateway API implementation specifics

To ensure interoperability between external vendor implementations and your networking infrastructure in OpenShift Container Platform, the Ingress Operator manages the lifecycle of Gateway API custom resource definitions (CRDs).

Understanding how these CRDs are managed helps you prevent disrupted workloads and security issues caused by incompatible vendor fields.

In some situations, Gateway API provides one or more fields that a vendor implementation does not support, but that implementation is otherwise compatible in schema with the rest of the fields. These "dead fields" can result in disrupted Ingress workloads, improperly provisioned applications and services, and security-related issues. Because OpenShift Container Platform uses a specific version of Gateway API CRDs, any use of third-party implementations of Gateway API must conform to the OpenShift Container Platform implementation to ensure that all fields work as expected.

Any CRDs created within an OpenShift Container Platform 4.22 cluster are compatibly versioned and maintained by the Ingress Operator. If CRDs are already present but were not previously managed by the Ingress Operator, the Ingress Operator checks whether these configurations are compatible with Gateway API version supported by OpenShift Container Platform, and creates an admin-gate that requires your acknowledgment of CRD succession.

Important

If you are updating your cluster from a previous OpenShift Container Platform version that contains Gateway API CRDs, change those resources so that they exactly match the version supported by OpenShift Container Platform. Otherwise, you cannot update your cluster because those CRDs were not managed by OpenShift Container Platform, and could contain functionality that is unsupported by Red Hat.

In previous versions of OpenShift Container Platform, cluster security policies blocked the deployment of the gateway.networking.x-k8s.io Gateway API CRD. Starting in OpenShift Container Platform 4.22, this restriction is removed, and you can deploy that CRD.

Note

Experimental Gateway API CRDs in the gateway.networking.k8s.io group remain restricted.

You can install the gateway.networking.x-k8s.io CRD and related objects on the cluster because they are no longer blocked. The built-in Gateway API implementation managed by the Ingress Operator does not reconcile those objects in OpenShift Container Platform. Use a compatible third-party Gateway implementation if you need those APIs reconciled.

3.1.3. Gateway API deployment topologies

Select an appropriate cluster deployment topology to organize and secure your routing infrastructure. Gateway API accommodates shared gateways or dedicated gateways. Choose a topology based on its distinct advantages and security implications.

3.1.3.1. Dedicated gateway

Routes and any load balancers or proxies are served from the same namespace. The Gateway object restricts routes to a particular application namespace. This is the default topology when deploying a Gateway API resource in OpenShift Container Platform.

The following example shows a dedicated Gateway resource, fin-gateway:

Example dedicated Gateway resource

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: fin-gateway
  namespace: openshift-ingress
spec:
  gatewayClassName: openshift-default
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    hostname: "*.example.com"

If you do not set spec.listeners[].allowedRoutes for a Gateway resource, the system implicitly sets the namespaces.from field to the value of Same.

The following example shows the associated HTTPRoute resource, sales-db, which attaches to the dedicated Gateway object:

Example HTTPRoute resource

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: sales-db
  namespace: openshift-ingress
spec:
  parentRefs:
  - name: fin-gateway
  hostnames:
  - sales-db.example.com
  rules:
    - backendRefs:
        - name: sales-db
          port: 8080

The HTTPRoute resource must have the name of the Gateway object as the value for its parentRefs field to attach to the gateway. The system implicitly assumes that the route exists in the same namespace as the Gateway object.

3.1.3.2. Shared gateway

Routes are served from multiple namespaces or multiple hostnames. The Gateway object allows routes from application namespaces by using the spec.listeners.allowedRoutes.namespaces field.

The following example shows a Gateway resource, devops-gateway, that has a spec.listeners.allowedRoutes.namespaces label selector set to match any namespaces containing shared-gateway-access: "true":

Example shared Gateway resource

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: devops-gateway
  namespace: openshift-ingress
spec:
  gatewayClassName: openshift-default
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    hostname: "*.example.com"
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            shared-gateway-access: "true"

The following examples show the allowed namespaces for the devops-gateway resource:

Example Namespace resources

apiVersion: v1
kind: Namespace
metadata:
  name: dev
  labels:
    shared-gateway-access: "true"
---
apiVersion: v1
kind: Namespace
metadata:
  name: ops
  labels:
    shared-gateway-access: "true"

In this example, two HTTPRoute resources, dev-portal and ops-home, are in different namespaces but are attached to the shared gateway:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: dev-portal
  namespace: dev
spec:
  parentRefs:
  - name: devops-gateway
    namespace: openshift-ingress
  rules:
  - backendRefs:
    - name: dev-portal
      port: 8080
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: ops-home
  namespace: ops
spec:
  parentRefs:
  - name: devops-gateway
    namespace: openshift-ingress
  rules:
  - backendRefs:
    - name: ops-home
      port: 8080

With a shared gateway topology, the routes must specify the namespace of the Gateway object it wants to attach to. Multiple Gateway objects can be deployed and shared across namespaces. When there are multiple shared gateways, this topology becomes conceptually similar to Ingress Controller sharding.

3.2. Enabling Gateway API

To route traffic using Gateway API, you must first enable the feature on your cluster. You can enable Gateway API by creating a GatewayClass custom resource, which triggers the Ingress Operator to provision the necessary controller and components.

After you successfully enable Gateway API, you can begin deploying gateways, assigning network addresses, and configuring listeners to control your network traffic flow.

To configure Gateway API for use on your cluster, you must create a GatewayClass resource. During the creation of the GatewayClass resource, the Ingress Operator installs a lightweight Istio control plane, based on Red Hat OpenShift Service Mesh, in the openshift-ingress namespace.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).

Procedure

  1. Create a GatewayClass object:

    1. Create a YAML file, openshift-default.yaml, that contains the following information:

      Example GatewayClass CR

      apiVersion: gateway.networking.k8s.io/v1
      kind: GatewayClass
      metadata:
        name: openshift-default
      spec:
        controllerName: openshift.io/gateway-controller/v1

      • metadata.name: The name of your GatewayClass object. The name must consist of a maximum of 63 lowercase alphanumeric characters or hyphens (-). The name must also start and end with an alphanumeric character.

        Important

        The controllerName value must be exactly as shown for the Ingress Operator to manage it. If you set this field to anything else, the Ingress Operator ignores the GatewayClass object and all associated Gateway, GRPCRoute, and HTTPRoute objects. The controller name is tied to the implementation of Gateway API in OpenShift Container Platform, and openshift.io/gateway-controller/v1 is the only controller name allowed.

    2. Run the following command to create the GatewayClass resource:

      $ oc create -f openshift-default.yaml

      Example output

      gatewayclass.gateway.networking.k8s.io/openshift-default created

Verification

  • Verify that the GatewayClass CR has been accepted and the controller is successfully installed by running the following command:

    $ oc get gatewayclass openshift-default -o yaml

    Example output

    # ...
    status:
      conditions:
      - lastTransitionTime: "2026-05-15T10:00:00Z"
        message: The GatewayClass has been accepted
        reason: Accepted
        status: "True"
        type: Accepted
      - lastTransitionTime: "2026-05-15T10:00:00Z"
        message: Istio installed successfully
        reason: Installed
        status: "True"
        type: ControllerInstalled
      - lastTransitionTime: "2026-05-15T10:00:00Z"
        message: Istio CRDs are being managed by cluster-ingress-operator
        reason: ManagedByCIO
        status: "True"
        type: CRDsReady
    # ...

    Inspect the status.conditions block in the output. A healthy GatewayClass CR reports a status of True for the Accepted, ControllerInstalled, and CRDsReady conditions.

To control network traffic flow, you can configure Gateway API listeners to define the designated port, protocol, and hostname for your gateway. By configuring listeners, you can specify secure TLS connections, dictate how traffic is terminated, and restrict which application routes are permitted to attach to the gateway.

To ensure that your applications receive only authenticated and authorized traffic, you must specify the allowed protocols and ports for your gateway.

If you are routing secure traffic, you must also configure TLS settings. You can define these parameters by configuring the spec.listeners field in your Gateway custom resource (CR).

Important

If your gateway is accessible from other namespaces, always configure the spec.listeners[].allowedRoutes[].namespaces.selector field with a selector for the permitted namespaces. By specifying a namespace selector, you prevent possible misuse or hijacking of the gateway from other namespaces.

If nothing is listed in the spec.listeners[].allowedRoutes[] field, the gateway is accessible only from the same namespace.

Procedure

  1. Create or edit a Gateway YAML file to include your listener configuration.

    The following example demonstrates a Gateway CR with two listeners, one for HTTP and one for HTTPS. For detailed descriptions of the listener fields, see "Gateway listener configuration reference".

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: <example_gateway>
      namespace: openshift-ingress
    spec:
      gatewayClassName: openshift-default
      listeners:
      - protocol: HTTP
        port: 80
        name: http
        hostname: "*.<example_domain.tld>"
        allowedRoutes:
          namespaces:
            from: Selector
            selector:
              matchLabels:
                env: "dev"
      - protocol: HTTPS
        port: 443
        name: https
        hostname: "*.<example_domain.tld>"
        tls:
          mode: Terminate
          certificateRefs:
            - name: <listener_cert>
              kind: Secret
        allowedRoutes:
          namespaces:
            from: Selector
            selector:
              matchLabels:
                env: "dev"

    With this configuration, only HTTPRoute resources in namespaces that have the env: "dev" label can attach to these listeners.

  2. Apply the Gateway CR by running the following command:

    $ oc apply -f <gateway_cr>.yaml

3.3.1.1. Gateway listener configuration reference

When configuring the spec.listeners field in your Gateway custom resource (CR), you can define network protocols, ports, hostnames, TLS termination, and route attachment policies.

You can customize your gateway listener configuration using the following fields:

spec.listeners
Defines the list of listeners for the gateway. You can customize this field with settings for port, protocol, TLS, hostnames, and allowed routes.
listeners.protocol and listeners.port
Defines the network port and protocol. For example, protocol: HTTP accepts HTTP traffic on port 80, and protocol: HTTPS accepts HTTPS traffic on port 443.
listeners.hostname
Defines the hostnames that the listener matches for incoming requests. For example, it can match only requests for hostnames ending in <example_domain.tld> (such as www.<example_domain.tld>). Always set a hostname on each listener, unless you are defining a catch-all route. If no hostname is specified, any route that can attach to the listener can claim arbitrary hostnames.
listeners.tls
Specifies the TLS settings for secure communication, including the mode (currently, only Terminate is supported on OpenShift Container Platform) and the Kubernetes secret containing the certificate keypair. For example, TLS is terminated at the gateway using a certificate stored in a Kubernetes Secret called <listener_cert>. You must ensure that the specified Kubernetes secret exists before you create the Gateway CR.
listeners.allowedRoutes
Controls which route resources can attach to this listener. If you omit this field, or set namespaces.from: Same, only routes in the same namespace as the Gateway can attach. To allow routes from other namespaces, set namespaces.from: Selector and a label selector for trusted namespaces. For example, an HTTP listener might allow HTTPRoute resources only from namespaces that have the env: "dev" label. Do not set namespaces.from: All; that setting allows routes from every namespace and can enable hostname or domain hijacking.

3.3.2. Understanding listener routing conflicts

When you configure a Gateway custom resource (CR) with multiple listeners, you must establish clear rules for overlapping hostnames and ports to ensure your traffic does not get misrouted. To avoid ambiguity, Gateway API uses specific conflict management rules.

If your listener configurations violate these rules, the affected listener receives a Conflicted status condition and cannot route traffic correctly.

To resolve or prevent routing conflicts, ensure that your listeners adhere to the following rules:

  • Distinct ports: A gateway can have distinct listeners that use the exact same hostname, provided their network ports are distinct.
  • Distinct hostnames: A gateway can have distinct listeners that use the exact same protocol and port, provided their hostnames are different.
  • Specificity precedence: If one listener uses a wildcard domain (for example, *.<example_domain.tld>) and another listener uses a more specific endpoint for that exact same domain (for example, <www.example_domain.tld>), the more specific entry takes precedence.

    This specificity rule also applies to multiple wildcard domains. For example, *.<example_domain.tld> takes precedence over *.<tld>. This ensures that traffic intended for a specific subdomain is accurately routed to its dedicated listener, even if a broader wildcard listener exists.

    Note

    In Gateway API, wildcards match one or more complete DNS labels. For example, *.<example.com> matches <www.example.com> and <sub.domain.example.com>, but does not match the root domain <example.com>.

When a listener is not routing traffic as expected, you can review its status conditions to quickly diagnose and fix the configuration error. The listener status condition gives insight into its current state and any underlying issues preventing it from accepting traffic.

Procedure

  1. Check the status conditions of your Gateway custom resource (CR) by running the following command:

    $ oc describe gateway <gateway_cr> -n <namespace>

When you troubleshoot your gateway listeners, you can review the status conditions in the Gateway custom resource (CR) output to identify configuration errors or conflicts.

The following table describes common listener conditions and how to resolve them:

Table 3.1. Gateway listener status conditions
ConditionDescription

Ready

Indicates that the listener is configured correctly and is actively listening for traffic.

Conflicted

Signifies an ambiguity or conflict in the listener’s configuration with another listener on the same gateway. If a listener is conflicted, review your listener configurations against the conflict management rules to identify and resolve the ambiguity.

Programmed

Denotes that the underlying infrastructure, such as a load balancer or proxy, has successfully been programmed with the listener’s configuration.

Accepted

Indicates that the gateway has accepted the listener’s configuration. This is usually an early step in the listener’s lifecycle.

Invalid

Means the listener’s configuration itself contains errors or is malformed, preventing it from being processed. An invalid status indicates errors in your YAML configuration. Check your configuration for typos, incorrect syntax, or missing required fields.

3.4. Assigning network addresses to gateways

You can configure network addresses for your gateway to provide a predictable entry point for external and internal traffic. This ensures that clients can reliably resolve and route requests to your load balancers.

Gateway API uses addresses to define the specific network locations that are assigned to your Gateway resource. In OpenShift Container Platform, you rely on the gateway controller to automatically provision and bind the necessary network addresses, such as an external or internal load balancer IP, to your gateway. On on-premise environments, this automatic provisioning requires a configured load balancer controller.

To successfully assign network addresses to your gateway, complete the following tasks:

  • Understand gateway address assignment and types to plan your DNS and load balancer configuration.
  • Understand on-premise gateway routing requirements to ensure your infrastructure can support Gateway API.
  • Configure automatic address assignment for a gateway to successfully deploy it without violating manual address constraints.
  • Configure an internal load balancer to restrict your gateway traffic to your private network.
  • Review cloud provider annotations to ensure your internal load balancer provisions correctly on your specific infrastructure.

OpenShift Container Platform automatically handles address assignment by provisioning a LoadBalancer service when you create a Gateway resource. The network address assigned to your gateway corresponds to the IP address or hostname of this underlying load balancer.

Important

Do not define the spec.addresses field. Manually requesting specific network addresses is not currently supported in OpenShift Container Platform. If you attempt to request a specific address manually, the gateway enters an error state.

The status.addresses field is populated automatically by the gateway controller. This field lists the actual, active network address assigned to your gateway by the load balancing infrastructure.

When the controller dynamically assigns an address to your gateway and populates the status.addresses field, it uses one of the following primary types to reflect the underlying load balancer:

Hostname
Represents a DNS-based ingress point. This concept is typically used for cloud load balancers where a DNS name exposes the load balancer.
IPAddress
A textual representation of a numeric IP address (IPv4 or IPv6) assigned by the load balancing infrastructure.

3.4.2. On-premise gateway routing requirements

Understand the specific routing and load balancing requirements for on-premise Gateway API deployments to ensure your gateway functions correctly.

Unlike cloud environments where load balancers are dynamically provisioned, on-premise clusters require a preconfigured load balancer controller. Red Hat tests and certifies Gateway API on on-premise platforms specifically with MetalLB.

Warning

If you attempt to use Gateway API on an on-premise cluster without a functional load balancer controller, the gateway service will remain in a "pending" state indefinitely.

Additionally, be aware of the following topology and load balancer limitations for on-premise environments:

  • Third-party load balancers: Red Hat does not currently test Gateway API with third-party load balancers such as F5 or Avi Kubernetes Operator (AKO). If you use an untested load balancer, the cluster administrator is responsible for ensuring it is configured and working properly.
  • Unsupported topologies: Environments without a load balancer controller are not supported. For example, you cannot use annotations to enforce a NodePort service type in place of a load balancer.

When you create a gateway resource, you must configure it for automatic address provisioning to successfully deploy the gateway without violating OpenShift Container Platform manual address constraints.

By intentionally omitting the addresses field, you allow the controller to seamlessly provision and bind the necessary external network addresses to your gateway.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • You have an existing GatewayClass custom resource, such as openshift-default.

Procedure

  1. Create a YAML file, such as hello-gateway.yaml, that defines your Gateway object.

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: sample-gateway
      namespace: openshift-ingress
    spec:
      gatewayClassName: openshift-default
      listeners:
      - name: http
        hostname: "*.gwapi.<cluster_domain>"
        port: 80
        protocol: HTTP
        allowedRoutes:
          namespaces:
            from: Selector
            selector:
              matchLabels:
                shared-gateway-access: "true"
    • metadata.name: Specify the name of your Gateway object. The name must consist of a maximum of 63 lowercase alphanumeric characters or hyphens (-). The name must also start and end with an alphanumeric character.
    • spec.gatewayClassName: Specify the GatewayClass object whose controller provisions the address and populates the status.addresses field.
    • spec.listeners[].hostname: Specify the listener hostname. Replace <cluster_domain> with your actual cluster ingress domain (for example, example.com). Setting a hostname limits which route hostnames can match this listener.
    • spec.listeners[].allowedRoutes.namespaces: Allow route attachment only from namespaces that have the shared-gateway-access: "true" label.
  2. Apply the Gateway configuration by running the following command:

    $ oc apply -f hello-gateway.yaml
  3. Verify that the controller automatically assigned an address to your gateway by running the following command:

    $ oc -n openshift-ingress get gateway sample-gateway

    Example output

    NAME             CLASS               ADDRESS             PROGRAMMED   AGE
    sample-gateway   openshift-default   <gateway_address>   True         6m16s

    The ADDRESS column in the output displays the dynamically provisioned network address for your gateway.

By default, Gateway API provisions an external load balancer. To restrict your gateway traffic to your private network, you can configure Gateway API to provision an internal load balancer by adding a cloud-specific annotation to your Gateway custom resource (CR).

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • You have configured a GatewayClass object.

Procedure

  1. Create or edit your Gateway CR to include the cloud-specific annotation under spec.infrastructure.annotations.

    The following example provisions an internal load balancer for an AWS cluster:

    Example Gateway CR for an AWS internal load balancer

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: mygateway
      namespace: openshift-ingress
    spec:
      gatewayClassName: openshift-default
      infrastructure:
        annotations:
        # Specifies the cloud provider annotation and value required to provision an internal load balancer:
          service.beta.kubernetes.io/aws-load-balancer-internal: "true"
      listeners:
      - name: https
        hostname: "*.example.com"
        port: 443
        protocol: HTTPS
        tls:
          mode: Terminate
          certificateRefs:
          - name: gateway-tls-secret
    # ...

  2. Apply the updated Gateway CR by running the following command:

    $ oc apply -f <gateway_filename>.yaml

Verification

  • Verify that the load balancer service is provisioned and has an internal IP address by running the following command:

    $ oc -n openshift-ingress get svc

To provision an internal load balancer for clusters deployed in private environments, you must add specific annotations to the spec.infrastructure.annotations field of your Gateway custom resource (CR).

This configuration is supported on Amazon Web Services (AWS), Microsoft Azure, Google Cloud, Red Hat OpenStack Platform (RHOSP), and IBM Cloud. The following table details the required cloud-specific annotations and their corresponding values.

Table 3.2. Internal load balancer annotations by cloud provider
Cloud ProviderAnnotationValue

AWS

service.beta.kubernetes.io/aws-load-balancer-internal

"true"

Azure

service.beta.kubernetes.io/azure-load-balancer-internal

"true"

Google Cloud

cloud.google.com/load-balancer-type

"Internal"

RHOSP

service.beta.kubernetes.io/openstack-internal-load-balancer

"true"

IBM Cloud/ IBM Power Virtual Server

service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type

"private"

3.5. Configure DNS for gateways

Configure automatic or manual DNS record management for Gateway API resources to provide predictable network addresses for incoming traffic.

3.5.1. DNS management requirements for Gateway API

The Ingress Operator manages DNS records for Gateway API resources when deployed in the openshift-ingress namespace. This automatic management applies only when specific namespace and domain conditions are met.

The Ingress Operator creates DNS records from hostnames specified in spec.listeners[*].hostname on the Gateway resource. The Operator does not create DNS records from hostnames specified only on route resources. Listeners without a hostname do not receive an automatically managed DNS record.

To enable automatic DNS record creation and lifecycle management for Gateway API resources, ensure you meet the following criteria:

  • You ensured that the cluster DNS configuration defines at least one managed public or private DNS zone.
  • You created the Gateway custom resource (CR) in the openshift-ingress namespace.
  • You ensured that the listener hostnames must fall under the cluster base domain. To inspect the base domain of your cluster, enter the following command:

    $ oc get dns.config.openshift.io cluster -o jsonpath='{.spec.baseDomain}'
  • You ensured that another Gateway does not use the listener hostname; otherwise, the Gateway reports DNSReady=False and does not publish a DNS record.

If you create the Gateway object in any other namespace, note the following limitations:

  • The Ingress Operator does not provision or manage DNS records for the Gateway.
  • You must manually configure and manage DNS records for all hostnames associated with that Gateway.

3.5.2. Automatic DNS management

When you deploy a Gateway object in the openshift-ingress namespace to use automatic DNS management, you must configure listener route attachment rules to support multi-namespace deployments.

Note

Setting the spec.listeners[*].allowedRoutes.namespaces.from field to Same on a Gateway in the openshift-ingress namespace restricts route attachment to that namespace. If you do not set that field, the Gateway defaults to this same behavior and only accepts route attachments from its own namespace. If you deploy HTTPRoute, GRPCRoute or TLSRoute objects in user namespaces, you cannot attach routes to the Gateway.

The following example creates a Gateway in the openshift-ingress namespace with a listener hostname under the cluster base domain, enabling automatic DNS management. The example also sets the allowedRoutes.namespaces.from field to Selector to allow route attachment from labeled application namespaces.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: managed-dns-gateway
  namespace: openshift-ingress
spec:
  gatewayClassName: openshift-gateway-manager
  listeners:
  - name: https
    hostname: "*.gwapi.<domain>"
    port: 443
    protocol: HTTPS
    tls:
      mode: Terminate
      certificateRefs:
      - name: gwapi-wildcard
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            gateway-access: "true"

where:

metadata.namespace
Deploying in openshift-ingress enables automatic DNS record management by the Ingress Operator.
spec.listeners.hostname

Replace <domain> with your cluster base domain. You can run the following command to get your domain name:

$ oc get dns.config.openshift.io cluster -o jsonpath='{.spec.baseDomain}'
spec.listeners.allowedRoutes.namespaces.from
Configured to Selector (or All) so route resources in designated application namespaces can attach. Same is not supported for cross-namespace application routes.

When you deploy a Gateway in the openshift-ingress namespace, the Ingress Operator automatically provisions DNS records for each listener hostname. You can verify that DNS is configured correctly by checking the DNSReady condition on the Gateway resource:

$ oc -n openshift-ingress get gateway managed-dns-gateway -o jsonpath='{.status.conditions[?(@.type=="DNSReady")]}' | jq

Example output

{
  "lastTransitionTime": "2025-01-15T12:00:00Z",
  "message": "All the listeners have DNS ready",
  "reason": "AllListenersReady",
  "status": "True",
  "type": "DNSReady"
}

If DNSReady is False, inspect the listener-level conditions for specific failure reasons. For more information, see "Verifying Gateway infrastructure status".

3.5.3. Configuring DNS for on-premise gateways

Configure DNS records manually on on-premise environments to ensure clients can reliably resolve your gateway.

Although the Ingress Operator automatically creates a DNSRecord custom resource (CR) using the hostname from the listener, this record is marked as "unmanaged" on on-premise platforms because the cluster Ingress Operator does not implement on-premise DNS providers. You must manually configure DNS records to point to the IP address of your load balancer.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • You have configured a load balancer controller, such as MetalLB, for your cluster.
  • Your gateway has been assigned an external network address by the load balancer.
  • Your gateway is located in the openshift-ingress namespace.

Procedure

  1. Retrieve the external IP address assigned to your gateway by the load balancer by running the following command:

    $ oc -n openshift-ingress get gateway <gateway_name>

    Note the IP address listed in the ADDRESS column.

  2. Access your organization’s DNS provider or server.
  3. Create a DNS record, such as an A record or wildcard A record, that maps the listener’s hostname to the external IP address of your gateway.

3.6. Routing HTTP requests to services

When you expose your applications through a gateway, you must configure an HTTPRoute custom resource (CR) to accurately direct incoming HTTP requests from your network listener to the appropriate backend services. A Gateway API HTTPRoute CR specifies the exact routing behavior for these requests by evaluating a set of rules.

Traffic delivery can be configured for an HTTPRoute using rules. You can configure up to 16 rules for a single route. Within each rule, you can establish the following routing behaviors:

  • Matches: Define the conditions an HTTP request must meet based on paths, headers, query parameters, or methods.
  • Filters: Apply processing directions to the request, such as header modifications, mirrors, or redirects.
  • BackendRefs: Designate the backend services where matching and filtered requests are delivered, including traffic weight distribution.
  • Timeouts: Establish strict time limits for the entire request or the backend hop.

3.6.1. Creating a basic HTTPRoute custom resource

To direct incoming network traffic from a gateway to your backend applications, you must create an HTTPRoute custom resource (CR). The resource specifies the hostnames the route handles and binds them to a parent Gateway CR.

Prerequisites

  • You created a target backend service.
  • You know the name and namespace of the parent Gateway CR.

Procedure

  1. Create an HTTPRoute CR file that references your parent gateway, application hostnames, and backend service, and save it as httproute.yaml:

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: sample-route
      namespace: my-application
    spec:
      parentRefs:
      - name: generic-gateway
        namespace: openshift-ingress
      hostnames:
      - app1.example.com
      - app2.example.com
      rules:
      - backendRefs:
        - name: application-backend
          port: 8080
    • You must include application hostnames and a backendRef rule that points to your backend service.
    • If your HTTPRoute and Gateway CRs are deployed in different namespaces, the Gateway CR listener must allow routes from the HTTPRoute namespace. You must configure the spec.listeners.allowedRoutes.namespaces field in the Gateway CR and specify a selector for trusted namespaces.
    • The listener hostname on the parent Gateway CR should cover the hostnames in your HTTPRoute CR. For example, a listener hostname of *.gwapi.apps.example.com accepts an HTTPRoute hostname such as app.gwapi.apps.example.com, but rejects hostnames outside that domain.
  2. Apply the HTTPRoute CR file to your cluster:

    $ oc apply -f httproute.yaml

Verification

  • Verify that the HTTPRoute CR was successfully created:

    $ oc get httproute <sample_route> -n <my_application>

    Example output

    NAME           HOSTNAMES                                 AGE
    sample-route   ["app1.example.com","app2.example.com"]   45s

3.6.2. Configuring path-based routing

To ensure traffic is routed to the correct application when multiple services share a gateway, you can define request matching conditions within your HTTPRoute custom resource (CR). You can match HTTP requests based on paths, headers, query parameters, or methods.

Prerequisites

  • You have installed the OpenShift CLI (oc).

Procedure

  1. Create or edit an HTTPRoute YAML file to include your desired match conditions under the spec.rules.matches field.

    The following example demonstrates a complete HTTPRoute custom resource (CR) configured with path-based matching to route requests for /<example_app> to a backend service. For details on configuring other match types, see Section 3.6.2.1, “Supported HTTPRoute match types”.

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: <path_match_example>
      namespace: <example_application>
    spec:
      parentRefs:
      - name: <example_gateway>
        namespace: openshift-ingress
      hostnames:
      - "<example.com>"
      rules:
      - matches:
        - path:
            type: Exact
            value: /<example_app>
        backendRefs:
        - name: <example_backend>
          port: 8080
  2. Apply the HTTPRoute CR by running the following command:

    $ oc apply -f <filename>.yaml

3.6.2.1. Supported HTTPRoute match types

Matches define conditions for matching rules against incoming HTTP requests. Each match is independent, meaning that any single satisfied match triggers the rule. You can combine multiple match types, all of which must be true for the request to match.

You can configure the following match types:

path
Consists of type and value. Path match type indicates how to match the value and may be either "Exact" or "PathPrefix" (default). The default path value, if omitted, is "/". On Red Hat OpenShift Service Mesh, "RegularExpression" may also be used as a type.
headers
Each consists of type, name, and value. Header match type indicates how to match the value and may be "Exact" (default) or on Red Hat OpenShift Service Mesh, "RegularExpression". Name is the HTTP header name, which must be case-insensitive. Value is the value of the HTTP header to be matched.
queryParameters
Each consists of type, name, and value. QueryParameters match type indicates how to match the value and may be "Exact" (default) or on Red Hat OpenShift Service Mesh, "RegularExpression". Name is the HTTP query parameter name and must match exactly. Value is the value of the HTTP query parameter to be matched.
method
A value in upper case that should match on the HTTP request method. Must be one of: GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, or PATCH.

The following example demonstrates a complete HTTPRoute custom resource (CR) configured with path-based matching to route requests for /<example_app> to a backend service:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: <path_match_example>
  namespace: <example_application>
spec:
  parentRefs:
  - name: <example_gateway>
    namespace: openshift-ingress
  hostnames:
  - "<example.com>"
  rules:
  - matches:
    - path:
        type: Exact
        value: /<example_app>
    backendRefs:
    - name: <example_backend>
      port: 8080
  • path specifies that the request must match a specific URL path.
  • type: Exact ensures the route only matches the exact string /<example_app>.
  • backendRefs defines the service where matching traffic is sent.

The following snippet demonstrates how to combine multiple header matches so that a request must contain both myheader: newheader AND color: orange to successfully match:

spec:
  rules:
  - matches:
    - headers:
      - name: <my_header>
        value: <new_header_value>
      - name: <color_header>
        value: <orange_value>
    backendRefs:
    - name: <example_service>
      port: 8080

To modify how HTTP requests are processed before they reach your backend services, you can pre-configure filters within the rules of your HTTPRoute custom resource (CR).

Configuring these filters allows you to automatically redirect traffic, modify headers, or mirror requests to achieve your desired routing behavior.

Prerequisites

  • You have installed the OpenShift CLI (oc).

Procedure

  1. Create or edit an HTTPRoute YAML file to include your desired processing directives under the spec.rules.filters field.

    The following example demonstrates a complete HTTPRoute custom resource (CR) with a requestRedirect filter that issues a permanent redirect (301) from HTTP to HTTPS. For details on configuring other filter types, see Section 3.6.3.1, “Supported HTTPRoute filters”.

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: <http_filter_example>
      namespace: <example_application>
    spec:
      parentRefs:
      - name: <example_gateway>
        namespace: openshift-ingress
      hostnames:
      - "<example.com>"
      rules:
      - filters:
        - type: RequestRedirect
          requestRedirect:
            scheme: https
            statusCode: 301
  2. Apply the HTTPRoute CR by running the following command:

    $ oc apply -f <filename>.yaml

3.6.3.1. Supported HTTPRoute filters

Filters apply processing directions to the HTTP request, such as header modification or redirect to another URL. You can specify up to 16 filters in a rule and combine most filter types except urlRewrite and requestRedirect.

You can apply the following filter types to a rule:

requestRedirect
Responds to an HTTP request with an HTTP 3xx code, instructing the client to retrieve another URL. Optional fields include scheme (http | https), hostname, path (type: replaceFullPath | replacePrefixMatch, string values for replaceFullPath or replacePrefixMatch), port, and statusCode (301 | 302 | 303 | 307 | 308).
requestHeaderModifier
Modifies an HTTP request’s headers. Only one modifier per header may be specified. Multiple values for a header must be comma-separated. Up to 16 header filters may be listed. Fields are one of Set, Add, Remove. Set, Add, and Remove may modify, add, and remove up to 16 header values that match a given name.
responseHeaderModifier
Available on Red Hat OpenShift Service Mesh, this extended filter modifies an HTTP response’s headers with the same constraints as requestHeaderModifier.
requestMirror
Available on Red Hat OpenShift Service Mesh, this extended filter mirrors (i.e. sends a duplicate) requests to specified destinations (backendRef). Fields include: backendRef, and the optional percent or fraction to specify the portion of requests that should be mirrored. If neither percent nor fraction are specified, then 100% of requests are mirrored.
urlRewrite
Available on Red Hat OpenShift Service Mesh, this extended filter modifies an HTTP request’s hostname, path, or both. It may not be used in combination with the requestRedirect filter. However, the path semantics for requestRedirect can also be used for urlRewrite, i.e. (type: replaceFullPath | replacePrefixMatch, string values for replaceFullPath or replacePrefixMatch).
3.6.3.1.1. Example: requestRedirect filter

The following example demonstrates a complete HTTPRoute custom resource (CR) with a requestRedirect filter that issues a permanent redirect (301) from HTTP to HTTPS:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: <http_filter_example>
  namespace: <example_application>
spec:
  parentRefs:
  - name: <example_gateway>
    namespace: openshift-ingress
  hostnames:
  - "<example.com>"
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301
  • hostnames defines the domain, such as "<example.com>", that this route applies to.
  • filters specifies the processing logic. In this example, the RequestRedirect type is used.
  • scheme: https instructs the gateway to redirect the client to the secure version of the URL.
  • statusCode: 301 indicates a permanent redirect.
3.6.3.1.2. Example: requestHeaderModifier filter

The following snippet demonstrates how to configure a requestHeaderModifier filter that adds a new header, modifies an existing header, and removes a specific header:

spec:
  rules:
  - filters:
    - type: RequestHeaderModifier
      requestHeaderModifier:
        add:
        - name: <my_header_name>
          value: <my_header_value>
    - type: RequestHeaderModifier
      requestHeaderModifier:
        set:
        - name: <old_header>
          value: <new_header_value>
    - type: RequestHeaderModifier
      requestHeaderModifier:
        remove: ["x-request-id"]

To route traffic to your backends, you must define service destinations and traffic weights within your HTTPRoute custom resource (CR) to distribute requests across your applications.

Prerequisites

  • You have installed the OpenShift CLI (oc).

Procedure

  1. Create or edit an HTTPRoute YAML file to include your desired service destinations under the spec.rules.backendRefs field.

    The following example demonstrates a complete HTTPRoute custom resource (CR) with a single backend destination that routes traffic to a service named <service_v1>. For details on configuring weights and routing to multiple destinations, see Section 3.6.4.1, “HTTPRoute backendRef configuration”.

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: <backend_route_example>
      namespace: <example_application>
    spec:
      parentRefs:
      - name: <example_gateway>
        namespace: openshift-ingress
      rules:
      - backendRefs:
        - name: <service_v1>
          port: 8080
  2. Apply the HTTPRoute CR by running the following command:

    $ oc apply -f <filename>.yaml

3.6.4.1. HTTPRoute backendRef configuration

BackendRefs are the service destinations of requests that meet your matches rules, and are composed of group, kind, name, namespace, port, and weight.

Name and port are the only required fields and refer to the service name and the service port number Weight is relevant when there is more than one backendRef, and specifies the proportion of requests forwarded to that specific backendRef. Without a backendRef, the rule doesn’t do any request forwarding and may return an error.

This example shows a BackendRef where there is a single backend destination, a service named <service_v1>:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: <backend_route_example>
  namespace: <example_application>
spec:
  parentRefs:
  - name: <example_gateway>
    namespace: openshift-ingress
  rules:
  - backendRefs:
    - name: <service_v1>
      port: 8080
  • backendRefs defines the destination services for the traffic.
  • name specifies the name of the Kubernetes service.
  • port specifies the port on which the service is listening.

This example shows two backendRefs where there is weighted delivery of 15 and 25 for the backends. This means <service_v1> gets 15/40 (3/8ths) of the traffic, and <service_v2> gets 25/40 (5/8ths) of the traffic. Though not required, it is recommended to have the weights add up to 100 whenever possible for clarity.

spec:
  rules:
  - backendRefs:
    - name: <service_v1>
      port: 8080
      weight: 15
    - name: <service_v2>
      port: 8080
      weight: 25

3.6.5. Setting timeouts for HTTP requests

To prevent hanging connections and ensure your application remains responsive, you can set strict timeouts for the entire request and the backend hop within your HTTPRoute custom resource (CR).

Prerequisites

  • You have installed the OpenShift CLI (oc).

Procedure

  1. Create or edit an HTTPRoute YAML file to include your desired timeout configurations under the spec.rules.timeouts field.

    The following example demonstrates a complete HTTPRoute custom resource (CR) where the entire request must complete within 30 seconds. For details on timeout formatting rules and backend request timeouts, see Section 3.6.5.1, “HTTPRoute timeout configuration”.

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: <timeout_example>
      namespace: <example_application>
    spec:
      parentRefs:
      - name: <example_gateway>
        namespace: openshift-ingress
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /<timeout_path>
        timeouts:
          request: 30s
        backendRefs:
        - name: <example_service>
          port: 8080
  2. Apply the HTTPRoute CR by running the following command:

    $ oc apply -f <filename>.yaml

3.6.5.1. HTTPRoute timeout configuration

There are two types of timeouts you can configure for an HTTPRoute custom resource (CR): request and backendRequest.

The request timeout covers the total time to send a request and then get a response back to the client. It represents the duration of the entire request-response transaction.

The backendRequest timeout covers the time for a request to travel from the gateway to the backend, and for a response to be received. Extending the timeout for a backendRequest can be helpful if the gateway needs to retry connections to a backend.

Note

The backendRequest timeout is classified as an extended feature (Support: Extended) according to Gateway API conventions.

When configuring timeouts, you must adhere to the following formatting rules and constraints:

  • The value of a backendRequest timeout cannot be greater than the value of the request timeout.
  • If specified, a timeout value must be 0 or greater than or equal to 1ms.
  • A zero-valued timeout (0) means there is no timeout.
  • Timeouts use a string format that starts with a number and expresses hours (h), minutes (m), seconds (s), or milliseconds (ms).
  • The number can be up to five digits, such as 10000s.
  • You can use multipart durations to express fractions, such as 1m30s, but you cannot use decimal dots.

The following example demonstrates a complete HTTPRoute custom resource (CR) where the entire request must complete within 30 seconds:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: <timeout_example>
  namespace: <example_application>
spec:
  parentRefs:
  - name: <example_gateway>
    namespace: openshift-ingress
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /<timeout_path>
    timeouts:
      request: 30s
    backendRefs:
    - name: <example_service>
      port: 8080
  • request specifies the timeout for the full request-response cycle.
  • PathPrefix ensures the timeout applies to all requests starting with /<timeout_path>.

The following snippet demonstrates a configuration where the request must succeed within 5 seconds, and the gateway-to-backend hop must complete within 1 second:

spec:
  rules:
  - timeouts:
      request: 5s
      backendRequest: 1s
    backendRefs:
    - name: <example_service>
      port: 8080

When you migrate from standard networking to Gateway API, you can compare OpenShift Container Platform routes with HTTPRoute custom resources (CRs) to understand which features are supported and how your configuration must change.

While both resources handle ingress traffic, they have distinct feature sets and implementation differences.

The following features are exclusive to HTTPRoute CRs:

  • Multiple hostnames
  • Matching based on HTTP headers
  • Matching based on query parameters
  • Request header modification
  • Request redirection
  • Request mirroring

The following features are exclusive to OpenShift Container Platform routes:

  • IP allow lists
  • Rate limiting (connection-based)
  • Subdomain indication
  • Re-encrypt TLS termination
  • Passthrough TLS termination

The following table outlines the features that are shared between both resources and how their specific implementations differ:

Table 3.3. Shared features and implementation differences
FeatureOpenShift Container Platform route implementationHTTPRoute implementation

Path matching

Supports prefix and exact matching.

Supports prefix, exact, and regular expression matching.

Backend references

Supports weighted traffic delivery to services.

Supports weighted traffic delivery to services via backendRefs.

Rewrite target

Configured using the haproxy.router.openshift.io/rewrite-target annotation.

Configured using the URLRewrite filter.

Sharding

Configured using metadata labels.

Configured using parent references (parentRefs).

3.7. Routing gRPC requests to services

When you expose your gRPC APIs through a gateway, you must configure a GRPCRoute resource to accurately direct incoming gRPC requests from a Gateway listener to an API object. A GRPCRoute specifies the exact routing behavior for these requests by evaluating a set of defined rules.

Within each GRPCRoute rule, you can establish the following routing behaviors:

  • matches: Define the conditions a gRPC request must meet based on specific gRPC methods and headers.
  • filters: Apply processing directions to the request, such as header modifications, before the traffic reaches the backend.
  • backendRefs: Designate the backend services where matching and filtered requests are delivered, including traffic weight distribution.

While standard GRPCRoute configurations share many similarities with HTTPRoute resources, the OpenShift Container Platform implementation of GRPCRoute adheres to the standard-channel Gateway API specification, which excludes upstream experimental fields and features.

To successfully configure your gRPC routing behavior, complete the following tasks:

  • Configuring gRPC request matching conditions
  • Applying processing filters to gRPC requests
  • Configuring routing destinations and traffic weights for gRPC
  • Understand GRPCRoute implementation details

When multiple gRPC services share a gateway, you can define request matching conditions based on gRPC methods and headers. This ensures that traffic is successfully routed to the correct backend application.

Matches define the specific conditions used for matching a rule against incoming gRPC requests. You can select gRPC requests via a method match, which can be an exact match or a regular expression, along with optional headers matches.

Each rule can specify a maximum of 64 matches. However, the total number of matches across all rules in a single GRPCRoute resource cannot exceed 128. If your routing requirements exceed this limit, you must distribute your complex matching combinations across multiple routes.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • You have installed Red Hat OpenShift Service Mesh.

Procedure

  1. Create or edit a GRPCRoute YAML file to include your desired match conditions under the spec.rules.matches field.

    The following example demonstrates a complete GRPCRoute resource configured with matching conditions for a specific gRPC service, method, and header:

    apiVersion: gateway.networking.k8s.io/v1
    kind: GRPCRoute
    metadata:
      name: grpc-match-example
      namespace: my-application
    spec:
      parentRefs:
      - name: my-gateway
        namespace: openshift-ingress
      hostnames:
      - "example.com"
      rules:
      - matches:
        - method:
            service: helloworld.Greeter
            method: SayHello
          headers:
          - name: x-version
            value: v1
        backendRefs:
        - name: greeter-service
          port: 50051
          weight: 1
    • parentRefs attaches the route to the my-gateway Gateway.
    • method specifies that the incoming request must be targeting the helloworld.Greeter service and specifically calling the SayHello method.
    • headers requires that the request must also include an x-version header with a value of v1. Both the method and header conditions must be met for this rule to apply.
    • backendRefs routes the matching traffic to the greeter-service backend.
  2. Apply the GRPCRoute resource by running the following command:

    $ oc apply -f <filename>.yaml

When a gRPC request hits your route, you can apply processing filters to modify the request or response before the traffic reaches your backend.

You can define optional filters within your routing rules to apply processing directives, such as request and response header modifiers or traffic mirroring. You can also specify rule-scoped filters directly within your backend references.

Because the data-plane behavior is provided by Red Hat OpenShift Service Mesh, you must validate specific feature support, such as filter capabilities and header matching, against your installed Service Mesh release.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • You have installed Red Hat OpenShift Service Mesh.

Procedure

  1. Create or edit a GRPCRoute YAML file to include your desired processing directives under the spec.rules.filters field.

    The following example demonstrates a complete GRPCRoute resource configured with a filter that adds a custom request header before routing to the backend service:

    apiVersion: gateway.networking.k8s.io/v1
    kind: GRPCRoute
    metadata:
      name: grpc-filter-example
      namespace: my-application
    spec:
      parentRefs:
      - name: my-gateway
        namespace: openshift-ingress
      hostnames:
      - "example.com"
      rules:
      - filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            add:
            - name: custom-grpc-header
              value: my-custom-value
        backendRefs:
        - name: greeter-service
          port: 50051
    • parentRefs attaches the route to a specific Gateway.
    • hostnames limits the route to requests intended for "example.com".
    • filters specifies the processing logic. In this example, the RequestHeaderModifier adds a custom header to the gRPC request before it reaches the backend.
    • backendRefs directs the modified traffic to the greeter-service backend on port 50051.
  2. Apply the GRPCRoute resource by running the following command:

    $ oc apply -f <filename>.yaml

When you route gRPC traffic, you must define backend service destinations and traffic weights to distribute requests across your APIs. BackendRefs designate the backend services where matching and filtered gRPC requests are delivered.

You can configure optional backend references for each routing rule. By defining multiple backend references and assigning a weight to each, you can control the proportion of gRPC traffic that is forwarded to specific versions of your service. The proportion of traffic sent to a specific backend is calculated by dividing its assigned weight by the sum of all weights across all backends configured in the rule.

Because Red Hat OpenShift Service Mesh handles the data-plane behavior, you must ensure that your GRPCRoute references an Istio ingress gateway in its parentRefs configuration.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • You have installed Red Hat OpenShift Service Mesh.

Procedure

  1. Create or edit a GRPCRoute YAML file to include your desired service destinations and traffic weights under the spec.rules.backendRefs field.

    The following example demonstrates a complete GRPCRoute resource that routes gRPC traffic between two versions of a backend service using proportional traffic weights:

    apiVersion: gateway.networking.k8s.io/v1
    kind: GRPCRoute
    metadata:
      name: grpc-weight-example
      namespace: my-application
    spec:
      parentRefs:
      - name: my-gateway
        namespace: openshift-ingress
      hostnames:
      - "example.com"
      rules:
      - backendRefs:
        - name: greeter-service-v1
          port: 50051
          weight: 90
        - name: greeter-service-v2
          port: 50051
          weight: 10
    • parentRefs attaches the route to the my-gateway Gateway.
    • backendRefs defines the destination services for the traffic.
    • weight dictates the traffic split. In this configuration, the total sum of the weights is 100. The route forwards 90% of the traffic to greeter-service-v1 and 10% to greeter-service-v2.
  2. Apply the GRPCRoute resource by running the following command:

    $ oc apply -f <filename>.yaml

3.7.4. GRPCRoute implementation details

The OpenShift Container Platform Cluster Ingress Operator vendors the standard-channel Gateway API v1.4.1 custom resource definition (CRD). When you migrate upstream GRPCRoute configurations to your cluster, you must ensure your manifests rely on standard-channel features to avoid validation errors.

Additionally, the cluster-ingress-operator only installs the GRPCRoute CRD and delegates all runtime semantics to Red Hat OpenShift Service Mesh. Because the operator does not reconcile GRPCRoute instances, the data-plane behavior depends entirely on your Service Mesh implementation.

The following list outlines the specific implementation details and channel limitations that apply to GRPCRoute resources on OpenShift Container Platform.

Experimental fields
Because OpenShift Container Platform uses the standard-channel CRD, upstream experimental features are not available. For example, the sessionPersistence block is excluded. The CRD will reject configurations that attempt to use any experimental fields.
Rule names
The spec.rules[].name field is currently an experimental feature in the upstream Gateway API. Because OpenShift Container Platform relies on the standard channel, this field is not available. You cannot annotate or deduplicate rule identities, and conformance suites expecting this field might fail.
Match limits
The OpenShift Container Platform schema fully aligns with upstream standard limits. A single GRPCRoute supports up to 16 rules, and each rule supports up to 64 matches. However, the total number of matches across all rules in a single route cannot exceed 128.

3.8. Securing HTTPRoutes

To protect sensitive data and meet security compliance requirements, you must secure your Gateway API application traffic. You can secure 'HTTPRoute' custom resources (CRs) by either applying edge or re-encrypt Transport Layer Security (TLS) termination. Choose your method based on your security architecture and performance needs.

To balance security compliance and application performance, you can configure edge or re-encrypt TLS termination on your gateway listeners.

Edge termination
Edge termination encrypts client traffic to the gateway but allows unencrypted traffic to pass to your internal services. This configuration is ideal for encrypting user logins while trading internal encryption for faster application performance.
Re-encrypt termination
Re-encrypt termination encrypts traffic from the client to the gateway, and then re-encrypts it to the destination service. This mode allows the gateway to inspect payloads to efficiently route traffic or block unauthorized access without eliminating backend encryption.
Important

OpenShift Container Platform does not support passthrough termination for Gateway API. Passthrough termination provides direct traffic encryption from the client to the service, and is only supported in traditional OpenShift Container Platform routes.

To secure traffic from clients to your gateway, configure a listener with the Terminate TLS mode and a certificateRef to an OpenShift Container Platform secret.

This configuration terminates encryption at the gateway for HTTPRoute custom resource (CR) traffic that targets the listener, and forwards unencrypted traffic to the destination service. You must have both an HTTPRoute CR and a gateway listener configured with intersecting hostnames for edge termination to successfully connect.

Prerequisites

  • You created an HTTPRoute CR that references your gateway. The hostnames defined in this route must match or intersect with the hostnames you plan to configure on your gateway listeners.
  • You created a Secret resource containing your TLS certificate and key in the same namespace as your gateway or in a namespace permitted by a ReferenceGrant CR.
Important

The configuration examples in this procedure use openshift-default as the gatewayClassName value. When creating your Gateway CR, ensure that the gatewayClassName field aligns with the GatewayClass CR in your cluster configuration.

Procedure

  • Create and apply a Gateway CR file configured for your domain requirements by using one of the following examples:

    • To secure multiple domains, configure separate listeners for each domain with their respective certificates as shown in the following example:

      apiVersion: gateway.networking.k8s.io/v1
      kind: Gateway
      metadata:
        name: tls-basic
        namespace: openshift-ingress
      spec:
        gatewayClassName: openshift-default
        listeners:
        - name: app1-https
          protocol: HTTPS
          port: 443
          hostname: app1.example.com
          tls:
            mode: Terminate
            certificateRefs:
            - kind: Secret
              group: ""
              name: app1-example-com-cert
        - name: app2-https
          protocol: HTTPS
          port: 443
          hostname: app2.example.com
          tls:
            mode: Terminate
            certificateRefs:
            - kind: Secret
              group: ""
              name: app2-example-com-cert
    • To secure wildcard domains, configure a single listener with a wildcard certificate:

      apiVersion: gateway.networking.k8s.io/v1
      kind: Gateway
      metadata:
        name: wildcard-gateway
        namespace: openshift-ingress
      spec:
        gatewayClassName: openshift-default
        listeners:
        - name: wildcard-https
          protocol: HTTPS
          port: 443
          hostname: "+++*+++.example.com"
          tls:
            mode: Terminate
            certificateRefs:
            - kind: Secret
              group: ""
              name: wildcard-cert

      You can configure both specific domain listeners and wildcard listeners on the same Gateway CR. Specific matches happen before wildcard matches, so a request to app1.example.com uses the specific certificate rather than the wildcard certificate.

    • To secure all domains, configure a listener that listens for all routes regardless of hostname as shown in the following example:

      apiVersion: gateway.networking.k8s.io/v1
      kind: Gateway
      metadata:
        name: default-gateway
        namespace: openshift-ingress
      spec:
        gatewayClassName: openshift-default
        listeners:
        - name: all-https
          protocol: HTTPS
          port: 443
          tls:
            mode: Terminate
            certificateRefs:
            - kind: Secret
              group: ""
              name: default-cert
    • To use a Secret object in a different namespace, configure your listener and create a corresponding ReferenceGrant CR as shown in the following example:

      apiVersion: gateway.networking.k8s.io/v1
      kind: Gateway
      metadata:
        name: cross-namespace-example
        namespace: example-ns1
      spec:
        gatewayClassName: openshift-default
        listeners:
        - name: https
          protocol: HTTPS
          port: 443
          hostname: "+++*+++.example.com"
          tls:
            mode: Terminate
            certificateRefs:
            - kind: Secret
              group: ""
              name: wildcard-cert
              namespace: example-ns2
      ---
      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: ReferenceGrant
      metadata:
        name: allow-ns1-reference
        namespace: example-ns2
      spec:
        from:
        - group: gateway.networking.k8s.io
          kind: Gateway
          namespace: example-ns1
        to:
        - group: ""
          kind: Secret

      Unlike standard OpenShift Container Platform routes that use namespace-wide annotations for cross-namespace permissions, Gateway API uses the ReferenceGrant CR to authorize access. This ReferenceGrant CR gives access from the Gateway CR in one namespace to the Secret object in another namespace.

Verification

  • Check the listener conditions to verify that the Gateway CR is successfully configured and listening on port 443. The following example checks the tls-basic sample gateway:

    $ oc get gateway tls-basic -n openshift-ingress -o yaml

    Example output

    status:
      listeners:
      - attachedRoutes: 1
        conditions:
        - lastTransitionTime: "2026-06-24T15:00:00Z"
          message: "The listener is valid"
          observedGeneration: 1
          reason: Accepted
          status: "True"
          type: Accepted
        - lastTransitionTime: "2026-06-24T15:00:00Z"
          message: "The listener is ready to accept traffic"
          observedGeneration: 1
          reason: Programmed
          status: "True"
          type: Programmed
        name: app1-https
        supportedKinds:
        - group: gateway.networking.k8s.io
          kind: HTTPRoute

3.8.3. About backend TLS validation

To ensure secure end-to-end encryption, you can use a BackendTLSPolicy custom resource (CR) to validate your backend certificates. This validation ensures that your Gateway CR securely connects to the correct destination pod.

To use re-encrypt termination in Gateway API, you must combine listener edge termination with a BackendTLSPolicy CR attached to the service.

Important

Re-encrypt for HTTPRoutes CRs requires a listener configured with edge termination on the Gateway CR and a BackendTLSPolicy CR that targets the service.

A BackendTLSPolicy CR describes up to 16 targets in the targetRefs parameter. The policy also determines how the backend certificate should be validated.

The BackendTLSPolicy CR specifies two options to validate backend certificates for a TLS connection. You must configure only one of the following options per policy:

caCertificateRefs
Use this option for explicit certificate authority (CA) certificates. The caCertificateRefs parameter can refer to up to eight PEM-encoded TLS certificates configured within a config map. The config map must reside in the same namespace as the BackendTLSPolicy CR. Cross-namespace references with a ReferenceGrant CR are not supported.
wellKnownCACertificates
Use this option for trusted system certificates.

The policy also specifies a Server Name Indication (SNI) hostname parameter that must match the certificate served by the destination pod unless you also specify a Subject Alternative Name (SAN) subjectAltNames parameter. You can specify up to five values in the subjectAltNames parameter.

You can use either SNIs or SANs depending on the certificate served by the targeted backend pods. If the pod certificate uses SANs, the BackendTLSPolicy CR must have at least one matching value in the subjectAltNames parameter to successfully connect using TLS. Each entry in the subjectAltNames parameter must include a type parameter. You can set the type value to either "hostname" or Uniform Resource Identifier ("URI"). You can specify the SAN itself as a domain name, URI, or a combination of both.

Important

Gateway API does not automatically evaluate the value of the hostname parameter as a SAN. If your certificate requires the hostname to be validated as a SAN, you must explicitly add it as a value in the subjectAltNames parameter.

To meet strict security requirements, use re-encrypt TLS termination to encrypt traffic from the gateway to your backend services. This ensures end-to-end encryption while allowing gateway payload inspection to route traffic efficiently.

Prerequisites

  • You created an edge-terminated listener on your gateway.
  • You created an HTTPRoute custom resource (CR).
  • You created a target backend service.
  • If you are using explicit CA certificates, you created a ConfigMap object containing the public CA certificate that signed the certificate of your backend service.
Important

Re-encrypt for HTTPRoutes CRs requires a listener configured with edge termination on the Gateway CR and a BackendTLSPolicy CR that targets the service.

Note

The BackendTLSPolicy CR must reside in the same namespace as your HTTPRoute CR unless you configure a ReferenceGrant CR. The HTTPRoute CR does not need to reside in the same namespace as your Gateway CR, provided the Gateway CR is configured to allow routes from other namespaces. Additionally, if you choose to specify a hostname parameter in the policy, its value must match the hostname configured in your HTTPRoute CR.

Procedure

  1. Create a BackendTLSPolicy CR that targets your backend service. Use one of the following configuration options:

    • To use system certificates for re-encrypt termination, set the wellKnownCACertificates parameter to the "System" value as shown in the following example:

      apiVersion: gateway.networking.k8s.io/v1
      kind: BackendTLSPolicy
      metadata:
        name: tls-upstream-dev
        namespace: my-application
      spec:
        targetRefs:
          - kind: Service
            name: dev
            group: ""
        validation:
          wellKnownCACertificates: "System"
          hostname: dev.example.com
    • To use explicit CA certificates for re-encrypt termination, configure the CR to use your pre-existing ConfigMap object, such as auth-cert in the following example:

      apiVersion: gateway.networking.k8s.io/v1
      kind: BackendTLSPolicy
      metadata:
        name: tls-upstream-auth
        namespace: my-application
      spec:
        targetRefs:
          - kind: Service
            name: auth
            group: ""
        validation:
          caCertificateRefs:
            - kind: ConfigMap
              name: auth-cert
              group: ""
          hostname: "authentication.example.com"
          subjectAltNames:
          - type: "URI"
            uri: "spiffe://authorization.example.com/identity"
    • To configure re-encrypt termination for a target service that exposes multiple ports and requires different policies, explicitly specify the port name using the sectionName parameter. The following example demonstrates this setup within your targetRefs configuration:

      Important

      If you omit the sectionName parameter when multiple references target the same service, the BackendTLSPolicy CR fails validation or results in a Conflicted status.

      apiVersion: gateway.networking.k8s.io/v1
      kind: BackendTLSPolicy
      metadata:
        name: tls-upstream-multi-port
        namespace: my-application
      spec:
        targetRefs:
          - kind: Service
            name: my-service
            group: ""
            sectionName: https
        validation:
          wellKnownCACertificates: "System"
          hostname: my-service.example.com
  2. Apply the policy to your cluster by running the following command:

    $ oc apply -f <filename>.yaml

Verification

  • Verify that the BackendTLSPolicy CR was accepted by the implementation controller by checking its status. The following example checks the tls-upstream-dev sample policy:

    $ oc get backendtlspolicy tls-upstream-dev -n my-application -o yaml

    Example output

    status:
      conditions:
      - lastTransitionTime: "2026-06-05T20:56:41Z"
        message: Configuration is valid
        observedGeneration: 1
        reason: Accepted
        status: "True"
        type: Accepted

Troubleshooting

  • If the Accepted status is set to False, check the reason parameter. Implementation-specific values, such as InvalidCACertificateRef or Pending, indicate why the re-encryption failed.

3.9. Verifying Gateway infrastructure status

To ensure your gateway infrastructure is properly configured and functioning, review the status conditions of your GatewayClass and Gateway custom resources (CRs). Checking these conditions confirms that the controller has successfully programmed your underlying data plane without routing conflicts.

3.9.1. GatewayClass status conditions reference

To verify that your GatewayClass custom resource (CR) is valid and ready to provision gateways, review its status conditions. A healthy GatewayClass CR reports a status of True for core conditions like Accepted and SupportedVersion.

Table 3.4. GatewayClass CR status conditions
ConditionStatusDescription and common reasons

Accepted

True

The GatewayClass CR is valid and the controller has claimed it.

Accepted

False

The configuration has errors or was rejected. Common reasons include:

  • InvalidParameters: Referenced parameters are invalid or not found.
  • Pending: The controller has not processed the resource yet.
  • Unknown: An unsupported controllerName was provided.

Accepted

Unknown

The GatewayClass CR is waiting for the controller to process it.

SupportedVersion

True

The installed Gateway API version is compatible with the controller.

SupportedVersion

False

There is a version mismatch. A common reason is UnsupportedVersion, which indicates that the custom resource definition (CRD) version does not match the controller requirements.

ControllerInstalled

True

The Cluster Ingress Operator successfully installed the controller for Gateway API.

ControllerInstalled

False

The installation failed.

ControllerInstalled

Unknown

The controller has not started the installation yet.

CRDsReady

True

The Istio CRDs are installed and actively managed by either the Cluster Ingress Operator or OLM.

CRDsReady

False

The CRDs were installed by a third party or have mixed ownership, preventing the controller from managing them.

CRDsReady

Unknown

The CRDs are not installed yet.

To verify that your gateway is configured in the data plane and ready to route traffic, review its gateway-level and listener-level status conditions. A healthy Gateway custom resource (CR) reports a status of True for its Accepted and Programmed conditions.

Important

The Conflicted listener condition uses negative polarity. This means that a status of False indicates a healthy state, while a status of True indicates an error.

Table 3.5. Gateway-level status conditions
ConditionStatusDescription and common reasons

Accepted

True

The gateway configuration is valid and working properly.

Accepted

False

The configuration has errors. Common reasons include:

  • ListenersNotValid: One or more listeners have issues.
  • InvalidParameters: The configuration is invalid.

Accepted

Unknown

The controller has not evaluated the gateway yet.

Programmed

True

The infrastructure is provisioned and the gateway is configured in the data plane, such as a load balancer or proxy.

Programmed

False

Programming failed or the data plane is not ready. Common reasons include:

  • NoResources: Insufficient resources or pods unavailable.
  • Invalid: Cannot apply to the data plane.
  • Pending

Programmed

Unknown

Programming is currently in progress.

LoadBalancerReady

True

The cloud load balancer service for the gateway is successfully provisioned.

LoadBalancerReady

False

The load balancer service failed to provision or is pending. Common reasons include ServiceNotFound, LoadBalancerPending, or SyncLoadBalancerFailed.

DNSReady

True

DNS records for all listeners are functioning correctly.

DNSReady

False

One or more listeners have DNS provisioning issues.

Table 3.6. Listener-level status conditions
ConditionStatusDescription and common reasons

Accepted

True

The listener configuration is valid and working properly.

Accepted

False

The listener configuration has errors.

Programmed

True

The listener is successfully configured in the data plane.

Programmed

False

The listener configuration failed in the data plane.

ResolvedRefs

True

All references, such as TLS certificates, are found and valid.

ResolvedRefs

False

At least one reference is invalid. Common reasons include:

  • InvalidCertificateRef: A TLS certificate was not found or is invalid.
  • RefNotPermitted: A cross-namespace reference is not allowed.

Conflicted (Negative polarity)

False

Healthy state. There are no conflicts.

Conflicted (Negative polarity)

True

The listener conflicts with another listener. Common reasons include:

  • ProtocolConflict: Multiple listeners on the same port with incompatible protocols.
  • HostnameConflict: Overlapping hostnames.

DNSReady

True

The DNS record for this listener’s hostname is successfully provisioned in all reported zones.

DNSReady

False

The DNS record failed to provision. Common reasons include FailedZones, NoDNSZones, or RecordNotFound.

DNSReady

Unknown

The DNS status cannot be determined or is unmanaged.

Note

Listeners without a configured hostname will not have DNS conditions added to their status.

Example Gateway CR status output showing a DNS failure on one listener

# ...
status:
  # Gateway-level conditions (LoadBalancer and aggregate DNS status)
  conditions:
  - type: LoadBalancerReady
    status: "True"
    reason: LoadBalancerProvisioned
    message: "The LoadBalancer service is provisioned"
    observedGeneration: 1
    lastTransitionTime: "2025-01-12T10:00:00Z"
  - type: DNSReady
    status: "False"
    reason: SomeListenersNotReady
    message: "One or more listeners have DNS provisioning issues"
    observedGeneration: 1
    lastTransitionTime: "2025-01-12T10:00:00Z"

  # Listener-level conditions (DNS status per listener)
  listeners:
  - name: <stage_http>
    conditions:
    - type: DNSReady
      status: "True"
      reason: NoFailedZones
      message: "The record is provisioned in all reported zones."
      observedGeneration: 1
      lastTransitionTime: "2025-01-12T10:00:00Z"
  - name: <prod_https>
    conditions:
    - type: DNSReady
      status: "False"
      reason: FailedZones
      message: "The record failed to provision in some zones: [<prod.example.com>]"
      observedGeneration: 1
      lastTransitionTime: "2025-01-12T10:00:00Z"

Note

For Google Cloud installations, you can use a custom DNS solution. You must manually create a DNS record for any gateways in Gateway API. For more information, see "Installing a cluster on Google Cloud with customizations".

To quickly check the health of your gateway infrastructure, query specific status fields using the OpenShift Container Platform CLI. You can validate your deployment, check route attachments, and retrieve IP addresses without parsing lengthy YAML manifests.

Prerequisites

  • You have access to the cluster as a user with the cluster-admin role.
  • You have installed the OpenShift CLI (oc).
  • Your gateway is deployed in the openshift-ingress namespace.
  • Your gateway is managed by the gateway controller (openshift.io/gateway-controller/v1).

Procedure

  • Run the relevant command for the status information you need to retrieve:

    • To list all GatewayClass custom resources (CRs) in your cluster, run the following command:

      $ oc get gatewayclass
    • To check if a specific GatewayClass CR has been accepted by the controller, run the following command:

      $ oc get gatewayclass <gatewayclass_name> -o jsonpath='{.status.conditions[?(@.type=="Accepted")].status}'
      • <gatewayclass_name>: Specify the name of your gateway class.
    • To list all Gateway custom resources (CRs) across all namespaces, run the following command:

      $ oc get gateway -A
    • To check if a specific Gateway CR is successfully programmed in the data plane, run the following command:

      $ oc get gateway <gateway_name> -n openshift-ingress -o jsonpath='{.status.conditions[?(@.type=="Programmed")].status}'
      • <gateway_name>: Specify the name of your gateway.
    • To retrieve the IP address assigned to a specific Gateway CR, run the following command:

      $ oc get gateway <gateway_name> -n openshift-ingress -o jsonpath='{.status.addresses[0].value}'
      • <gateway_name>: Specify the name of your gateway.
    • To check the total number of routes attached to a specific Gateway CR, run the following command:

      $ oc get gateway <gateway_name> -n openshift-ingress -o jsonpath='{.status.listeners[*].attachedRoutes}'
      • <gateway_name>: Specify the name of your gateway.
    • To watch a specific Gateway CR for real-time status changes, run the following command:

      $ oc get gateway <gateway_name> -n openshift-ingress -w
      • <gateway_name>: Specify the name of your gateway.
Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat Documentation

Legal Notice

Theme

© 2026 Red Hat
Back to top