This topic describes how to configure and update a Spring Cloud Gateway for Kubernetes instance.

Configure Gateway Instances

To create a Gateway instance, you must create a resource of type SpringCloudGateway. The definition for SpringCloudGateway specifies:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name:            # Name given to this Gateway instance (required)
  labels:
    my-custom-label: hello # Labels defined in the Gateway resource will also be applied to the Gateway Pods for simplified management
  annotations:
    my-custom-annotation: my-value # Annotations defined on the Gateway resource will also be applied to the Gateway Pods for simplified management
spec:
  count:           # Number of container instances (pods) to scale Gateway for high availability (HA) configuration
  tls:             # DEPRECATED: Use server.tls instead to set a list of TLS-enabled hosts
    - hosts:       # Array of hostnames for which to perform TLS termination using the specified certificate
      secretName:  # Name of TLS secret to load certificate and key from
  server:
    tls:            # Set a list of TLS-enabled hosts
      - hosts:      # Array of hostnames for which to perform TLS termination using the specified certificate
        secretName: # Name of TLS secret to load certificate and key from
  client:
    tls:           # Configure trusted certificates for upstream connections
      secretNames: # Name of TLS secrets containing trusted certificates for upstream connections
  sso:
    secret:        # Secret name to be used for SSO configuration
    roles-attribute-name:
                   # Roles attribute name used to extract user roles for Roles filter (default: 'roles')
    inactive-session-expiration-in-minutes:
                   # Time to life of inactive sessions in minutes, 0 means sessions won't expire.
  observability:
    metrics:
      wavefront:
        enabled:   # If Wavefront metrics should be pushed
      prometheus:
        enabled:   # If a Prometheus endpoint should be exposed
        annotations:
          enabled: # If scrapping annotations should be included in the Pod
    tracing:
      wavefront:
        enabled: # If Wavefront traces should be pushed
    wavefront:
      secret:        # Secret name to be used for Wavefront configuration
      source:        # The Wavefront source (default: Gateway Pod name, `gateway-0`).
      application:   # The Wavefront application (default: Gateway Namespace `namespace`).
      service:       # The Wavefront service (default: Gateway name `my-gateway`).
  api:
    groupId:       # Unique identifier for the group of APIs available on the Gateway instance (default: normalized title of the Gateway instance)
    title:         # Title describing the context of the APIs available on the Gateway instance (default: name of the Gateway instance)
    description:   # Detailed description of the APIs available on the Gateway instance (default: `Generated OpenAPI 3 document that describes the API routes configured for '[Gateway instance name]' Spring Cloud Gateway instance deployed under '[namespace]' namespace.`)
    documentation: # Location of additional documentation for the APIs available on the Gateway instance
    version:       # Version of APIs available on this Gateway instance (default: `unspecified`)
    serverUrl:     # Base URL that API consumers will use to access APIs on the Gateway instance
    cors:
      allowedOrigins:          # Allowed origins to make cross-site requests, applied globally
      allowedOriginPatterns:   # Allowed origin patterns to make cross-site requests, applied globally
      allowedMethods:          # Allowed HTTP methods on cross-site requests, applied globally
      allowedHeaders:          # Allowed headers in cross-site request, applied globally
      maxAge:                  # How long, in seconds, the response from a pre-flight request can be cached by clients, applied globally
      allowCredentials:        # Whether user credentials are supported on cross-site requests, applied globally
      exposedHeaders:          # HTTP response headers to expose for cross-site requests, applied globally
      perRoute:                # A map of URL Patterns to Spring Framework CorsConfiguration, to configure CORS per route.

  java-opts:       # JRE parameters for Gateway instance to enhance performance

  env:             # (deprecated: Use 'podOverrides' instead) Set a list of [configuration](https://cloud.spring.io/spring-cloud-gateway/reference/html/appendix.html#common-application-properties) environment variables to configure this Gateway instance
    - name:          # Name of the environment variable
      value:         # Value of environment variable

  extensions:                 # Additional configurations for global features (e.g. custom filters, Api Key,...)
    custom:                   # Array of custom extensions to load (name must match the ConfigMap name).
    secretsProviders:         # Array of secret providers. Only one can be set at this time.
    - name:                   # Name of the secret provider
      awsSecretsManager:      # AWS Secrets Manager configuration parameters
        iamRoleArn:           # The IAM Role ARN to associate with the service account. e.g. arn:aws:iam::111122223333:role/iam-role-name
      azureKeyVault:          # Azure Key Vault configuration parameters
        aadpodidbinding:      # Your Azure AD Pod Identity. e.g. my-pod-identity
      googleSecretManager:    # Google Secret Manager configuration parameters
        iamServiceAccount:    # The email address of the GCP IAM Service Account. e.g. secrets-sa@my-project.iam.gserviceaccount.com
      vault:                  # Vault integration configuration parameters. Requires the Vault Agent Injector
        authPath:             # Authentication path for the Kubernetes auth method.
        path:                 # Vault secrets' path (e.g. 'my-secrets/context').
        roleName:             # Vault role name with access to the secrets according to the Vault policies.
    filters:
      apiKey:                 # API Key specific configurations
        enabled:
        secretsProviderName:  # Currently only supports Vault with the Agent Injector
      jwtKey:                 # JWT Key specific configurations
        enabled:
        secretsProviderName:  # Currently only supports Vault with the Agent Injector

  resources:       # (deprecated: Use 'podOverrides' instead)
    requests:      # Requested amount of compute resources for the Gateway instance
      cpu:
      memory:
    limits:        # Maximum amount of compute resources allowed for the Gateway instance
      cpu:
      memory:

  responseCache:
      enabled:	     # Activate the global HTTP response cache feature
      local:         # Configuration for local cache feature
        size:        # Maximum size of cache (10MB, 900KB, 1GB...) that algorithm will use to determine if the cache needs to evict some entries
        timeToLive:  # Time before a cached entry is expired (300s, 5m, 1h...)
      gemfire:	     # Configuration for gemfire cache feature
        region:      # Gemfire region name for global caching
        secret:      # Name of a secret in the same namespace which contains username and password for authenticating on Gemfire cluster
        locators:    # Set a list of gemfire locators to use for global caching
          - host:    # Gemfire locator host
            port:    # Gemfire locator port
        tls:         # Optionally configure TLS connections to the Gemfire cluster
          enabled:   # Enable or disable Gemfire TLS
          secret:    # Name of a secret in the same namespace which contains truststore information 

  securityContext: # (deprecated: Use 'podOverrides' instead) SecurityContext applied to the Gateway pod(s).
    fsGroup:       # Set to 1000 by default
    runAsGroup:
    runAsUser:

  serviceAccount:  # Name of the ServiceAccount associated to the Gateway instance
    name:

  service:         # Configuration of the Kubernetes service for the gateway
    type:          # Determines how the Service is exposed. Either ClusterIP, NodePort, or LoadBalancer. Defaults to ClusterIP.
    nodePort:      # The port on which this service is exposed when type=NodePort or LoadBalancer.

  podOverrides:    # Used to override the gateway pod's default specs. To configure the gateway container, specify the specs under a container with the name 'gateway'.

Following is an example Gateway instance configuration file:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  count: 3
  api:
    title: My Exciting APIs
    description: Lots of new exciting APIs that you can use for examples!
    version: 0.1.0
    serverUrl: https://gateway.example.com
  env:
    - name: spring.cloud.gateway.httpclient.connect-timeout
      value: "90s"

Configure External Access

Each Gateway instance has an associated service of type ClusterIP. You can expose this service via common Kubernetes approaches such as ingress routing or port forwarding. Consult your cloud provider's documentation for Ingress options available to you.

Using an Ingress Resource

Before adding an Ingress, ensure that you have an ingress controller running in your Kubernetes cluster according to your cloud provider documentation.

To use an Ingress resource for exposing a Gateway instance:

  1. In the namespace where the Gateway instance was created, locate the ClusterIP service associated with the Gateway instance. You can either use this service as an Ingress backend or change it to a different Service type.

  2. Create a file called ingress-config.yaml, with the following YAML definition:

    apiVersion: networking.k8s.io/v1
    kind: Ingress 
    metadata: 
      name: my-gateway-ingress
      namespace: my-namespace
      annotations:
        kubernetes.io/ingress.class: contour 
    spec: 
      rules: 
        - host: my-gateway.my-example-domain.com 
          http: 
            paths:
              - path: /
                pathType: Prefix
                backend: 
                  service:
                    name: my-gateway 
                    port:
                      number: 80 
    

    For the host and serviceName values, substitute your desired hostname and service name.

    This example Ingress resource configuration uses the Project Contour Ingress Controller. You can adapt the example configuration if you wish to use another Ingress implementation.

  3. Apply the Ingress definition file. The Ingress resource must be created in the same namespace as the Gateway instance.

  4. Examine the newly created Ingress resource:

    $ kubectl -n my-namespace get ingress my-gateway-ingress
    
    NAME                  CLASS    HOSTS                                     ADDRESS       PORTS   AGE
    my-gateway-ingress    <none>   my-gateway.my-example-domain.com          34.69.53.79    80     2m51s
    
    $ kubectl -n my-namespace describe ingress my-gateway-ingress
    
    Name:             my-gateway-ingress
    Namespace:        my-namespace 
    Address:          34.69.53.79 
    Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>) 
    Rules: 
      Host                                     Path  Backends 
      ----                                     ----  -------- 
      my-gateway.my-example-domain.com
                                               /   my-gateway:80 () 
    

    As the example output shows, the my-gateway.my-example-domain.com virtual host in the Ingress definition is mapped to the my-gateway service on the backend.

  5. Ensure that you can resolve the Ingress definition hostname (in this example, my-gateway.my-example-domain.com) to the IP address of the Ingress resource.

    The IP address is shown in the Address field of the output from the kubectl describe command.

    For local testing, use the command below to open your /etc/hosts file.

    sudo vim /etc/hosts
    

    Resolve the hostname by adding a line to the hosts file.

    34.69.53.79     my-gateway.my-example-domain.com 
    

    For extended evaluation, you might create a wildcard DNS A record that maps any virtual host on the domain name (for example, *.my-example-domain.com) to the Ingress resource.

  6. You should now be able to connect to your Gateway instance via the Ingress resource, using a web browser or an HTTP client such as HTTPie or cURL.

    $ http my-gateway.my-example-domain.com/github
    $ http my-gateway.my-example-domain.com/github/<YOUR_GITHUB_USERNAME>
    

    These requests should receive responses from the GitHub homepage (https://github.com) or from the requested path on the GitHub website.

  7. Test the SSO configuration, for example using an HTTP client such as HTTPie:

    $ http my-gateway.my-example-domain.com/github
    

    This request should result in a 302 HTTP status code response, redirecting to the SSO login page. If you use a web browser to access the route my-gateway.my-example-domain.com/github, you will be redirected to the SSO login page. After authenticating, you will be redirected to the GitHub home page.

Gateway Actuator Management Port

Spring Cloud Gateway for Kubernetes instances are created with a Spring Boot actuator management port. The management port is 8090 on each Gateway instance pod based on the HA configuration. This management port can be used for monitoring using the following endpoints:

  • /actuator/info - display version and other Gateway instance information
  • /actuator/health - displays Gateway instance health indicator as status value UP or DOWN
  • /actuator/gateway/routes - retrieve list of all API routes currently available on Gateway instance
  • /actuator/gateway/globalfilters - retrieve list of global filters enabled on Gateway instance
  • /actuator/gateway/routefilters - retrieve list of route filters available on Gateway instance

Configure for High Availability

You can configure Spring Cloud Gateway for Kubernetes to run multiple instances in High Availability as you would do with a normal Kubernetes resource.

While a Gateway is running you can use kubectl scale to modify the number of replicas. For example, given a Gateway that has 1 replica, the following will increase the number of replicas to 4.

$ kubectl scale scg my-gateway --replicas=4

And to decrease the number back to the original value.

$ kubectl scale scg my-gateway --replicas=1

In initial configuration, you can specify the number of replicas using the spec.count parameter. The following example configures a replica count of 3.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  count: 3

So long as no other changes are introduced in the descriptor, you can safely modify spec.count and re-apply to increase or decrease the number of replicas.

To verify your changes use kubectl get pods to check that the pods match the count number.

Configure TLS

Spring Cloud Gateway for Kubernetes supports TLS in order to encrypt data in flight, and to assert identity and trust between services. This section describes the two scenarios in which you may need to customise your Gateway's TLS behaviour.

TLS termination for inbound requests

Spring Cloud Gateway for Kubernetes can be configured to perform TLS termination for inbound requests. When this feature is enabled, the Gateway will serve a custom certificate to the requesting client. If required, the Gateway can select from a set of certificates to respond with, based on the requested host.

If you enable TLS termination on your Gateway instance, you will need to route requests to port 443, rather than port 80, of the Gateway service.

If you are using an Ingress in front of your Gateway and would like to delegate TLS termination responsibilities to the Gateway, you will need to configure your Ingress to perform TLS passthrough. This configuration will be dependent on the Ingress implementation in use, so please refer to your Ingress provider's documentation for this step. As an example, to do this using Contour, instead of using the Ingress API you will need to create an HTTPProxy instance, using the TLS passthrough option:

apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: my-gateway-httpproxy
spec:
  virtualhost:
    fqdn: my-gateway.my-example-domain.com
    tls:
      passthrough: true
  tcpproxy:
    services:
      - name: my-gateway
        port: 443

The certificates Spring Cloud Gateway for Kubernetes will use for TLS termination, and their associated private keys, are loaded from Kubernetes TLS secrets. You will need to create a TLS secret for each certificate you would like the Gateway to serve. The easiest way to do this is with kubectl, using PEM encoded certificate and key files.

kubectl create secret tls my-tls-secret --cert=path/to/certificate.pem --key=path/to/private-key.pem

For each TLS secret you create, the certificate.pem file should contain the server certificate to add to the Gateway, and the private-key.pem file should contain the private key for that certificate, in PKCS#8 or PKCS#1 format.

Next, create a SpringCloudGateway resource which references your TLS secrets. Populating the spec.server.tls array enables the TLS termination feature. Each array item should consist of a secretName which references the secret containing the certificate/key pair you want to serve, and a list of hosts. When a request arrives at the gateway referencing one of these hosts, the gateway will serve the certificate from the matching secret.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: test-gateway-tls
spec:
  server:
    tls:
      - hosts:
          - host-a.my-tls-gateway.my-example-domain.com
          - host-b.my-tls-gateway.my-example-domain.com
        secretName: tls-secret-1
      - hosts:
          - host-c.my-tls-gateway.my-example-domain.com
          - host-d.my-tls-gateway.my-example-domain.com
        secretName: tls-secret-2

The client with which you make requests to your gateway must support Server Name Indication, in order to pass the requested hostname to the gateway as part of the TLS handshake.

Deprecation: The spec.server.tls replaces the spec.tls property found in older versions of the SpringCloudGateway custom resource definition. spec.tls has been deprecated and will be removed in the future, so we recommend changing existing configurations to the new spec.server.tls format.

To verify that everything is working as expected, you can use openssl to check the certificates that are returned for each of the configured hosts. For example:

openssl s_client -showcerts -servername host-a.my-tls-gateway.my-example-domain.com -connect <your ingress ip>:443 | openssl x509 -text

where <your ingress ip> should be replaced with the external IP of your TLS passthrough enabled ingress.

Custom Certificate Authorities for outbound requests

The second scenario which may require configuration is when Spring Cloud Gateway for Kubernetes is acting as a client, making outbound requests to upstream services, and those services are serving certificates which are signed by a Certificate Authority which is not universally trusted. This could be the case, for example, if you make use of custom CA certificates that are generated and trusted within your organisation. In this case, the Gateway can be provided with a list of CA certificates that it should trust when making these outbound requests.

Custom CA Certificates are loaded from Kubernetes TLS secrets. The Kubernetes CLI does not allow creating a tls secret with only a certificate. In this case you need to create a resource and apply it, here is a way to do it on step.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: my-ca-certificate-secret-1
type: tls
data:
  tls.crt: $(cat path/to/tls.crt | base64 | tr -d '\n')
EOF

Next, create a `SpringCloudGateway` resource which references your custom CA certificate secrets in the `spec.client.tls` field. The resulting Gateway will then trust any certificate it receives which is signed by one of the CA certificates in the configured list.

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: test-gateway-tls spec: client: tls: secretNames: - my-ca-certificate-secret-1 - my-ca-certificate-secret-2


## <a id="env-config"></a>Configure Environment Variables

You can define a map of environment variables to configure the API gateway using the `spec.env` property. The following example configure the connection timeout from API gateway to application services and the Spring Framework web package logging level.

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: gateway-demo spec: ... env: - name: spring.cloud.gateway.httpclient.connect-timeout value: "90s" - name: logging.level.org.springframework.web value: debug

## <a id="secure-headers-filter"></a>Disable SecureHeaders Global Filter

The backing app for a Spring Cloud Gateway service instance has a custom SecureHeaders filter globally enabled by default. This filter adds the following headers to the response:

<table>
	<col style="width:50%">
	<col style="width:50%">
	<thead>
		<td><strong>Enabled Secure Header</strong></td>
		<td><strong>Default Value</strong></td>
	</thead>
	<tr>
		<td><code>Cache-Control</code></td>
		<td><code>no-cache, no-store, max-age=0, must-revalidate</code></td>
	</tr>
	<tr>
		<td><code>Pragma</code></td>
		<td><code>no-cache</code></td>
	</tr>
	<tr>
		<td><code>Expires</code></td>
		<td><code>0</code></tr>
	<tr>
		<td><code>X-Content-Type-Options</code></td>
		<td><code>nosniff</code></td>
	</tr>
	<tr>
		<td><code>Strict-Transport-Security</code></td>
		<td><code>max-age=631138519</code></td>
	</tr>
	<tr>
		<td><code>X-Frame-Options</code></td>
		<td><code>DENY</code></td>
	</tr>
	<tr>
		<td><code>X-XSS-Protection</code></td>
		<td><code>1; mode=block</code></td>
	</tr>
</table>

If you do not want any secure headers being added to the response, you can disable the global filter for the entire gateway instance by setting `disable-secure-headers` to `true`:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: env: - name: spring.cloud.gateway.secure-headers.disabled value: "true"


To disable a specific header for a given route, you could use [`RemoveResponseHeader` filter](https://cloud.spring.io/spring-cloud-gateway/reference/html/#removeresponseheader-gatewayfilter-factory) for the route.
For example, to remove `X-Frame-Options` header for a route, you might run:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGatewayRouteConfig metadata: name: my-gateway-routes spec: routes: - uri: https://httpbin.org predicates: - Path=/remove-cache-control/** filters: - StripPrefix=1 - RemoveResponseHeader=X-Frame-Options


To disable a specific header globally for all routes, you could set an environment variable on the gateway according
to the [`SecureHeaders` filter doc](https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-secureheaders-gatewayfilter-factory):

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: env: - name: spring.cloud.gateway.filter.secure-headers.disable value: "x-frame-options"


## <a id="cache-config"></a>Configure global HTTP response cache

You can define a global HTTP response cache that will be applied to all route configurations on your gateway.

According to HTTP specifications, there are some considerations to take into account when enabling this feature:
- It only handles bodyless `GET` requests.
- It only caches responses with the following status codes: HTTP `200` (OK), HTTP `206` (Partial Content) and HTTP `301` (Moved Permanently).
- Response data will not be cached if the `Cache-Control` header does not allow it (`no-store` in the request, `no-store` or `private` in the response).
- If the response is already cached and a new request is performed with the `no-cache` value in the `Cache-Control` header, it will return a bodyless response with `304` (Not Modified).

There are two response cache implementations available:
- Local response cache: an in-memory cache implemented with Caffeine
- Gemfire response cache: a shared, distributed cache using Gemfire

The `spec.responseCache.enabled` parameter must be `true` in order to enable any HTTP response caching on the gateway. Enabling just this parameter without specifying any other configuration will enable the local response cache implementation, with a default time to live for cached items of 5 minutes. Further configuration options for each of the response cache implementations are described below.

Please note that the respective global response cache implementation must be enabled as described here in order to use either of the [LocalResponseCache](route-filters.html#local-response-cache) or [GemfireResponseCache](route-filters.html#gemfire-response-cache) route filters.

<p class="note">
  <strong>Note:</strong>
  If configuration is specified for both cache implementations, then the local cache implementation will be used. The Gemfire configuration will be ignored.
</p>

### <a id="local-global-response-cache"></a>Local global HTTP response cache

The local response cache (implemented with Caffeine) allows for configuration of the following optional parameters in the `spec.responseCache.local` block:

<table>
	<col style="width:15%">
	<col style="width:50%">
	<col style="width:35%">
	<thead>
		<td><strong>Parameter</strong></td>
		<td><strong>Function</strong></td>
		<td><strong>Example</strong></td>
	</thead>
	<tr>
		<td><code>size</code></td>
		<td>
		    Maximum cache size before the eviction algorithm is invoked. The size can be specified in KB, MB or GB.
        </td>
		<td><code>size: 8MB</code></td>
	</tr>
	<tr>
		<td><code>timeToLive</code></td>
		<td>
		    Time before a cached entry is expired, expressed in s for seconds, m for minutes or h for hours.
        </td>
		<td><code>timeToLive: 5m</code></td>
	</tr>
</table>


apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: responseCache: enabled: true local: size: 8MB timeToLive: 5m


The local response cache implementation automatically calculates and sets the `max-age` value in the HTTP `Cache-Control` header. Only if `max-age` is present on the original response
will the value be rewritten with the number of seconds set in the `timeToLive` configuration parameter. In consecutive calls this value will be recalculated and set to the number of seconds left before the cached entry is evicted.

### <a id="gemfire-global-response-cache"></a>Gemfire global HTTP response cache

Given a region and connection details, a shared distributed cache through Gemfire can be used. The following parameters can be configured in the `spec.responseCache.gemfire` block:

<table>
	<col style="width:15%">
	<col style="width:50%">
	<col style="width:35%">
	<thead>
		<td><strong>Parameter</strong></td>
		<td><strong>Function</strong></td>
		<td><strong>Example</strong></td>
	</thead>
	<tr>
		<td><code>region</code></td>
		<td>
		    Gemfire region name for global caching, as all Gemfire cache data is organized into data regions.
        </td>
		<td><code>region: my-region-name</code></td>
	</tr>
	<tr>
		<td><code>secret</code></td>
		<td>
		    The name of a Secret within the same namespace, containing credentials for authenticating with the Gemfire cluster. The secret should contain values for keys named <code>gemfire.username</code> and <code>gemfire.password</code>.
        </td>
		<td><code>secret: my-gemfire-credentials-secret</code></td>
	</tr>
	<tr>
		<td><code>locators</code></td>
		<td>
		    A list of locator servers that provides Gemfire discovery information. Please note that if using TLS-secured connections to the Gemfire cluster, the provided locator hosts must match with the Common Name or Subject Alternative Names of the certificate being served by the locator.  
        </td>
		<td><code>locators:<br>&nbsp;&nbsp;- host: my-gemfire-locator.cluster.local<br>&nbsp;&nbsp;&nbsp;&nbsp;port: 10334</code></td>
	</tr>
    <tr>
		<td><code>tls</code></td>
		<td>
		    The <code>tls</code> key is optional, and only required in order to use TLS when connecting to Gemfire. Set the <code>enabled</code> key to <code>true</code> to enable TLS support. The optional <code>secret</code> key should contain the name of a Secret within the same namespace, containing truststore information for connecting to the Gemfire cluster with TLS. The secret must specify a value for a key named <code>truststore</code>, containing the bytes of a supported Java truststore. Optionally the secret can also contain values for <code>truststore.password</code> (defaults to the empty string) and <code>truststore.type</code> (defaults to <code>JKS</code>). If <code>secret</code> is not specified then the JVM's default truststore will be used.
        </td>
		<td><code>tls:<br>&nbsp;&nbsp;enabled: true<br>&nbsp;&nbsp;secret: my-gemfire-tls-secret</code></td>
	</tr>
</table>

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: responseCache: enabled: true gemfire: region: my-region-name secret: my-gemfire-credentials-secret locators: - host: my-gemfire-locator.cluster.local port: 10334 tls: enabled: true secret: my-gemfire-tls-secret


apiVersion: v1 kind: Secret metadata: name: my-gemfire-credentials-secret type: Opaque data: gemfire.username: ... gemfire.password: ...


apiVersion: v1 kind: Secret metadata: name: my-gemfire-tls-secret type: Opaque data: truststore: ... # Truststore bytes truststore.password: ... truststore.type: ...




## <a id="cors-config"></a>Configure Cross-Origin Resource Sharing (CORS)

You can define a global CORS behavior that will be applied to all route configurations mapped to it.

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: api: cors: allowedOrigins: - "https://foo.example.com" allowedMethods: - "GET" - "PUT" - "POST" allowedHeaders: - '*'


The following parameters can be configured in the `spec.api.cors` block:

<table>
	<col style="width:25%">
	<col style="width:50%">
	<col style="width:25%">
	<thead>
		<td><strong>Parameter</strong></td>
		<td><strong>Function</strong></td>
		<td><strong>Example</strong></td>
	</thead>
	<tr>
		<td><code>allowedOrigins</code></td>
		<td>
		    Allowed origins to make cross-site requests. The special value "*" allows all domains.
		    These values will be combined with the values from allowedOriginPatterns.
        </td>
		<td><code>allowedOrigins: https://example.com</code></td>
	</tr>
	<tr>
		<td><code>allowedOriginPatterns</code></td>
		<td>
		    Alternative to allowedOrigins that supports more flexible origins patterns with "*" anywhere in the host name in addition to port lists.
            These values will be combined with the values from allowedOrigins.
        </td>
		<td><code>allowedOriginPatterns:<br>&nbsp;&nbsp;- https://*.test.com:8080</code></td>
	</tr>
	<tr>
		<td><code>allowedMethods</code></td>
		<td>Allowed HTTP methods on cross-site requests. The special value "*" allows all methods. If not set, "GET" and "HEAD" are allowed by default.</td>
		<td><code>allowedMethods:<br>&nbsp;&nbsp;- GET<br>&nbsp;&nbsp;- PUT<br>&nbsp;&nbsp;- POST</code></td>
	</tr>
	<tr>
		<td><code>allowedHeaders</code></td>
		<td>Allowed headers in cross-site requests. The special value "*" allows actual requests to send any header.</td>
		<td><code>allowedHeaders:<br>&nbsp;&nbsp;- X-Custom-Header</code></tr>
	<tr>
		<td><code>maxAge</code></td>
		<td>How long, in seconds, the response from a pre-flight request can be cached by clients.</td>
		<td><code>maxAge: 300</code></td>
	</tr>
	<tr>
		<td><code>allowCredentials</code></td>
		<td>Whether user credentials are supported on cross-site requests. Valid values: `true`, `false`.</td>
		<td><code>allowCredentials: true</code></td>
	</tr>
	<tr>
		<td><code>exposedHeaders</code></td>
		<td>HTTP response headers to expose for cross-site requests.</td>
		<td><code>exposedHeaders:<br>&nbsp;&nbsp;- X-Custom-Header</code></td>
	</tr>
</table>

You can also configure CORS behavior per route. However, the global CORS configuration must not be set.
Each route defined on the gateway should have a matching path predicate on the route config.

Note that you can also define per-route cors behavior through the [Cors filter](route-filters.html#cors).

The example below configures CORS behavior for the `/get/**` and `/example/**` routes:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: api: cors: perRoute: '[/get/]': allowedOrigins: - "https://foo.example.com" allowedMethods: - "GET" - "PUT" - "POST" allowedHeaders: - '*' '[/example/]': allowedOrigins: - "https://bar.example.com" allowedMethods: - "GET" - "POST" allowedHeaders: - '*'


Each route can be configured with the same parameters as in the table above.

Here is a matching route config:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGatewayRouteConfig metadata: name: my-gateway-routes spec: routes: - uri: https://httpbin.org predicates: - Path=/get/** filters: - StripPrefix=1 - uri: https://httpbin.org predicates: - Path=/example/** filters: - StripPrefix=1


<p class="note">
  <strong>Note:</strong>
  To avoid browser calls failing due to duplicated headers (for example, receiving multiple 'Access-Control-Allow-Origin' or multiple 'Access-Control-Allow-Credentials') because a downstream service is also doing CORS processing,
  duplicates in these two headers are automatically removed and the one configured in the gateway will always predominate.
</p>

## <a id="response-cache"></a>Configure Response Cache

HTTP GET responses coming from a route under Spring Cloud Gateway could be cached setting the flag `spec.responseCache.enabled` to `true`.

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: responseCache: enabled: true size: 500MB # (Optional) if the cache reached 500MB summing all the responses, the eviction process will eventually be triggered timeToLive: 300 # (Optional) 300 seconds of Time To Live for an entry in the cache


There are two additional options available:
* `size`: maximum of the total size
* `timeToLive`: amount of seconds a response will be kept into the cache

Note: This feature only handles bodyless HTTP GET requests.

## <a id="java-opts"></a>Configure Java Environment Options

For JVM tuning it is possible to define Java Environment Options (`JAVA_OPTS`) in the Spring Cloud Gateway for K8s configuration.

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: count: 2 java-opts: -XX:+PrintFlagsFinal -Xmx512m


This will restart the pods and apply the options to the underlying gateway instances.

## <a id="session-expiration"></a>Configure session expiration

If you need to be able to discard inactive sessions after a certain time (e.g 10 minutes), just add the `inactive-session-expiration-in-minutes` configuration.

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: sso: secret: my-sso-credentials inactive-session-expiration-in-minutes: 10


This does not modify any authorization server token expiration (or ttl) configuration.
It only affects the session information managed inside the gateway.

## <a id="hw-resources"></a>Configuring Hardware Resources

Similarly to other Kubernetes resources, you can optionally define the required memory (RAM) and CPU for a Gateway under `spec.resources`.

By default each instance is initialized with:

<table style="max-width: 300px">
	<col>
	<col >
	<col style="text-align: right">
	<thead>
		<th>Resource</th>
		<th>Requested</th>
		<th>Limit</th>
	</thead>
	<tr>
		<td>Memory</td>
		<td style="text-align: right">256Mi</td>
		<td style="text-align: right">512Mi</td>
	</tr>
	<tr>
		<td>CPU</td>
		<td style="text-align: right">500m</td>
		<td style="text-align: right">2</td>
	</tr>
</table>

But you can change it as seen in the example below.
Note that less than the required may cause issues and is not recommended.

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: resources: requests: memory: "512Mi" cpu: "1" limits: memory: "1Gi" cpu: "2"


## <a id="probes"></a>Configuring Probes

Similarly to other Kubernetes resources, you can optionally configure the `livenessProbe`, `readinessProbe`, and  `startupProbe`, for a Gateway.

By default each instance is initialized with:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: livenessProbe: initialDelaySeconds: 5 failureThreshold: 10 periodSeconds: 3 timeoutSeconds: 1 successThreshold: 1 readinessProbe: initialDelaySeconds: 5 failureThreshold: 10 periodSeconds: 3 timeoutSeconds: 1 successThreshold: 1 startupProbe: initialDelaySeconds: 10 failureThreshold: 30 periodSeconds: 3 timeoutSeconds: 1 successThreshold: 1


But you can change them in order to better match your requirements.

## <a id="observability"></a>Configure Observability

Spring Cloud Gateway for Kubernetes can be configured expose tracing and to generate a set of metrics and tracings based on different monitoring signals
to help with understanding behaviour in aggregate.

<p class="note">
  <strong>Note</strong>: Metrics and Tracing are independent from each other.
</p>

### <a id="observability-metrics-wavefront"></a>Exposing Metrics to Wavefront

To expose metrics to [Wavefront](https://tanzu.vmware.com/observability) we need to create a `Secret` with the following
data: `wavefront.api-token` and `wavefront.uri`, representing Wavefront's API token and Wavefront's URI endpoint
respectively. For example:

apiVersion: v1 kind: Secret metadata: name: metrics-wavefront-secret data: wavefront.api-token: "NWU3ZCFmNjYtODlkNi00N2Y5LWE0YTMtM2U3OTVmM2Y3MTZk" wavefront.uri: "aHR0cHM6Ly92bAdhcmUud2F2ZWZyb250LmNvbQ=="


Then, in the `SpringCloudGateway` kind, reference the secret created in the step before under the `metrics` section. For
example:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: test-gateway-metrics spec: observability: metrics: wavefront: enabled: true wavefront: secret: metrics-wavefront-secret source: my-source application: my-shopping-application service: gateway-service


After applying the configuration, Wavefront will start receiving the metrics provided by default
by [Spring Cloud Gateway](https://cloud.spring.io/spring-cloud-gateway/reference/html/).

<p class="note"><strong>Note: </strong> If you are also using wavefront for tracing, ensure you specify the same
secret and source in both specs.</p>

#### <a id="observability-metrics-wavefront-dashboard"></a>Using the Spring Cloud Gateway for Kubernetes Dashboard for Wavefront

Spring Cloud Gateway for Kubernetes has a pre-built dashboard you can use in Wavefront.

If you are using [VMware's Wavefront](https://vmware.wavefront.com), then you can [clone and customize](https://docs.wavefront.com/ui_dashboards.html) the already created [Spring Cloud Gateway for Kubernetes Dashboard](https://vmware.wavefront.com/dashboards/Spring-Cloud-Gateway-for-Kubernetes).

Alternatively, you can find a `dashboards` folder inside `Spring Cloud Gateway for Kubernetes` release artifacts which contains a Wavefront template.

To import it, we need to [create an API Token](https://vmware.wavefront.com/userprofile/apiaccess) and execute the following command:

curl -XPOST 'https://vmware.wavefront.com/api/v2/dashboard' --header "Authorization: Bearer $" --header "Content-Type: application/json" -d "@wavefront-spring-cloud-gateway-for-kubernetes.json"


![Using the Spring Cloud Gateway for Kubernetes Dashboard for Wavefront](images/observability/metrics-wavefront.png)

### <a id="observability-metrics-prometheus"></a>Exposing Metrics to Prometheus

To expose metrics to [Prometheus](https://prometheus.io/) we need to add a prometheus section in the `SpringCloudGateway` kind and if we want scrapping annotations to be added into the gateway pods, for
example:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: test-gateway-metrics spec: observability: metrics: prometheus: enabled: true


After applying the configuration, the [Prometheus actuator](https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints) endpoint will be available.

If, in addition to this, we want the scrapping annotations to be added to all the Spring Cloud Gateway Pods, we should create our Prometheus connfigurations with `annotations` set to `true`, for example:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: test-gateway-metrics-with-annotations spec: observability: metrics: prometheus: enabled: true annotations: enabled: true


This will add the following annotations to every Spring Cloud Gateway Pod:

annotations: prometheus.io/scrape: "true" prometheus.io/path: "/actuator/prometheus" prometheus.io/port: "8090"


#### <a id="observability-metrics-grafana-dashboard"></a>Using the Spring Cloud Gateway for Kubernetes Dashboard for Grafana

You can find a `dashboards` folder inside `Spring Cloud Gateway for Kubernetes` release artifacts which contains a Grafana template.

To import it you can follow [the how to import guide](https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard).

![Using the Spring Cloud Gateway for Kubernetes Dashboard for Grafana](images/observability/metrics-grafana.png)

### <a id="observability-tracing"></a>Exposing Tracing to Wavefront

To expose tracing to [Wavefront](https://tanzu.vmware.com/observability) we need to create a `Secret` with the following
data: `wavefront.api-token` and `wavefront.uri`, representing Wavefront's API token and Wavefront's URI endpoint
respectively. For example:

apiVersion: v1 kind: Secret metadata: name: tracing-wavefront-secret data: wavefront.api-token: "NWU3ZCFmNjYtODlkNi00N2Y5LWE0YTMtM2U3OTVmM2Y3MTZk" wavefront.uri: "aHR0cHM6Ly92bAdhcmUud2F2ZWZyb250LmNvbQ=="


Then, in the `SpringCloudGateway` kind, reference the secret created in the step before under the `tracing` section. For
example:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: test-gateway-tracing spec: observability: tracing: wavefront: enabled: true wavefront: secret: tracing-wavefront-secret source: my-source application: my-shopping-application service: gateway-service


After applying the configuration, [Wavefront will start receiving the traces](https://docs.wavefront.com/tracing_basics.html)

![Exposing Tracing to Wavefront](images/observability/tracing-wavefront.png)

<p class="note"><strong>Note: </strong> If you are also using wavefront for metrics, ensure you specify the same
secret and source in both specs.</p>

### <a id="applying-labels"></a>Applying custom labels to the Gateway Pods

Custom labels can be added to the Gateway configuration. These labels will be propagated to the Pods created by the gateway operator
For example:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: test-gateway-tracing labels: test-label: test spec: count: 2


Then the Pods can be listed by specifying the label:

kubectl get pods -l test-label=test


## <a id="customizing-service-type"></a>Customizing the service type

By default, the gateway is exposed with a ClusterIP service. You can change the type to a NodePort or a LoadBalancer by specifying the <code>spec.service.type</code>.
You can also configure the exposed port by specifying <code>spec.service.port</code>. If not specified, the port will automatically be assigned.

For example:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: service: type: NodePort nodePort: 32222


Note, for local development, your cluster needs to be configured to expose your chosen <code>nodePort</code> before you can send traffic to the nodes from the host.

### <a id="using-pod-overrides"></a>Using podOverrides to customize the gateway

Using `podOverrides` you can customize the gateway pod using the specs from the Pod resource.
This can be used to set node selectors, affinity rules, volumes, init containers, and more on the gateway pod.
Volumes, containers, and init containers set via `podOverrides` will be combined with the ones set by the `scg-operator` service.

In addition, you can also customize the gateway container by adding the specs under a container named 'gateway'.
This can be used to configure probes, security context, resources, volume mounts, and more on the gateway container.
Environment variables and volume mounts set via `podOverrides` will be combined with the ones set by the `scg-operator` service.

In the example below, we specify:
- an init container for the gateway pod
- affinity rules for the gateway pod
- additional env variables for the gateway container
- a liveness probe for the gateway container
- a volume for the gateway pod, mounted to the gateway container

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: my-gateway spec: podOverrides: initContainers: - name: busybox-init image: busybox:1.28 command: [ 'sh', '-c', 'echo The app is running!' ] containers: - name: gateway env: - name: username value: admin - name: API_KEY valueFrom: secretKeyRef: name: application-api-key key: api_key optional: false livenessProbe: initialDelaySeconds: 5 failureThreshold: 12 periodSeconds: 4 timeoutSeconds: 2 successThreshold: 1 httpGet: port: 8090 path: actuator/health/liveness scheme: HTTP volumeMounts: - name: storage mountPath: /data/storage affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: myLabel operator: Exists topologyKey: k8s.io/hostname volumes: - name: storage emptyDir:


### <a id="horizontal-pod-autoscaler"></a>Scaling the gateway with a HorizontalPodAutoscaler

You can define a HorizontalPodAutoscaler to automatically scale the gateway on demand. A sample is provided below:

apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: my-gateway-hpa spec: minReplicas: 1 maxReplicas: 3 metrics:

  • type: Resource resource: name: cpu target: type: Utilization averageUtilization: 20 scaleTargetRef: apiVersion: tanzu.vmware.com/v1 kind: SpringCloudGateway name: my-gateway

This requires the [Kubernetes Metrics Server](https://github.com/kubernetes-sigs/metrics-server) installed on the cluster.

## <a id="secrets-providers"></a>Working with Secrets Providers

Spring Cloud Gateway for Kubernetes includes support for the [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) to pass secrets from a supported provider. The supported providers are:
- Google Secret Manager
- AWS Secrets Manager
- Azure Key Vault
- Hashicorp Vault

Only one secret provider instance can be provided at this time.

### <a id="secrets-providers-gsm"></a>Working with Google Secret Manager

Prerequisites:
- A GKE Cluster with [Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) enabled
- The [Secret Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html) installed on the cluster
- The [Google Secret Store CSI Driver provider](https://github.com/GoogleCloudPlatform/secrets-store-csi-driver-provider-gcp) installed on the cluster
- A GCP IAM Service Account with the <code>secretmanager.secretAccessor</code> and <code>secretmanager.viewer</code> roles.
- An instance of the <code>SecretProviderClass</code> in the same namespace as the gateway. For example:

    ```
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: my-gcp-secret
    spec:
      provider: gcp
      parameters:
        secrets: |
          - resourceName: "projects/my-project/secrets/db-password/versions/latest"
            path: "db-password"
    ```

Provide the name of the <code>SecretProviderClass</code>, as well as the GCP IAM Service Account email when defining the gateway spec:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: gateway spec: extensions: secretsProviders: - name: my-gcp-secret # must match SecretProviderClass name googleSecretManager: iamServiceAccount: gke-workload@my-project.iam.gserviceaccount.com # GCP IAM Service Account email


Alternatively, if you created a Kubernetes service account when you created the GCP IAM service account, you can provide it in the <code>spec.serviceAccount.name</code>.

In addition, if you need to run the gateway pods on specific nodes that use Workload Identity,
you can add the <code>iam.gke.io/gke-metadata-server-enabled: "true"</code> nodeSelector to the gateway via <code>spec.podOverrides.nodeSelector</code>.
For Autopilot clusters, omit the <code>nodeSelector</code> field. Autopilot rejects this nodeSelector because all nodes use Workload Identity.

The secrets will be mounted to <code>/mnt/secrets/secret-name</code>. You can use this in a custom extension:

String password = Files.readString(Path.of("/mnt/secrets/db-password"));


### <a id="secrets-providers-aws"></a>Working with AWS Secrets Manager

Prerequisites:
- An AWS Cluster
- The [Secret Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html) installed on the cluster
- The [AWS Secret Store CSI Driver provider](https://github.com/aws/secrets-store-csi-driver-provider-aws) installed on the cluster
- A secret in AWS Secrets Manager - take note of the secret's Amazon Resource Name (ARN)
- A policy to access the secret with the <code>secretsmanager:GetSecretValue</code> and <code>secretsmanager:DescribeSecret</code> permissions. Take note of the policy ARN.
- An IAM Role for the Kubernetes service account, with the policy attached. Take note of the role ARN.
- An instance of the <code>SecretProviderClass</code> in the same namespace as the gateway. For example:

    ```
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: my-aws-secret
    spec:
      provider: aws
      parameters:
        objects: |
              # Secret ARN
            - objectName: "arn:aws:secretsmanager:ca-central-1:111122223333:secret:my-secret-name"
              jmesPath:
                  - path: password
                    objectAlias: db-password
    ```

Provide the name of the <code>SecretProviderClass</code>, as well as the AWS IAM Role ARN when defining the gateway spec:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: gateway spec: extensions: secretsProviders: - name: my-aws-secret # must match SecretProviderClass name awsSecretsManager: # IAM Role ARN created above iamRoleArn: arn:aws:iam::111122223333:role/eksctl-my-eks-addon-iamserviceaccount-d-Role1-1ABCDEFGHI


Alternatively, if you created a Kubernetes service account when you created the AWS IAM role, you can provide it in the <code>spec.serviceAccount.name</code>.

The secrets will be mounted to <code>/mnt/secrets/secret-name</code>. You can use this in a custom extension:

String password = Files.readString(Path.of("/mnt/secrets/db-password"));


### <a id="secrets-providers-azure"></a>Working with Azure Key Vault

Prerequisites:
- A cluster with Azure Active Directory (Azure AD) pod-managed identities and
  [Azure Key Vault Provider for Secrets Store CSI Driver support](https://docs.microsoft.com/en-us/azure/aks/csi-secrets-store-driver) features enabled
- An Azure Key Vault and secret
- [A Managed Identity](https://docs.microsoft.com/en-us/azure/aks/use-azure-ad-pod-identity#create-an-identity)
- [Assign permissions](https://docs.microsoft.com/en-us/azure/aks/use-azure-ad-pod-identity#assign-permissions-for-the-managed-identity) to the managed identity
- [A Pod Identity](https://docs.microsoft.com/en-us/azure/aks/use-azure-ad-pod-identity#create-a-pod-identity) tied to the managed identity
- [Assign permissions to the pod identity](https://docs.microsoft.com/en-us/azure/aks/csi-secrets-store-identity-access#usage) to access the keys, secrets, and/or certs in vault
- An instance of the <code>SecretProviderClass</code> in the same namespace as the gateway. For example:

    ```
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: my-azure-secret
    spec:
      provider: azure
      parameters:
        usePodIdentity: "true"                                         # Set to true for using managed identity
        userAssignedIdentityID: 068afe91-0aaf-4973-8ed8-33b3d333a69b   # Set the clientID of the user-assigned managed identity to use
        keyvaultName: my-key-vault                                     # Set to the name of your Azure key vault
        objects:  |
          array:
            - |
              objectName: db-password
              objectType: secret                                       # object types: secret, key, or cert
        tenantId: 0c29feca-cadb-4708-98dd-04d49a42bc5d                 # tenant id of the key vault
    ```


Provide the name of the <code>SecretProviderClass</code>, as well as the Azure AD Pod Identity when defining the gateway spec:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: gateway spec: extensions: secretsProviders: - name: my-azure-secret # must match SecretProviderClass name azureKeyVault: aadpodidbinding: my-pod-identity # Azure AD Pod Identity


The secrets will be mounted to <code>/mnt/secrets/secret-name</code>. You can use this in a custom extension:

String password = Files.readString(Path.of("/mnt/secrets/db-password"));


### <a id="secrets-providers-vault"></a>Working with Hashicorp Vault

The Secret Provider CSI is an alternate way of authenticating and retrieving secrets than using the Vault Agent Injector.

Prerequisites:
- [Install Vault with CSI enabled](https://learn.hashicorp.com/tutorials/vault/kubernetes-secret-store-driver#install-the-vault-helm-chart)
- [A secret added to Vault](https://learn.hashicorp.com/tutorials/vault/kubernetes-secret-store-driver#set-a-secret-in-vault)
- [Enable Kubernetes Authentication](https://learn.hashicorp.com/tutorials/vault/kubernetes-secret-store-driver#configure-kubernetes-authentication)
- A Vault policy with read access to the secret
- A Kubernetes authentication role, with the Vault policy, bound to the service account name and namespace of the gateway
- The [Secret Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html) installed on the cluster
- An instance of the <code>SecretProviderClass</code> in the same namespace as the gateway. For example:
    ```
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: my-vault-secret
    spec:
      provider: vault
      parameters:
        vaultAddress: "http://vault.vault:8200"      # In the form: http://vault.{vault-install-namespace}:8200
        roleName: "gateway"                          # vault role
        objects: |
          - objectName: "db-password"                # appears as /mnt/secrets/db-password
            secretPath: "secret/data/db-password"    # path in vault
            secretKey: "password
    ```

Provide the name of the <code>SecretProviderClass</code> when defining the gateway spec:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: gateway spec: extensions: secretsProviders: - name: my-vault-secret # no additional configuration required, must match SecretProviderClass name


The secrets will be mounted to <code>/mnt/secrets/secret-name</code>. You can use this in a custom extension:

String password = Files.readString(Path.of("/mnt/secrets/db-password"));


## <a id="path-length-config"></a>Configuring Path predicates to match on more specific paths first

By default, if you have multiple routes using similar Path predicates, e.g. `Path=/org/**` and `Path=/org/users/**`,
Spring Cloud Gateway for Kubernetes would route to the first matching Path predicate, rather than the more specific path.
You can use the `order` field to prioritize specific routes, however it still might be difficult to coordinate the correct order,
especially if different teams manage the routes.

Alternatively, Spring Cloud Gateway for Kubernetes provides an environment variable to route by more specific path:

spring.cloud.gateway.k8s.route.order=pathlength


By setting this flag on the gateway, it will order the routes by the more specific path.

<strong>Note the following behavior:</strong>
- With this flag, the paths are ordered by the first path in the Path predicate.
  If multiple paths are provided in the Path predicate, e.g. `Path=/org/**,/abc/123/**` and `Path=/org/users/**,/abc/**`,
  internally, it would be sorted as `Path=/org/users/**,/abc/**`, followed by `Path=/org/**,/abc/123/**`.
  As such, a request to `/abc/123`, would match on `Path=/org/users/**,/abc/**`.
- Order precedes the path specificity. A route with a higher order and less specific path will match before a route with a lower order precedence and more specific path.

## <a id="json-to-grpc-config"></a>Configuring the JSON to gRPC Filter

Spring Cloud Gateway OSS contains a filter to automatically transform a [JSON request into to gRPC request](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-jsontogrpc-gatewayfilter-factory) transparently for the client.
This filter can be configured with the following route configuration:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGatewayRouteConfig metadata: name: test-gateway-grpc-routes spec: routes: - uri: https://test-grpc-server-service predicates: - Path=/json/hello filters: - JsonToGrpc=file:proto-file/hello.pb,file:proto-file/hello.proto,HelloService,hello


Since gRPC is based on HTTP/2 it is a good practice to secure the gateway application via TLS. A complete configuration requires configuring both the certificate to connect to the gRPC service and the keystore to expose the gateway HTTP endpoint.
If your gateway access is not secured (for example, TLS is treated in another layer like ingress) you can ignore the `server.ssl.*` properties from the example.
In order for the gateway to have access to the protobuf definition files, the public certificate, and, for example, the key store. It can be configured the following way:

apiVersion: "tanzu.vmware.com/v1" kind: SpringCloudGateway metadata: name: test-gateway-grpc spec: env: - name: "spring.cloud.gateway.httpclient.ssl.trusted-x509-certificates" value: "file:ssl-files/public.cert"

- name: "server.ssl.key-store-type"
  value: "PKCS12"
- name: "server.ssl.key-store"
  value: "file:ssl-files/keystore.p12"
- name: "server.ssl.key-store-password"
  value: "password"

- name: "server.http2.enabled"
  value: "true"

podOverrides: containers: - name: gateway volumeMounts: - name: proto-file mountPath: /workspace/proto-file - name: ssl-files mountPath: /workspace/ssl-files volumes: - name: proto-file configMap: name: proto-file items: - key: hello.pb path: hello.pb - key: hello.proto path: hello.proto - name: ssl-files configMap: name: ssl-files items: - key: keystore.p12 path: keystore.p12 - key: public.cert path: public.cert

check-circle-line exclamation-circle-line close-line
Scroll to top icon