Route Services

Page last updated:

This topic provides guidance for offering a service to a Cloud Foundry Application Runtime (CFAR) services marketplace. For information about consuming these services, see Manage App Requests with Route Services.

Note: Route services require Diego. Your deployment must use the Diego architecture or you must enable Diego for your app.

Introduction

CFAR app developers may wish to apply transformation or processing to requests before they reach an app. Common examples of use cases include authentication, rate limiting, and caching services. Route services are a kind of Marketplace service that developers can use to apply various transformations to app requests by binding an app’s route to a service instance. Through integrations with service brokers and, optionally, with the CFAR routing tier, providers can offer these services to developers with a familiar, automated, self-service, and on-demand user experience.

Architecture

CFAR supports the following three models for route services:

In each model, you configure a route service to process traffic addressed to an app.

Fully-Brokered Service

In the fully-brokered service model, the CFAR router receives all traffic to apps in the deployment before any processing by the route service. Developers can bind a route service to any app, and if an app is bound to a route service, the CFAR router sends its traffic to the service. After the route service processes requests, it sends them back to the load balancer in front of the CFAR router. The second time through, the CFAR router recognizes that the route service has already handled them, and forwards them directly to app instances.

Fully brokered

The route service can run inside or outside of CFAR, so long as it fulfills the Service Instance Responsibilities to integrate it with the CFAR router. A service broker publishes the route service to the CFAR marketplace, making it available to developers. Developers can then create an instance of the service and bind it to their apps with the following commands:

cf create-service BROKER-SERVICE-PLAN SERVICE-INSTANCE cf bind-route-service YOUR-APP-DOMAIN SERVICE-INSTANCE [--hostname HOSTNAME] [--path PATH]

Developers configure the service either through the service provider’s web interface or by passing arbitrary parameters to their cf create-service call through the -c flag.

Advantages:

  • Developers can use a Service Broker to dynamically configure how the route service processes traffic to specific apps.
  • Adding route services requires no manual infrastructure configuration.
  • Traffic to apps that do not use the service makes fewer network hops because requests for those apps do not pass through the route service.

Disadvantages:

  • Traffic to apps that use the route service makes additional network hops, as compared to the static model.

Static, Brokered Service

In the static, brokered service model, an operator installs a static routing service, which might be a piece of hardware, in front of the load balancer. The routing service runs outside of CFAR and receives traffic to all apps running in the CFAR deployment. The service provider creates a service broker to publish the service to the CFAR marketplace. As with a fully-brokered service, a developer can use the service by instantiating it with cf create-service and binding it to an app with cf bind-route-service.

Static, brokered

In this model, you configure route services on an app-by-app basis. When you bind a service to an app, the service broker directs the routing service to process that app’s traffic rather than pass the requests through unchanged.

Advantages:

  • Developers can use a service broker to dynamically configure how the route service processes traffic to specific apps.
  • Traffic to apps that use the route service takes fewer network hops.

Disadvantages:

  • Adding route services requires manual infrastructure configuration.
  • Traffic to apps that do not use the route service make unnecessary network hops. Requests for all apps hosted by the deployment pass through the route service component.

User-Provided Service

If a route service is not listed in the CFAR marketplace by a broker, a developer can still bind it to their app as a user-provided service. The service can run anywhere, either inside or outside of CFAR, but it must fulfill the integration requirements described in Service Instance Responsibilities. The service also needs to be reachable by an outbound connection from the CFAR router.

User-provided

This model is identical to the fully-brokered service model, except without the broker. Developers configure the service manually, outside of CFAR. They can then create a user-provided service instance and bind it to their app with the following commands, supplying the URL of their route service:

cf create-user-provided-service SERVICE-INSTANCE -r ROUTE-SERVICE-URL cf bind-route-service DOMAIN SERVICE-INSTANCE [--hostname HOSTNAME]

Advantages:

  • Adding route services requires no manual infrastructure configuration.
  • Traffic to apps that do not use the service makes fewer network hops because requests for those apps do not pass through the route service.

Disadvantages:

  • Developers must manually provision and configure route services out of the context of CFAR because no service broker automates these operations.
  • Traffic to apps that use the route service makes additional network hops, as compared to the static model.

Architecture Comparison

The models above require the broker and service instance responsibilities summarized in the following table:

Route Services Architecture Fulfills CFAR Service Instance Responsibilities Fulfills CFAR Broker Responsibilities
Fully-Brokered Yes Yes
Static Brokered No Yes
User-Provided Yes No

Enabling Route Services in CFAR

To enable support for route services in a CFAR deployment, the operator must provide a passphrase used by the Gorouter to encrypt a header that is sent with the request to the route service. The Gorouter uses this header to validate the request sent by the route service to the app route. The passphrase is configured in the cf-release manifest.
properties:
router:
route_services_secret: YOUR-SECRET-PASSPHRASE

Note: The route_services_secret property should be a robust passphrase. For more information, see the Gorouter spec in the cf-release repository on GitHub.

Route service instances should send requests to the value of x-cf-forwarded-url, obeying the scheme. The scheme is https by default. For environments that do not support TLS termination, this property can be set to false.
properties:
router:
route_services_recommend_https: true
The Gorouter only forwards requests to route services over SSL. By default, certificates provided by route services must be signed by a trusted CA. If they are not, the Gorouter rejects the request. In development environments, this concern may be unreasonable. To disable SSL certificate validation, modify the following property:
properties:
router:
ssl_skip_validation: true

Service Instance

The following applies only when a broker returns route_service_url in the bind response.

How It Works

Binding a service instance to a route associates the route_service_url with the route in the CFAR router. All requests for the route are proxied to the URL specified by route_service_url.

The CFAR router includes the X-CF-Forwarded-Url header containing the originally requested URL, as well as the X-CF-Proxy-Signature and X-CF-Proxy-Metadata headers used by the router to validate that the route-service sent the request. These headers are described in the Headers section, below.

Service Instance Responsibilities

The route service must handle requests by either:

  • Accepting the request by making a new request to the originally requested URL, or to another location, and then responding to the originating requestor.
  • Rejecting the request by responding with a non 2xx HTTP status code.

When forwarding a request to the originally requested URL, the route service must forward the X-CF-Forwarded-Url, X-CF-Proxy-Signature and X-CF-Proxy-Metadata headers on the request or it will be rejected. When forwarding a request to a location other than the originally requested URL, the route service should strip these headers.

Headers

The following HTTP headers are added by the Gorouter to requests forwarded to route services.

X-CF-Forwarded-Url

The X-CF-Forwarded-Url header contains the originally requested URL. The route service may choose to forward the request to this URL or to another.

X-CF-Proxy-Signature

When the Gorouter receives a request with this header, it will accept and forward the request to the app only if the URL of the request matches the one associated with the token, and if the request was received on time. Otherwise, the request is rejected.

X-CF-Proxy-Signature also signals to the Gorouter that a request has transited a route service. If this header is present, the Gorouter does not forward the request to a route service. The route-service needs to forward these headers in subsequent requests to the orignally requested URL, so that it knows not to send the request back to the route service but to the app. The headers should NOT be sent in the HTTP reponse to the GoRouter, only in the new HTTP request to the GoRouter.

Note: The X-CF-Proxy-Signature header is an access token. Anyone possessing your X-CF-Proxy-Signature token can bypass the route service. Treat this token as a secret that cannot be shared with anyone.

CF-hosted Route Services cannot be chained: If the route service forwards the request to a URL which resolves to a route for a different app on CFAR, the route must not have a bound route service. Otherwise, the request is rejected as the requested URL does not match the one in the forwarded X-CF-Proxy-Signature header.

X-CF-Proxy-Metadata

The X-CF-Proxy-Metadata header aids in the encryption and description of X-CF-Proxy-Signature.

SSL Certificates

When CFAR is deployed in a development environment, certificates hosted by the load balancer are self-signed, and not signed by a trusted Certificate Authority. When the route service finishes processing an inbound request and makes a call to the value of X-CF-Forwarded-Url, be prepared to accept the self-signed certificate when integrating with a non-production deployment of CFAR.

Timeouts

Route services must forward the request to the app route within the number of seconds configured by the router.route_service_timeout property. The router.route_service_timeout property defaults to 60 seconds.

In addition, all requests must respond in the number of seconds configured by the request_timeout_in_seconds property. The request_timeout_in_seconds property default to 900 seconds.

Timeouts are configurable for the router using the cf-release BOSH deployment manifest. For more information, see the spec.

Broker Responsibilities

Catalog Endpoint

Brokers must include requires: ["route_forwarding"] for a service in the catalog endpoint. If this is not present, CFAR does not permit users to bind an instance of the service to a route.

Binding Endpoint

When users bind a route to a service instance, CFAR sends a bind request to the broker, including the route address with bind_resource.route. A route is an address used by clients to reach apps mapped to the route. The broker may return route_service_url, containing a URL where CFAR should proxy requests for the route. This URL must have an https scheme, or the Cloud Controller rejects the binding. route_service_url is optional, and not returning this field enables a broker to dynamically configure a network component already in the request path for the route, requiring no change in the CFAR router.

For more information about bind requests, see the Binding section of the Open Service Broker API (v2.13) spec on GitHub.

Example Route Services

  • Logging Route Service: This route service can be pushed as an app to CFAR. It fulfills the service instance responsibilities above and logs requests received and sent. It can be used to see the route service integration in action by tailing its logs.

  • Rate Limiting Route Service: This example route service is a simple CFAR app that provides rate limiting to control the rate of traffic to an app.

  • Spring Boot Example: Logs requests received and sent, written in Spring Boot.

Tutorial

The following instructions show how to use the Logging Route Service described in Example Route Services to verify that when a route service is bound to a route, requests for that route are proxied to the route service.

For a video of this tutorial, see Route Services in Pivotal Cloud Foundry 1.7 on YouTube.

These commands requires the Cloud Foundry Command Line Interface (cf CLI) v6.16 or later.

To use the logging route service:

  1. Push the logging route service as an app by running:

    cf push logger
    
  2. Create a user-provided service instance, and include the route of the logging route service you pushed as route_service_url. Be sure to use https for the scheme. Run:

    cf create-user-provided-service mylogger -r https://logger.cf.example.com
    
  3. Push a sample app like Spring Music. By default, this creates a route spring-music.cf.example.com. Run:

    cf push spring-music
    
  4. Bind the user-provided service instance to the route of your sample app. The bind-route-service command takes a route and a service instance; the route is specified in the following example by domain cf.example.com and hostname spring-music. Run:

    cf bind-route-service cf.example.com mylogger --hostname spring-music
    
  5. Tail the logs for your route service by running:

    cf logs logger
    
  6. Send a request to the sample app and view in the route service logs that the request is forwarded to it by running:

    curl spring-music.cf.example.com
    

Security Considerations

The contract between route services and the Gorouter, applicable for fully-brokered and user-provided models, enables a CFAR operator to suggest whether or not requests forwarded from the route service to a load balancer are encrypted. The CFAR operator makes this suggestion by setting the router.route_services_recommend_https manifest property.

This suggestion does not allow the platform to guarantee that a route service obeys the scheme of the X-Forwarded-Url header. If a route service ignores the scheme and downgrades the request to plain text, a malicious actor can intercept the request and use or modify the data within it.

For increased security, follow these recommendations:

  • A load balancer terminating TLS should sanitize and reset X-Forwarded-Proto based on whether the request it received was encrypted or not. Set the router.sanitize_forwarded_proto: false manifest property for the Gorouter.

  • A load balancer configured for TCP passthrough should sanitize and reset the header based on whether the request it received was encrypted or not. Set the router.sanitize_forwarded_proto: true manifest property for the Gorouter.

For more information about securing traffic into CFAR, see Securing Traffic into CFAR.

Note: When a route service is mapped to a route, the Gorouter sanitizes the X-Forwarded-Proto header once, even though requests pass through the Gorouter more than once.

Recommendations for Securing Route Services

To best secure communications through route services, CFAR operators should:

  1. Set the router.route_services_recommended_https: true manifest property.

  2. Set the router.disable_http: true manifest property. Setting this property disables the HTTP listener, forcing all communication to the Gorouter to be HTTPS. This assumes all route services will communicate over HTTPS with the Gorouter. This causes requests from other clients made to port 80 to be rejected. You should confirm that clients of all apps make requests over TLS.

  3. Confirm that route services do not modify the value of the X-Forwarded-Proto header.

Create a pull request or raise an issue on the source for this page in GitHub