-
Notifications
You must be signed in to change notification settings - Fork 60
/
route-services.html.md.erb
491 lines (363 loc) · 19.1 KB
/
route-services.html.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
---
title: Offering route services
owner: Core Services
---
You can offer a service to a <%= vars.app_runtime_full %> (<%= vars.app_runtime_abbr %>) services
Marketplace.
For information about consuming these services, see
<% if vars.guide_name == 'Tile Developer' %>
[Managing apps and services using Apps Manager](https://docs.vmware.com/en/VMware-Tanzu-Application-Service/6.0/tas-for-vms/manage-apps.html).
<% else %>
[Managing App Requests with Route Services](../devguide/services/route-binding.html).
<% end %>
<% if vars.platform_code == 'CF' %>
<p> Route services require Diego. Your deployment must use the Diego architecture or you must enable Diego for your app.
</p>
<% end %>
<%= vars.app_runtime_abbr %> app developers might want to apply
transformation or processing to requests before they reach an
app. Common use cases include authentication, rate
limiting, and caching services.
Route services are a kind of
Marketplace service that you 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 <%= vars.app_runtime_abbr %> routing tier, providers can
offer these services with a familiar, automated,
self-service, and on-demand user experience.
<% if vars.platform_code != 'CF' && vars.guide_name == 'Tile Developer' %>
<p> The procedures in this topic use the Cloud Foundry Command Line Interface (cf CLI).
You can also manage route services using Apps Manager.
For more information, see the
<a href="https://docs.vmware.com/en/VMware-Tanzu-Application-Service/6.0/tas-for-vms/manage-apps.html">Route Services</a>
section of the <em>Managing Apps and Service Instances using Apps Manager</em> topic.
</p>
<% end %>
<% if vars.platform_code != 'CF' && vars.guide_name != 'Tile Developer' %>
<p> The procedures in this topic use the Cloud Foundry Command Line Interface (cf CLI).
You can also manage route services using Apps Manager.
For more information, see the
<a href="../console/manage-apps.html#manage-route-services">Manage Route Services</a>
section of the <em>Managing Apps and Service Instances Using Apps Manager</em> topic.
</p>
<% end %>
## <a name='architecture'></a> Architecture
<%= vars.app_runtime_abbr %> supports the following models for
route services, each of which is described in this topic:
* [Fully-brokered services](#fully-brokered)
* [Static, brokered services](#static-brokered)
* [User-provided services](#user-provided)
In each model, you configure a route service to process traffic
addressed to an app.
### <a name="fully-brokered"></a> Fully-brokered service
In the fully-brokered service model, the <%= vars.app_runtime_abbr %>
router receives all traffic to apps in the deployment before any
processing by the route service. You can bind a route service
to any app, and if an app is bound to a route service, the <%= vars.app_runtime_abbr %> router sends
the traffic to the
service. After the route service processes requests, it sends it
back to the load balancer in front of the <%= vars.app_runtime_abbr %>
router. The second time through, the <%= vars.app_runtime_abbr %>
router recognizes that the route service has already handled them, and
forwards them directly to app instances.
![Fully brokered service model](./images/route-services-fully-brokered.png)
The route service can run inside or outside of <%= vars.app_runtime_abbr %>, as long as it
fulfills the [Service Instance
responsibilities](#service-instance-responsibilities) to integrate it
with the <%= vars.app_runtime_abbr %> router.
A service broker
publishes the route service to the <%= vars.app_runtime_abbr %>
marketplace, and makes it available to developers.
You can then
create an instance of the service and bind it to your apps with the
following commands:
```console
cf create-service BROKER-SERVICE-PLAN SERVICE-INSTANCE
cf bind-route-service YOUR-APP-DOMAIN SERVICE-INSTANCE [--hostname HOSTNAME] [--path PATH]
```
You can configure the service either through the service provider web interface or by passing
<% if vars.guide_name == 'Tile Developer' %>
[arbitrary parameters](https://docs.vmware.com/en/VMware-Tanzu-Application-Service/6.0/tas-for-vms/services-managing-services.html#arbitrary-parameters)
<% else %>
[arbitrary parameters](../devguide/services/managing-services.html#arbitrary-params-create)
<% end %>
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.
### <a name="static-brokered"></a> 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 <%= vars.app_runtime_abbr %> and receives traffic
to all apps running in
the <%= vars.app_runtime_abbr %> deployment. The service provider
creates a service broker to publish the service to the <%= vars.app_runtime_abbr %> marketplace.
As with a fully-brokered
service, you can use the service by instantiating it with `cf
create-service` and binding it to an app with `cf bind-route-service`.
![Static brokered service model.](./images/route-services-static-brokered.png)
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 passing 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.
### <a name="user-provided"></a> User-provided service
If a route service is not listed in the <%= vars.app_runtime_abbr %>
marketplace by a broker, you can still bind it to your app as
a user provided service. The service can run anywhere, either inside
or outside of <%= vars.app_runtime_abbr %>, but it must fulfill the
integration requirements described in [Service Instance responsibilities](#service-instance-responsibilities).
The service also needs to be reachable by an outbound connection from the <%= vars.app_runtime_abbr %> router.
![Bound to your app as user provided service.](./images/route-services-user-provided.png)
This model is identical to the fully-brokered service model, except
without the broker. You can configure the service manually, outside
of <%= vars.app_runtime_abbr %>.
You can then create a user provided
service instance and bind it to your app with the following commands,that supply the URL of their route
service:
```console
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:**
* You must manually provision and configure route services out
of the context of <%= vars.app_runtime_abbr %> 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.
### <a name="architecture-comparison"></a> Architecture comparison
The previous models require the broker and service instance
responsibilities summarized in the following table:
<table class=“table”>
<thead>
<tr>
<th>Route Services Architecture</th>
<th>Fulfills <%= vars.app_runtime_abbr %> <br>Service Instance Responsibilities (1)</th>
<th>Fulfills <%= vars.app_runtime_abbr %> <br>Broker Responsibilities (2)</th>
</tr></thead><tr>
<td>Fully-Brokered</td>
<td>Yes</td>
<td>Yes</td>
</tr><tr>
<td>Static Brokered</td>
<td>No</td>
<td>Yes</td>
</tr><tr>
<td>User-Provided</td>
<td>Yes</td>
<td>No</td>
</tr>
</table>
1 - See <a href="#service-instance-responsibilities">Service Instance Responsibilities</a>
2 - See <a href="#broker-responsibilities">Broker Responsibilities</a>
## <a name='service-instance'></a> Service instance
The following information applies only when a broker returns `route_service_url`
in a bind response.
Binding a service instance to a route associates the
`route_service_url` with the route in the <%= vars.app_runtime_abbr %>
router. All requests for the route are proxied to the URL specified by
`route_service_url`.
The <%= vars.app_runtime_abbr %> 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](#headers) section.
### <a name='service-instance-responsibilities'></a> Service instance responsibilities
The route service must handle requests by either:
* Accepting the request, making a new request to the original
requested URL, or to another location, and then responding to the
original 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. If it doesn't, it is rejected.
When forwarding a request to a location other than the originally
requested URL, the route service strips these headers.
### <a name='headers'></a> 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 might 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 accepts
and forwards the request to the app only if the URL of the request
matches the one associated with the token, and 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 orignal
requested URL, so that it knows not to send the request back to the
route service but to the app. The headers must NOT be sent in the
HTTP response to the GoRouter, only in the new HTTP request to the
GoRouter.
CF-hosted Route Services cannot be chained: If the route service
forwards the request to a URL to resolve a route for a
different app on <%= vars.app_runtime_abbr %>, 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.
>**Important**
>The <code>X-CF-Proxy-Signature</code> header is
>an <strong>access token</strong>. Anyone possessing your <code>X-CF-Proxy-Signature</code>
>token can bypass the route service. Do not share your your <code>X-CF-Proxy-Signature</code>
>token with anyone.
#### X-CF-Proxy-Metadata
The `X-CF-Proxy-Metadata` header aids in the encryption and
description of `X-CF-Proxy-Signature`.
### <a name='ssl-certs'></a> SSL certificates
When <%= vars.app_runtime_abbr %> 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 <%= vars.app_runtime_abbr %>.
### <a name='timeouts'></a> Timeouts
<% if vars.platform_code == 'CF' %>
Route services must forward the
request to the app route within the number of seconds configured by
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 (defaults to 900 seconds).
Timeouts are configurable for the router using the cf-release BOSH
deployment manifest. For more information, see the [spec](https://github.com/cloudfoundry/routing-release/blob/master/jobs/gorouter/spec).
<% else %>
Route services must forward the request to the app route
within 60 seconds.
In addition, all requests must respond in 900 seconds.
<% end %>
## <a name='broker-responsibilities'></a> Broker responsibilities
### <a name='catalog'></a> Catalog endpoint
Brokers must include `requires: ["route_forwarding"]` for a service in
the catalog endpoint. If this is not present, <%= vars.app_runtime_abbr %> does not permit users to bind an instance of
the service to a route.
### <a name='binding'></a> Binding endpoint
When you bind a route to a service instance, <%= vars.app_runtime_abbr %> 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 might
return `route_service_url`, containing a URL where <%= vars.app_runtime_abbr %> proxies 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
allows a broker to dynamically configure a network component already
in the request path for the route, requiring no change in the <%= vars.app_runtime_abbr %> router.
For more information about bind requests, see the
[Binding](https://github.com/openservicebrokerapi/servicebroker/blob/v2.13/spec.md#binding) section of the _Open Service Broker API
(v2.13)_ specification on GitHub.
## <a name='examples'></a> Route services examples
* [Logging Route Service](https://github.com/cloudfoundry/cf-acceptance-tests/tree/release-candidate/assets/logging-route-service):
This route service can be pushed as an app to <%= vars.app_runtime_abbr %>. It fulfills the service instance
responsibilities 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](https://github.com/cloudfoundry-samples/ratelimit-service):
This example route service is a simple <%= vars.app_runtime_abbr %>
app that provides rate limiting to control the rate of traffic to an
app.
* [Spring Boot examples](https://github.com/in28minutes/spring-boot-examples).
## <a name='tutorial'></a> Tutorial
The following instructions show how to use the Logging Route
Service described in [Route Services examples](#examples) 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](https://youtu.be/VaaZJE2E4jI) on YouTube.
These commands require 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:
```console
cf push logger
```
1. Create a user provided service instance, and include the route of
the logging route service you pushed as `route_service_url`. Make sure
to use `https` for the scheme.
Run:
```console
cf create-user-provided-service mylogger -r https://logger.cf.example.com
```
1. Push a sample app such as [Spring
Music](https://github.com/cloudfoundry-samples/spring-music). By
default, this creates a route `spring-music.cf.example.com`.
Run:
```
cf push spring-music
```
1. 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:
```console
cf bind-route-service cf.example.com mylogger --hostname spring-music
```
1. Tail the logs for your route service by running:
```
cf logs logger
```
1. Send a request to the sample app and view in the route service logs
that the request is forwarded to it by running:
```console
curl spring-music.cf.example.com
```
<% if vars.platform_code == 'CF' %>
## <a name='security-considerations'></a> Security considerations
The contract between route services and the Gorouter, applicable for
fully-brokered and user-provided models, allows a <%= vars.app_runtime_abbr %> operator to suggest
whether or not requests
forwarded from the route service to a load balancer are encrypted. The
<%= vars.app_runtime_abbr %> 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, the requester can intercept, and use, or edit the data
within it.
For increased security, follow these recommendations:
* A load balancer stops TLS and can 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 can 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.
When a route service is mapped
to a route, the Gorouter sanitizes the <code>X-Forwarded-Proto</code>
header once, even though requests pass through the Gorouter more than
once.
For more information about
securing traffic into <%= vars.app_runtime_abbr %>, see [Securing Traffic into <%= vars.app_runtime_abbr %>](../adminguide/securing-traffic.html).
## <a name='secure-route-services'></a> Recommendations for securing route services
To best secure communications through route services, <%= vars.app_runtime_abbr %> operators:
1. Set the `router.route_services_recommend_https: true` manifest
property.
1. Set the `router.disable_http: true` manifest property. Setting this
property deactivates the HTTP listener, and forces all communication to the
Gorouter to be HTTPS. This assumes all route services communicate
over HTTPS with the Gorouter. This causes requests from other clients
made to port 80 to be rejected. You must confirm that clients of all
apps make requests over TLS.
1. Confirm that route services do not change the value of the
`X-Forwarded-Proto` header.
<% end %>