Skip to main content
logoTetrate Service BridgeVersion: next

Validating API calls with OpenAPI

When Tetrate Gateways deliver RESTFul and other APIs, they function as an API Gateway. API delivery often relies on three specific capabilities:

  • Authentication Offload, generally using JWT Token validation or OIDC flows, relieving the API service of the burden of implementing and managing authentication;
  • Rate Limiting, controlling the volume of requests to an API instance, based on a global limit or defined by various dimensions, such as an access token;
  • Payload Validation, evaluating each API request against an OpenAPI Specification, to verify compliance and block potential attempts to abuse the API

This document concentrates on the third capability, OpenAPI Specification-based payload validation:

  • OpenAPI Spec definitions are added to a Tetrate Workspace using either the TSB UI or the TSB API (tctl, GitOps)
  • Gateway performs validation according to the openapi settings in the Gateway resource
  • Requests are admitted or blocked depending on whether or not they comply with the OpenAPI Spec definition

Before you begin - a demo service

To illustrate OAS Validation, the workflow in this document will use the jmalloc/echo-server application. This application responds to every HTTP request, echoing back the request it was given, and is an ideal base with which to test API traffic:

  1. Create the environment

    Select or create a namespace in your TSB-managed Workload cluster to use for testing. This namespace must be managed by TSB, so it must be included in a TSB workspace and in a Gateway Group for that workspace.

    In the examples below, we use:

    • Namespace: my-namespace (set as ${NS})
    • Workspace: my-workspace
    • Gateway Group: my-workspace-gatewaygroup
    • Tenant: my-tenant
    • Organization: my-organization

    Edit the examples to match your environment.

  2. Deploy the echo-server app

    Deploy the echo-server app to the namespace in the TSB workload cluster, for example, as follows:

    NS=my-namespace

    cat <<EOF > ${NS}-echo-server.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: echo
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: echo-server
    template:
    metadata:
    labels:
    app: echo-server
    spec:
    containers:
    - name: echo-server
    image: jmalloc/echo-server
    ports:
    - name: http-port
    containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: echo-service
    spec:
    ports:
    - name: http-port
    port: 80
    targetPort: http-port
    protocol: TCP
    selector:
    app: echo-server
    EOF

    kubectl apply -n ${NS} -f ${NS}-echo-server.yaml
  3. Deploy a Tetrate gateway

    Deploy a Tetrate gateway to the same namespace; this action deploys an Envoy instance within the namespace. Note the annotation needed to enable the OpenAPI validation feature:

    cat <<EOF > ${NS}-ingress-gw.yaml
    apiVersion: install.tetrate.io/v1alpha1
    kind: Gateway
    metadata:
    name: ${NS}-ingress-gw
    annotations:
    install.tetrate.io/enable-openapi-validation: "true"
    spec:
    type: UNIFIED
    kubeSpec:
    service:
    ports:
    - port: 8080
    name: http-8080
    EOF

    kubectl apply -n ${NS} -f ${NS}-ingress-gw.yaml
    Enable-Openapi-Validation annotation

    The enable-openapi-validation annotation is necessary for this use case. The default Envoy gateway deployed by Tetrate does not include the additional functionality to parse and validate API request against an OAS definition; the annotation instructs the Tetrate platform to deploy an extended Envoy gateway.

  4. Deploy a Gateway Resource to Expose the App

    Deploy a Tetrate Gateway Resource to expose the application through the gateway:

    cat <<EOF > ${NS}-echo-ingress-plain.yaml
    apiVersion: gateway.tsb.tetrate.io/v2
    kind: Gateway
    metadata:
    organization: my-organization
    tenant: my-tenant
    workspace: my-workspace
    group: my-workspace-gatewaygroup
    name: echo-gateway
    spec:
    workloadSelector:
    namespace: ${NS}
    labels:
    app: ${NS}-ingress-gw
    http:
    - name: echo
    port: 8080
    hostname: "echo.tetrate.io"
    routing:
    rules:
    - route:
    serviceDestination:
    host: "${NS}/echo-service.${NS}.svc.cluster.local"
    port: 80
    EOF

    tctl apply -f ${NS}-echo-ingress-plain.yaml
  5. Verify you can access the App

    GW_IP=`kubectl get svc -n ${NS} ${NS}-ingress-gw -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}"`
    GW_ADDRESS=${GW_IP}:8080

    echo GW_ADDRESS is $GW_ADDRESS

    curl -s -D - -X POST -H "Host: echo.tetrate.io" http://$GW_ADDRESS/users/123 -d '{"username":"john"}'

Configure OpenAPI Payload Validation

We will upload an OAS definition to the Tetrate workspace, and then configure our Gateway Resource to perform OpenAPI Payload Validation.

  1. Upload a definition

    Upload an OpenAPI definition, using either the UI, API or GitOps interfaces:

    Navigate to the Workspace > OpenAPI Payload Validation page and create a new API resource:

    Create a new OpenAPI API resource Create a new OpenAPI API resource

    Copy-and-paste the OpenAPI Spec content from the tctl or GitOps example.

  2. Update the Gateway resource to enable OAS Payload Validation

    Update the Gateway resource, adding the openapi stanza. Check the organization, tenant and workspace names in the fdn:

    cat <<EOF > ${NS}-echo-ingress-oas.yaml
    apiVersion: gateway.tsb.tetrate.io/v2
    kind: Gateway
    metadata:
    organization: my-organization
    tenant: my-tenant
    workspace: my-workspace
    group: my-workspace-gatewaygroup
    name: echo-gateway
    spec:
    workloadSelector:
    namespace: ${NS}
    labels:
    app: ${NS}-ingress-gw
    http:
    - name: echo
    port: 8080
    hostname: "echo.tetrate.io"
    routing:
    rules:
    - route:
    serviceDestination:
    host: "${NS}/echo-service.${NS}.svc.cluster.local"
    port: 80
    openapi:
    fqn: organizations/my-organization/tenants/my-tenant/workspaces/${NS}-ws/apis/openapi-test
    validation:
    enabled: true
    pathPrefix: ""
    EOF

    tctl apply -f ${NS}-echo-ingress-oas.yaml
  3. Verify you can access the App

    Finally, verify once again that you can access the app:

    GW_IP=`kubectl get svc -n ${NS} ${NS}-ingress-gw -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}"`
    GW_ADDRESS=${GW_IP}:8080

    echo GW_ADDRESS is $GW_ADDRESS

    curl -s -D - -X POST -H "Host: echo.tetrate.io" http://$GW_ADDRESS/users/123 -d '{"username":"john"}'

Test Validation

You can test validation against the OAS spec used above, with requests resembling the following:

echo; echo The following requests will work
curl -s -D - -X POST -H "Host: echo.tetrate.io" http://$GW_ADDRESS/users/123 -d '{"username":"john"}' | head -1
curl -s -D - -X GET -H "Host: echo.tetrate.io" http://$GW_ADDRESS/messages | head -1
curl -s -D - -X GET -H "Host: echo.tetrate.io" http://$GW_ADDRESS/messages\?limit=10 | head -1

echo; echo These requests will return 403 Forbidden as they do not match a path in the spec
curl -s -D - -X POST -H "Host: echo.tetrate.io" http://$GW_ADDRESS/u-sers/123 -d '{"username":"john"}' | head -1
curl -s -D - -X GET -H "Host: echo.tetrate.io" http://$GW_ADDRESS/m-essages | head -1
curl -s -D - -X GET -H "Host: echo.tetrate.io" http://$GW_ADDRESS/m-essages\?limit=10 | head -1

echo; echo These requests will return 422 Unprocessable Entity as they fail validation in the spec
curl -s -D - -X POST -H "Host: echo.tetrate.io" http://$GW_ADDRESS/users/123 | head -1
curl -s -D - -X POST -H "Host: echo.tetrate.io" http://$GW_ADDRESS/users/123 -d '{"username":123}' | head -1
curl -s -D - -X POST -H "Host: echo.tetrate.io" http://$GW_ADDRESS/users/123 -d '{}' | head -1
curl -s -D - -X POST -H "Host: echo.tetrate.io" http://$GW_ADDRESS/users/123 -d '{"username":"john","name":"john"}' | head -1
curl -s -D - -X POST -H "Host: echo.tetrate.io" http://$GW_ADDRESS/users/john -d '{"username":"john"}' | head -1
curl -s -D - -X GET -H "Host: echo.tetrate.io" http://$GW_ADDRESS/messages\?limit=0 | head -1
curl -s -D - -X GET -H "Host: echo.tetrate.io" http://$GW_ADDRESS/messages\?limit=101 | head -1

Follow the Gateway Logs

Follow the gateway logs:

kubectl logs -f -n ${NS} -l app=${NS}-ingress-gw

Whenever a request is refused (fails validation), the response is logged with either a 403 (request did not match a path in the spec) or 422 (payload failed validation) status code:

[2025-01-02T16:39:34.908Z] "GET /messages?limit=0 HTTP/1.1" 422 -  - "-" 0 194 0 - "172.16.0.5" "curl/7.81.0" "1de263d3-84cb-4b60-a26a-9981220f606d" "echo.tetrate.io" "-" outbound|80||echo-service.echo-test.svc.cluster.local - 172.16.0.168:8080 172.16.0.5:60316 - echo-gateway-echo-external-0

If refused, the response contains a brief description of the reason why the request failed validation:

HTTP/1.1 422 Unprocessable Entity
content-length: 194
content-type: text/plain
date: Thu, 02 Jan 2025 16:39:34 GMT
server: istio-envoy

Request validation failed: Query parameters are not as expected: Validation of parameter limit failed: Parameter limit does not match the schema: At /limit of 0 - instance is below minimum of 1

Switch between Validating and Non-Validating mode

You can update the Gateway resource to enable or disable validation:

openapi:
fqn: organizations/my-organization/tenants/my-tenant/workspaces/${NS}-ws/apis/openapi-test
validation:
enabled: true # false for no validation
pathPrefix: ""

Update the OAS definition

If you update or edit the OAS definition, the Gateway will reload the new definition and log the parsed version.

For example, in the example above, you can change the parameters to validate the limit value, allowing requests such as http://$GW_ADDRESS/messages\?limit=101.

Configure Validation

OAS Validation is configured as follows:

openapi:
fqn: organizations/my-organization/tenants/my-tenant/workspaces/${NS}-ws/apis/openapi-test
validation:
enabled: true
pathPrefix: ""
  • fqn: the 'fully-qualified name' identifies the OAS definition in the TSB hierarchy. A Gateway can access any OAS definitions that are published to the same parent Workspace
  • enabled: when set to false, OAS Validation is not performed
  • pathPrefix: the value, such as /api/v1, is stripped from the client-provided URL before the URL is matched against the OAS definition; this allows you to expose APIs under specific paths

The API documentation is described in more detail in the Reference Guide.