Spring Cloud Gateway includes an OpenAPI route conversion tool to help you generate a RouteConfig for a given OpenAPI spec. This feature is bundled with the Spring Cloud Gateway Operator and is exposed as an API. It can accept both OpenAPI 2.0 and OpenAPI 3.0 specs.
An OpenAPI Conversion service can be found in an SCG operator instance. If you have the service exposed in your kubernetes cluster via port-forward
or Ingress
, you only need to send a POST request with path /api/convert/openapi
to the reachable SCG-operator instance.
The next attributes are supported by the OpenAPI Conversion service
Field | Description |
service |
Kubernetes Service to route traffic to spec.routes spec which doesn't contain any service configuration.
|
openapi |
|
routes |
|
For more details about the JSON schema, please, check the section JSON schema to validate requests.
You can generate a RouteConfig for your service calling the operator endpoint. For example, given you have the operator exposed at http://operator.scg
and your Kubernetes service my-service
. For your OpenAPI specification "https://petstore3.swagger.io/api/v3/openapi.json", you only need to make a call to the endpoint at api/convert/openapi
:
curl --request POST 'http://operator.scg/api/convert/openapi' \
--header 'Content-Type: application/json' \
--data-raw '{
"service": {
"name": "my-service"
},
"openapi": {
"location": "https://petstore3.swagger.io/api/v3/openapi.json"
}
}'
This endpoint will return a JSON response, e.g:
{
"apiVersion": "tanzu.vmware.com/v1",
"kind": "SpringCloudGatewayRouteConfig",
"metadata": {
"name": "my-service"
},
"spec": {
"openapi": {
"components": {
"schemas": {...},
"requestBodies": {...},
"securitySchemes": {...}
},
"ref": "https://petstore3.swagger.io/api/v3/openapi.json"
},
"routes": [
{
"description": "Update an existing pet by Id",
"model": {
"requestBody": {...},
"responses": {...}
},
"predicates": [
"Path=/pet",
"Method=PUT"
],
"tags": [
"pet"
],
"title": "Update an existing pet"
},
...
],
"service": {
"name": "my-service"
}
}
}
For example, the request body below will pull the OpenAPI spec exposed via the openapi
service in the development
namespace, effectively making a call the uri openapi.development.svc.cluster.local:8080/openapi
:
{
"service": {
"name": "openapi",
"namespace": "development",
"port": "8080"
},
"openapi": {
"location": "/openapi"
}
}
To provide service level filters, you can specify a filters
array inside service
of the request body:
{
"openapi": {
"location": "https://petstore3.swagger.io/api/v3/openapi.json"
},
"service": {
"name": "my-service",
"filters": ["StripPrefix=1"]
}
}
Example result JSON:
{
"apiVersion": "tanzu.vmware.com/v1",
"kind": "SpringCloudGatewayRouteConfig",
"metadata": {
"name": "my-service"
},
"spec": {
"openapi": {...},
"routes": [...],
"service": {
"filters": [
"StripPrefix=1"
],
"name": "my-service"
}
}
}
Route level filters can be applied with a wildcard or using exact path. First route whose predicate matches exactly with the OpenAPI spec path is taken first. Otherwise, the first most specific matching a wildcard path will be taken.
Example:
"routes": [
{ # Route 1
"predicates": ["Method=GET", "Path=/pet/findByStatus"],
"filters": ["RateLimit=1,10s", "CustomFilter1"]
},
{ # Route 2
"predicates": ["Method=GET", "Path=/pet**"],
"filters": ["RateLimit=2,10s", "CustomFilter2"]
},
{ # Route 3
"predicates": ["Method=PUT", "Path=/store**"],
"filters": ["RateLimit=3,10s", "CustomFilter3"]
},
{ # Route 4
"predicates": ["Method=PUT", "Path=/store/order**"],
"filters": ["RateLimit=4,10s", "CustomFilter4"]
},
{ # Route 5
"predicates": ["Method=PUT", "Path=/store/order**"],
"filters": ["RateLimit=5,10s", "CustomFilter5"]
}
]
GET /pet/findByStatus
will use filters ["RateLimit=1,10s", "CustomFilter1"]
and attributes coming from Route 1GET /pet
will use filters ["RateLimit=2,10s", "CustomFilter2"]
and attributes coming from Route 2PUT /store
will use filters ["RateLimit=3,10s", "CustomFilter3"]
and attributes coming from Route 3PUT /store/order
will use filters ["RateLimit=4,10s", "CustomFilter4"]
and attributes coming from Route 4/store/order**
In addition, you can specify multiple methods to match with.
For example, given a request body of:
{
"service": {
"name": "test-service"
},
"openapi": {
"location": "https://petstore3.swagger.io/api/v3/openapi.json"
},
"routes": [
{
"predicates": ["Method=PUT,DELETE", "Path=/user**"],
"filters": ["RateLimit=4,15s", "StripPrefix=2"]
}
]
}
PUT /user/{username}
and DELETE /user/{username}
will have the filters RateLimit=4,15s
and StripPrefix=2
appliedApart of predicates
and filters
, you can activate some features in a route adding the next optional attributes:
ssoEnabled
(true|false): Activate SSO validation. See "Using Single Sign-On"tokenRelay
(true|false): Pass currently-authenticated user's identity token to application serviceorder
(number): Route processing order, same as Spring Cloud Gatewaytags
(array of strings): Classification tags, will override tags to methods in the generated OpenAPI documentationThe next route will activate SSO, pass authentication token to the upstream service, override tags by the tag "status" and the order of the route will be 1000
"routes" : [
{
"predicates": [ "Method=GET", "Path=/order/findByStatus" ],
"filters": [ "RateLimit=2,10s" ],
"ssoEnabled": true,
"tokenRelay": true,
"order": 1000,
"tags": ["status"]
}
]
You can fetch the JSON schema to validate requests by calling /json/schema
on the Spring Cloud Gateway operator.
For example, given you have the Spring Cloud Gateway operator exposed at http://operator.scg
, you can run:
curl --request GET 'http://operator.scg/json/schema' --header 'Accept: application/json'
To retrieve OpenAPI spec hosted with private CA, you need to provide a secret containing the custom CA cert and bind it to the scg-operator deployment. First we need to create a kubernetes secret with the CA certificate. This can be done either
Use cert-manager to create a TLS secret from the ClusterIssuer
on your cluster.
Create a certificate from your ClusterIssuer
Create a certificate from your ClusterIssuer
to generate a secret, e.g. scg-tls-cert
.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: scg-tls-cert
namespace: spring-cloud-gateway
spec:
secretName: scg-tls-cert
dnsNames:
- "your.domain.here"
issuerRef:
name: "your-cluster-issuer-here"
kind: ClusterIssuer
This secret will contain 3 keys: ca.crt
, tls.key
, and tls.crt
. We will need to construct a secret with only the ca.crt
. If you are on a TAP cluster, the next section will make use of the SecretTemplate
to achieve this.
If not, inspect the secret and extract the CA crt to a file, ca.crt
:
kubectl get secret scg-tls-cert -o yaml | yq -r '.data["ca.crt"]' | base64 -d > ca.crt
Then follow the steps on With CA certificate generated outside of the cluster
Create a SecretTemplate for the CA Cert
Using a SecretTemplate
from the secrettemplates.secretgen.carvel.dev
CRD, we can create a secret scg-ca-cert
with only the ca.crt
from the original scg-tls-cert
secret:
apiVersion: secretgen.carvel.dev/v1alpha1
kind: SecretTemplate
metadata:
name: scg-ca-cert
namespace: spring-cloud-gateway
spec:
inputResources:
- name: scg-tls-cert
ref:
apiVersion: v1
kind: Secret
name: scg-tls-cert
template:
data:
ca.crt: $(.scg-tls-cert.data.ca\.crt)
Finally, see Create a ServiceBinding to the SCG Operator to bind the secret to the scg-operator
deployment.
If you have a CA certificate file, e.g. ca.crt
, you can create the secret as follows:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: scg-ca-cert
type: Opaque
data:
ca.crt: $(cat path/to/ca.crt | base64 | tr -d '\n')
EOF
Now that we have a secret with only the ca.crt
, we create a ServiceBinding
of type ca-certificates
and apply it to the scg-operator
deployment. This requires the Service Bindings operator, which is installed in TAP, and uses the servicebindings.servicebinding.io
CRD.
apiVersion: servicebinding.io/v1beta1
kind: ServiceBinding
metadata:
name: tls-cert
namespace: spring-cloud-gateway
spec:
name: tls-cert
service:
apiVersion: v1
kind: Secret
name: scg-ca-cert
workload:
apiVersion: apps/v1
kind: Deployment
name: scg-operator
type: ca-certificates
The scg-operator pod will restart with a volume mount /bindings/tls-cert
containing the CA cert. You can list the files with the following command:
kubectl exec -it deploy/scg-operator -- ls /bindings/tls-cert
which should return something similar to:
ca.crt type
ca.crt
being the CA certificatetype
as ca-certificates
to let container know this is a servicebinding for CA certificates