Configuring and deploying Gateway policies with Connectivity Link
Secure, protect, and connect APIs on OpenShift
Abstract
Preface Copy linkLink copied to clipboard!
Providing feedback on Red Hat documentation
Red Hat appreciates your feedback on product documentation.
To propose improvements, open a Jira issue and describe your suggested changes. Provide as much detail as possible to help the documentation team to address your request quickly.
Prerequisite
- You have a Red Hat Customer Portal account. This account enables you to log in to the Red Hat Jira Software instance. If you do not have an account, you will be prompted to create one.
Procedure
- Click the following link: Create issue.
- In the Summary text box, enter a brief description of the issue.
In the Description text box, provide the following information:
- The URL of the page where you found the issue.
- A detailed description of the issue. You can leave the information in other fields at their default values.
- In the Reporter field, enter your Jira user name.
- Click Create to submit the Jira issue to the documentation team.
Thank you for taking the time to provide feedback.
Chapter 1. Secure, protect, and connect APIs on OpenShift with Connectivity Link Copy linkLink copied to clipboard!
This guide walks you through using Connectivity Link on OpenShift to secure, protect, and connect an API exposed by a Gateway that is based on Kubernetes Gateway API. You can use this walkthrough for a Gateway deployed on a single OpenShift cluster or a Gateway distributed across multiple OpenShift clusters with a shared HTTPS listener hostname. This guide shows how the platform engineer and application developer user roles can each use Connectivity Link to achieve their goals.
1.1. What Connectivity Link can do in multicluster environments Copy linkLink copied to clipboard!
You can leverage Connectivity Link’s capabilities in single or multiple OpenShift clusters. The following features are designed to work across multiple clusters as well as in a single-cluster environment:
-
Multicluster ingress: Connectivity Link provides multicluster ingress connectivity using DNS to bring traffic to your Gateways by using a strategy defined in a
DNSPolicy. -
Global rate limiting: Connectivity Link can enable global rate limiting use cases when configured to use a shared Redis or Dragonfly store for counters based on limits defined by a
RateLimitPolicy. -
Global auth: You can configure a Connectivity Link
AuthPolicyto leverage external auth providers to ensure that different clusters exposing the same API authenticate and authorize in the same way. -
Automatic TLS certificate generation: You can configure a
TLSPolicyto automatically provision TLS certificates based on Gateway listener hosts by using integration with cert-manager and ACME providers such as Let’s Encrypt. - Integration with federated metrics stores: Connectivity Link has example dashboards and metrics for visualizing your Gateways and observing traffic hitting those Gateways across multiple clusters.
1.2. User role workflows Copy linkLink copied to clipboard!
- Platform engineer: This guide walks through deploying a Gateway that provides secure communication and is protected and ready for use by application development teams to deploy an API. It then walks through using this Gateway in clusters in different geographic regions, leveraging Connectivity Link to bring specific traffic to your geo-located Gateways. This approach reduces latency and distributes load, while still protecting and securing with global rate limiting and auth.
Application developer: This guide walks through deploying your application API and shows how to override your Gateway-level global auth and rate limiting policies to configure your application-level auth and rate limiting requirements.
NoteFor details on how both user roles can observe and monitor Gateways when the OpenShift observability stack and user workload monitoring are deployed, see Connectivity Link Observability Guide.
1.3. Deployment management tooling Copy linkLink copied to clipboard!
While this guide uses kubectl commands for simplicity, working with multiple clusters is complex. It is best to use a tool such as Argo CD to manage the deployment of resources to multiple clusters.
Chapter 2. Check your Connectivity Link installation and permissions Copy linkLink copied to clipboard!
This guide expects that you have successfully installed Connectivity Link on at least one OpenShift cluster, and that you have the correct user permissions.
Prerequisites
- You completed the Connectivity Link installation steps on one or more clusters, as described in Installing Connectivity Link on OpenShift.
-
You have the
kubectloroccommand installed. - You have write access to the OpenShift namespaces used in this guide.
- You have an AWS account with Amazon Route 53 and a DNS zone for the examples in this guide. Google Cloud DNS and Microsoft Azure DNS are also supported.
Optional:
- For rate limiting in a multicluster environment, you have installed Connectivity Link on more than one cluster and have a shared accessible Redis-based datastore. For more details, see Installing Connectivity Link on OpenShift.
- For Observability, OpenShift user workload monitoring is configured to remote write to a central storage system such as Thanos, as described in Connectivity Link Observability Guide.
Chapter 3. Connectivity Link platform engineer workflow Copy linkLink copied to clipboard!
This section of the walkthrough shows how as a platform engineer you can deploy a Gateway that provides secure communication and is protected and ready for use by application development teams. It also shows how to use this Gateway in multiple clusters in different geographic regions.
Prerequisites
In multicluster environments, you must perform the following steps in each cluster individually, unless specifically excluded.
3.1. Step 1 - Set your environment variables Copy linkLink copied to clipboard!
Procedure
Set the following environment variables, which are used for convenience in this guide:
export zid=change-to-your-DNS-zone-ID export rootDomain=demo.example.com export gatewayNS=api-gateway export gatewayName=external export devNS=toystore export AWS_ACCESS_KEY_ID=xxxx export AWS_SECRET_ACCESS_KEY=xxxx export AWS_REGION=us-east-1 export clusterIssuerName=lets-encrypt export EMAIL=foo@example.comIn this example,
zidis your hosted zone ID displayed in the AWS Route 53 console.rootDomainis the top-level AWS Route 53 domain name that you will use for Connectivity Link.NoteThis guide uses environment variables for convenience only. If you know the environment variable values, you can set up the required
.yamlfiles in way that suits your needs.
3.2. Step 2 - Set up a DNS provider secret Copy linkLink copied to clipboard!
The DNS provider supplies a credential to access the DNS zones that Connectivity Link can use to set up DNS configuration. You must ensure that this credential has access to only the zones that you want managed.
You must apply the following Secret resources to each cluster. If you are adding an additional cluster, add them to the new cluster.
Procedure
If your Gateway namespace does not already exist, create it as follows:
kubectl create ns ${gatewayNS}If the secret for your DNS provider credentials was not already created when installing Connectivity Link, create this secret in your Gateway namespace as follows:
kubectl -n ${gatewayNS} create secret generic aws-credentials \ --type=kuadrant.io/aws \ --from-literal=AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \ --from-literal=AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEYBefore adding a TLS issuer, you must also create the credentials secret in the
cert-managernamespace as follows:kubectl -n cert-manager create secret generic aws-credentials \ --type=kuadrant.io/aws \ --from-literal=AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \ --from-literal=AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
3.3. Step 3 - Add a TLS issuer Copy linkLink copied to clipboard!
To secure communication to the Gateways, you will define a TLS issuer for TLS certificates. This example uses Let’s Encrypt, but you can use any certificate issuer supported by cert-manager.
Procedure
Enter the following command to define a TLS issuer. This example uses Let’s Encrypt, which you must also apply to all clusters:
kubectl apply -f - <<EOF apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: ${clusterIssuerName} spec: acme: email: ${EMAIL} privateKeySecretRef: name: le-secret server: https://acme-v02.api.letsencrypt.org/directory solvers: - dns01: route53: hostedZoneID: ${zid} region: ${AWS_REGION} accessKeyIDSecretRef: key: AWS_ACCESS_KEY_ID name: aws-credentials secretAccessKeySecretRef: key: AWS_SECRET_ACCESS_KEY name: aws-credentials EOFWait for the
ClusterIssuerto become ready as follows:kubectl wait clusterissuer/${clusterIssuerName} --for=condition=ready=true
3.4. Step 4 - Set up a Gateway Copy linkLink copied to clipboard!
For Connectivity Link to balance traffic using DNS across two or more clusters, you must define a Gateway with a shared host. You will define this by using an HTTPS listener with a wildcard hostname based on the root domain. As mentioned earlier, you must apply these resources to all clusters.
For now, the Gateway is set to accept an HTTPRoute from the same namespace only. This allows you to restrict who can use the Gateway until it is ready for general use.
Procedure
Enter the following command to create the Gateway:
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: ${gatewayName} namespace: ${gatewayNS} labels: kuadrant.io/gateway: "true" spec: gatewayClassName: istio listeners: - allowedRoutes: namespaces: from: Same hostname: "*.${rootDomain}" name: api port: 443 protocol: HTTPS tls: certificateRefs: - group: "" kind: Secret name: api-${gatewayName}-tls mode: Terminate EOFCheck the status of your Gateway as follows:
kubectl get gateway ${gatewayName} -n ${gatewayNS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}' kubectl get gateway ${gatewayName} -n ${gatewayNS} -o=jsonpath='{.status.conditions[?(@.type=="Programmed")].message}'Your Gateway should be accepted and programmed, which means valid and assigned an external address.
However, if you check your HTTPS listener status as follows, you will see that it is not yet programmed or ready to accept traffic due to bad TLS configuration:
kubectl get gateway ${gatewayName} -n ${gatewayNS} -o=jsonpath='{.status.listeners[0].conditions[?(@.type=="Programmed")].message}'Connectivity Link can help with this by using a TLSPolicy, which is described in the next step.
3.4.1. Optional: Configure metrics to be scraped from the Gateway instance Copy linkLink copied to clipboard!
If you have Prometheus set up in your cluster, you can configure a PodMonitor to scrape metrics directly from the Gateway pod. This configuration is required for metrics such as istio_requests_total. You must add the following configuration in the namespace where the Gateway is running:
kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: istio-proxies-monitor
namespace: ${gatewayNS}
spec:
selector:
matchExpressions:
- key: istio-prometheus-ignore
operator: DoesNotExist
podMetricsEndpoints:
- path: /stats/prometheus
interval: 30s
relabelings:
- action: keep
sourceLabels: ["__meta_kubernetes_pod_container_name"]
regex: "istio-proxy"
- action: keep
sourceLabels:
["__meta_kubernetes_pod_annotationpresent_prometheus_io_scrape"]
- action: replace
regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
replacement: "[\$2]:\$1"
sourceLabels:
[
"__meta_kubernetes_pod_annotation_prometheus_io_port",
"__meta_kubernetes_pod_ip",
]
targetLabel: "__address__"
- action: replace
regex: (\d+);((([0-9]+?)(\.|$)){4})
replacement: "\$2:\$1"
sourceLabels:
[
"__meta_kubernetes_pod_annotation_prometheus_io_port",
"__meta_kubernetes_pod_ip",
]
targetLabel: "__address__"
- action: labeldrop
regex: "__meta_kubernetes_pod_label_(.+)"
- sourceLabels: ["__meta_kubernetes_namespace"]
action: replace
targetLabel: namespace
- sourceLabels: ["__meta_kubernetes_pod_name"]
action: replace
targetLabel: pod_name
EOF
For more information on configuring metrics, see the Connectivity Link Observability Guide.
3.5. Step 5 - Configure your Gateway policies and HTTP route Copy linkLink copied to clipboard!
While your Gateway is now deployed, it has no exposed endpoints and your HTTPS listener is not programmed. Next, you can set up a TLSPolicy that leverages your CertificateIssuer to set up your HTTPS listener certificates.
You will define an AuthPolicy that will set up a default HTTP 403 response for any unprotected endpoints, as well as a RateLimitPolicy that will set up a default artificially low global limit to further protect any endpoints exposed by this Gateway.
You will also define a DNSPolicy with a load balancing strategy, and an HTTPRoute for your Gateway to communicate with your backend application API.
3.5.1. Set the TLS policy Copy linkLink copied to clipboard!
Procedure
Set the
TLSPolicyfor your Gateway as follows:kubectl apply -f - <<EOF apiVersion: kuadrant.io/v1 kind: TLSPolicy metadata: name: ${gatewayName}-tls namespace: ${gatewayNS} spec: targetRef: name: ${gatewayName} group: gateway.networking.k8s.io kind: Gateway issuerRef: group: cert-manager.io kind: ClusterIssuer name: ${clusterIssuerName} EOFCheck that your TLS policy was accepted by the controller as follows:
kubectl get tlspolicy ${gatewayName}-tls -n ${gatewayNS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}'
3.5.2. Set the Auth policy Copy linkLink copied to clipboard!
Procedure
Set a default, deny-all
AuthPolicyfor your Gateway as follows:kubectl apply -f - <<EOF apiVersion: kuadrant.io/v1 kind: AuthPolicy metadata: name: ${gatewayName}-auth namespace: ${gatewayNS} spec: targetRef: group: gateway.networking.k8s.io kind: Gateway name: ${gatewayName} defaults: rules: authorization: "deny": opa: rego: "allow = false" EOFCheck that your auth policy was accepted by the controller as follows:
kubectl get authpolicy ${gatewayName}-auth -n ${gatewayNS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}'
3.5.3. Set the rate limit policy Copy linkLink copied to clipboard!
Procedure
Set the default
RateLimitPolicyfor your Gateway as follows:kubectl apply -f - <<EOF apiVersion: kuadrant.io/v1 kind: RateLimitPolicy metadata: name: ${gatewayName}-rlp namespace: ${gatewayNS} spec: targetRef: group: gateway.networking.k8s.io kind: Gateway name: ${gatewayName} defaults: limits: "low-limit": rates: - limit: 2 window: 10s EOFNoteIt might take a few minutes for the
RateLimitPolicyto be applied depending on your cluster. The limit in this example is artificially low to show it working easily.To check your rate limits have been accepted, enter the following command:
kubectl get ratelimitpolicy ${gatewayName}-rlp -n ${gatewayNS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}'
3.5.4. Set the DNS policy Copy linkLink copied to clipboard!
Procedure
Set the
DNSPolicyfor your Gateway as follows:kubectl apply -f - <<EOF apiVersion: kuadrant.io/v1 kind: DNSPolicy metadata: name: ${gatewayName}-dnspolicy namespace: ${gatewayNS} spec: targetRef: name: ${gatewayName} group: gateway.networking.k8s.io kind: Gateway providerRefs: - name: aws-credentials loadBalancing: weight: 120 geo: EU defaultGeo: true EOFNoteThe
DNSPolicywill use the DNS ProviderSecretthat you defined earlier. Thegeoin this example isEU, but you can change this to suit your requirements.Check that your
DNSPolicyhas been accepted as follows:kubectl get dnspolicy ${gatewayName}-dnspolicy -n ${gatewayNS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}'
3.5.5. Create an HTTP route Copy linkLink copied to clipboard!
For test purposes, this section assumes that the toystore application is deployed. For more information, see Chapter 4, Connectivity Link application developer workflow.
Procedure
Create an
HTTPRouteto test your Gateway as follows:kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: test namespace: ${gatewayNS} labels: service: toystore spec: parentRefs: - name: ${gatewayName} namespace: ${gatewayNS} hostnames: - "test.${rootDomain}" rules: - backendRefs: - name: toystore port: 80 EOFCheck your Gateway policies are enforced as follows:
kubectl get dnspolicy ${gatewayName}-dnspolicy -n ${gatewayNS} -o=jsonpath='{.status.conditions[?(@.type=="Enforced")].message}' kubectl get authpolicy ${gatewayName}-auth -n ${gatewayNS} -o=jsonpath='{.status.conditions[?(@.type=="Enforced")].message}' kubectl get ratelimitpolicy ${gatewayName}-rlp -n ${gatewayNS} -o=jsonpath='{.status.conditions[?(@.type=="Enforced")].message}'Check your HTTPS listener is ready as follows:
kubectl get gateway ${gatewayName} -n ${gatewayNS} -o=jsonpath='{.status.listeners[0].conditions[?(@.type=="Programmed")].message}'
3.6. Step 6 - Test connectivity and deny all auth Copy linkLink copied to clipboard!
You can use curl to test your endpoint connectivity and auth.
Procedure
Enter the following command:
curl -w "%{http_code}" https://$(kubectl get httproute test -n ${gatewayNS} -o=jsonpath='{.spec.hostnames[0]}')You should see an HTTP
403response.
3.7. Step 7 - Open up the Gateway for other namespaces Copy linkLink copied to clipboard!
Because you have configured the Gateway, secured it with Connectivity Link policies, and tested it, you can now open it up for use by other teams in other namespaces.
Procedure
Enter the following command:
kubectl patch gateway ${gatewayName} -n ${gatewayNS} --type='json' -p='[{"op": "replace", "path": "/spec/listeners/0/allowedRoutes/namespaces/from", "value":"All"}]'
3.8. Step 8 - Extend the Gateway to multiple clusters and configure geo-based routing Copy linkLink copied to clipboard!
Procedure
To distribute this Gateway across multiple clusters, repeat this setup process for each cluster.
By default, this will implement a round-robin DNS strategy to distribute traffic evenly across the different clusters. Setting up your Gateways to serve clients based on their geographic location is straightforward with your current configuration.
Assuming that you have deployed Gateway instances across multiple clusters as per this guide, the next step involves updating the DNS controller with the geographic regions of the visible Gateways.
For instance, if you have one cluster in North America and another in the EU, you can direct traffic to these Gateways based on their location by configuring the appropriate policy. For your North American cluster, you can create a DNSPolicy and set the
loadBalancing:geofield toUS.
Chapter 4. Connectivity Link application developer workflow Copy linkLink copied to clipboard!
This section of the walkthrough shows how as an application developer you can override your existing Gateway-level policies to configure your application-level routing, authentication, and rate limiting requirements.
Prerequisites
- Your Connectivity Link environment is set up and policies are configured as described in Chapter 3, Connectivity Link platform engineer workflow.
4.1. Step 1 - Deploy the toystore app Copy linkLink copied to clipboard!
Procedure
Create the namespace for your application as follows, if it does not already exist:
kubectl create ns ${devNS}Deploy the
toystoreapplication to your developer namespace as follows, if it has not already been deployed:kubectl apply -f https://raw.githubusercontent.com/Kuadrant/Kuadrant-operator/main/examples/toystore/toystore.yaml -n ${devNS}
4.2. Step 2 - Set up the HTTPRoute for your API Copy linkLink copied to clipboard!
Procedure
Enter the following command to define an HTTP route for your Toystore application API:
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: toystore labels: deployment: toystore service: toystore spec: parentRefs: - name: ${gatewayName} namespace: ${gatewayNS} hostnames: - "api.${rootDomain}" rules: - matches: - method: GET path: type: PathPrefix value: "/cars" - method: GET path: type: PathPrefix value: "/dolls" backendRefs: - name: toystore port: 80 - matches: - path: type: PathPrefix value: "/admin" backendRefs: - name: toystore port: 80 EOFWith this
HTTPRoutein place, the service that you deployed is now exposed by the Gateway.You can access your API endpoint over HTTPS as follows:
export INGRESS_HOST=$(kubectl get gtw ${gatewayName} -o jsonpath='{.status.addresses[0].value}' -n api-gateway) curl --resolve api.${rootDomain}:443:${INGRESS_HOST} "https://api.${rootDomain}/cars"
4.3. Step 3 - Override the Gateway’s deny-all AuthPolicy Copy linkLink copied to clipboard!
Next, you will allow authenticated access to the Toystore API. You can do this by defining an AuthPolicy that targets the HTTPRoute resource created in the previous step.
Any new HTTPRoutes will still be affected by the existing Gateway-level policy. Because you want users to now access this API, you must override that Gateway policy. For simplicity, you can use API keys to authenticate the requests, but other options such as OpenID Connect are also available.
Procedure
Define API keys for bob and alice users as follows:
kubectl apply -f - <<EOF apiVersion: v1 kind: Secret metadata: name: bob-key labels: authorino.kuadrant.io/managed-by: authorino app: toystore annotations: secret.kuadrant.io/user-id: bob stringData: api_key: IAMBOB type: Opaque --- apiVersion: v1 kind: Secret metadata: name: alice-key labels: authorino.kuadrant.io/managed-by: authorino app: toystore annotations: secret.kuadrant.io/user-id: alice stringData: api_key: IAMALICE type: Opaque EOFOverride the
AuthPolicyto start accepting the API keys as follows:kubectl apply -f - <<EOF apiVersion: kuadrant.io/v1 kind: AuthPolicy metadata: name: toystore spec: targetRef: group: gateway.networking.k8s.io kind: HTTPRoute name: toystore rules: authentication: "api-key-users": apiKey: selector: matchLabels: app: toystore credentials: authorizationHeader: prefix: APIKEY response: success: filters: "identity": json: properties: "userid": selector: auth.identity.metadata.annotations.secret\.kuadrant\.io/user-id EOF
4.4. Step 4 - Override the Gateway’s RateLimitPolicy Copy linkLink copied to clipboard!
The configured Gateway limits provide a good set of limits for the general case. However, as the developer of the Toystore API, you might want to only allow a certain number of requests for specific users, and a general limit for all other users.
Procedure
Enter the following command to set rate limits for specific users:
kubectl apply -f - <<EOF apiVersion: kuadrant.io/v1 kind: RateLimitPolicy metadata: name: toystore spec: targetRef: group: gateway.networking.k8s.io kind: HTTPRoute name: toystore limits: "general-user": rates: - limit: 1 duration: 3 unit: second counters: - metadata.filter_metadata.envoy\.filters\.http\.ext_authz.identity.userid when: - selector: metadata.filter_metadata.envoy\.filters\.http\.ext_authz.identity.userid operator: neq value: bob "bob-limit": rates: - limit: 2 duration: 3 unit: second when: - selector: metadata.filter_metadata.envoy\.filters\.http\.ext_authz.identity.userid operator: eq value: bob EOFNoteIt might take a few minutes for the
RateLimitPolicyto be applied, depending on your cluster.As another example, you could give bob twice as many requests to use compared to all other users.
To test your new setup, send requests as alice as follows:
while :; do curl --resolve api.${rootDomain}:443:${INGRESS_HOST} --write-out '%{http_code}\n' --silent --output /dev/null -H 'Authorization: APIKEY IAMALICE' "https://api.${rootDomain}/cars" | grep -E --color "\b(429)\b|$"; sleep 1; doneSend requests as bob as follows:
while :; do curl --resolve api.${rootDomain}:443:${INGRESS_HOST} --write-out '%{http_code}\n' --silent --output /dev/null -H 'Authorization: APIKEY IAMBOB' "https://api.${rootDomain}/cars" | grep -E --color "\b(429)\b|$"; sleep 1; doneNoteIf you set up a DNS provider and configured a
DNSPolicyas described in the platform engineer workflow, you can omit the--resolve api.${rootDomain}:443:${INGRESS_HOST}flag. For example, for alice as follows:while :; do curl --write-out '%{http_code}\n' --silent --output /dev/null -H 'Authorization: APIKEY IAMALICE' "https://api.${rootDomain}/cars" | grep -E --color "\b(429)\b|$"; sleep 1; doneNoteIf you followed through this guide on more than one cluster, the DNS record for the
HTTPRoutehostname will have multiple IP addresses. This means that requests will be made in a round-robin pattern across clusters because your DNS provider sends different responses to lookups.
Appendix A. Using your Red Hat subscription Copy linkLink copied to clipboard!
Red Hat Connectivity Link is provided through a software subscription. To manage your subscriptions, access your account at the Red Hat Customer Portal.
Managing your subscriptions
- Go to access.redhat.com.
- If you do not already have an account, create one.
- Log in to your account.
- In the menu bar, click Subscriptions to view and manage your subscriptions.
Revised on 2025-05-14 11:01:41 UTC