|
| 1 | +--- |
| 2 | +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
| 3 | +# SPDX-License-Identifier: Apache-2.0 |
| 4 | +title: "External Access" |
| 5 | +sidebar-title: "External Access" |
| 6 | +slug: "kubernetes/openshift/external-access" |
| 7 | +description: "Expose the OpenShell gateway on OpenShift using a reencrypt Route or the Kubernetes Gateway API." |
| 8 | +keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, Route, Gateway API, Istio, gRPC, Ingress" |
| 9 | +position: 2 |
| 10 | +--- |
| 11 | + |
| 12 | +The gateway multiplexes gRPC and HTTP on a single port. External access must preserve HTTP/2 for gRPC to work. OpenShift offers two paths: |
| 13 | + |
| 14 | +| Method | HTTP/2 | Config complexity | Dependencies | |
| 15 | +|---|---|---|---| |
| 16 | +| [Reencrypt Route](#reencrypt-route) | Via annotation | Low (2 commands) | None | |
| 17 | +| [Gateway API](#gateway-api-with-istio) | Native | Medium (3 YAML resources) | Istio / Gateway API controller | |
| 18 | + |
| 19 | +## Why not edge or passthrough? |
| 20 | + |
| 21 | +| Route type | Problem | |
| 22 | +|---|---| |
| 23 | +| Edge | Terminates TLS and forces HTTP/1.1 to the backend, breaking gRPC. | |
| 24 | +| Passthrough | Preserves HTTP/2 but exposes the gateway's mTLS client certificate requirement to browsers, causing `ERR_BAD_SSL_CLIENT_AUTH_CERT`. | |
| 25 | + |
| 26 | +## Reencrypt Route |
| 27 | + |
| 28 | +A reencrypt route terminates external TLS at the OpenShift router, then re-establishes TLS to the gateway backend. The `backend-protocol=h2` annotation tells HAProxy to use HTTP/2 for the backend connection. |
| 29 | + |
| 30 | +```shell |
| 31 | +DEST_CA=$(oc get secret openshell-server-tls -n openshell \ |
| 32 | + -o jsonpath='{.data.ca\.crt}' | base64 -d) |
| 33 | + |
| 34 | +oc create route reencrypt openshell \ |
| 35 | + --service=openshell --port=8080 \ |
| 36 | + --dest-ca-cert=<(echo "$DEST_CA") \ |
| 37 | + -n openshell |
| 38 | + |
| 39 | +oc annotate route openshell -n openshell \ |
| 40 | + haproxy.router.openshift.io/backend-protocol=h2 --overwrite |
| 41 | +``` |
| 42 | + |
| 43 | +Register the gateway with the CLI using the route hostname: |
| 44 | + |
| 45 | +```shell |
| 46 | +oc get route openshell -n openshell -o jsonpath='{.spec.host}' |
| 47 | +openshell gateway add https://<route-hostname> --gateway-insecure --name openshift |
| 48 | +``` |
| 49 | + |
| 50 | +## Gateway API with Istio |
| 51 | + |
| 52 | +OpenShift manages the Gateway API CRDs through the Ingress Operator. The standard [Envoy Gateway](/kubernetes/ingress) cannot be installed because the Ingress Operator rejects third-party Gateway API CRD installations. Instead, use the OpenShift-managed Istio-based Gateway controller. |
| 53 | + |
| 54 | +<Steps> |
| 55 | + |
| 56 | +## Identify the GatewayClass |
| 57 | + |
| 58 | +```shell |
| 59 | +oc get gatewayclass |
| 60 | +``` |
| 61 | + |
| 62 | +Look for a class with an Istio-based controller (e.g. `istio` or `data-science-gateway-class`). The class must show `ACCEPTED: True`. |
| 63 | + |
| 64 | +## Create the Gateway and GRPCRoute |
| 65 | + |
| 66 | +```shell |
| 67 | +kubectl apply -f - <<'EOF' |
| 68 | +apiVersion: gateway.networking.k8s.io/v1 |
| 69 | +kind: Gateway |
| 70 | +metadata: |
| 71 | + name: openshell-gateway |
| 72 | + namespace: openshell |
| 73 | +spec: |
| 74 | + gatewayClassName: istio |
| 75 | + listeners: |
| 76 | + - name: grpc |
| 77 | + protocol: HTTPS |
| 78 | + port: 443 |
| 79 | + tls: |
| 80 | + mode: Terminate |
| 81 | + certificateRefs: |
| 82 | + - name: openshell-server-tls |
| 83 | + kind: Secret |
| 84 | + allowedRoutes: |
| 85 | + namespaces: |
| 86 | + from: Same |
| 87 | +--- |
| 88 | +apiVersion: gateway.networking.k8s.io/v1 |
| 89 | +kind: GRPCRoute |
| 90 | +metadata: |
| 91 | + name: openshell |
| 92 | + namespace: openshell |
| 93 | +spec: |
| 94 | + parentRefs: |
| 95 | + - name: openshell-gateway |
| 96 | + namespace: openshell |
| 97 | + rules: |
| 98 | + - backendRefs: |
| 99 | + - name: openshell |
| 100 | + port: 8080 |
| 101 | +EOF |
| 102 | +``` |
| 103 | + |
| 104 | +## Configure TLS to the backend |
| 105 | + |
| 106 | +The Istio envoy proxy terminates external TLS at the Gateway, then connects to the backend in plaintext by default. Since the OpenShell gateway expects TLS, create a `DestinationRule` for TLS origination: |
| 107 | + |
| 108 | +```shell |
| 109 | +kubectl apply -f - <<'EOF' |
| 110 | +apiVersion: networking.istio.io/v1 |
| 111 | +kind: DestinationRule |
| 112 | +metadata: |
| 113 | + name: openshell-tls-origination |
| 114 | + namespace: openshell |
| 115 | +spec: |
| 116 | + host: openshell.openshell.svc.cluster.local |
| 117 | + trafficPolicy: |
| 118 | + tls: |
| 119 | + mode: SIMPLE |
| 120 | + insecureSkipVerify: true |
| 121 | +EOF |
| 122 | +``` |
| 123 | + |
| 124 | +## Get the external address |
| 125 | + |
| 126 | +The Gateway controller creates a LoadBalancer service. Wait for the external address: |
| 127 | + |
| 128 | +```shell |
| 129 | +oc get gateway openshell-gateway -n openshell \ |
| 130 | + -o jsonpath='{.status.addresses[0].value}' |
| 131 | +``` |
| 132 | + |
| 133 | +<Note> |
| 134 | +AWS ELB DNS names can take 1-2 minutes to propagate after creation. |
| 135 | +</Note> |
| 136 | + |
| 137 | +## Register the gateway |
| 138 | + |
| 139 | +```shell |
| 140 | +openshell gateway add https://<external-address> --gateway-insecure --name openshift |
| 141 | +``` |
| 142 | + |
| 143 | +</Steps> |
| 144 | + |
| 145 | +## Next steps |
| 146 | + |
| 147 | +- [OIDC with Keycloak](/kubernetes/openshift/oidc-keycloak) — add `--oidc-issuer` to the `gateway add` command for authenticated access. |
0 commit comments