github.com/projectcontour/contour@v1.28.2/site/content/docs/v1.4.0/httpproxy.md (about) 1 # HTTPProxy Reference 2 3 <div id="toc" class="navigation"></div> 4 5 The [Ingress][1] object was added to Kubernetes in version 1.1 to describe properties of a cluster-wide reverse HTTP proxy. 6 Since that time, the Ingress object has not progressed beyond the beta stage, and its stagnation inspired an [explosion of annotations][2] to express missing properties of HTTP routing. 7 8 The goal of the `HTTPProxy` (previously `IngressRoute`) Custom Resource Definition (CRD) is to expand upon the functionality of the Ingress API to allow for a richer user experience as well addressing the limitations of the latter's use in multi tenent environments. 9 10 ## Key HTTPProxy Benefits 11 12 - Safely supports multi-team Kubernetes clusters, with the ability to limit which Namespaces may configure virtual hosts and TLS credentials. 13 - Enables including of routing configuration for a path or domain from another HTTPProxy, possibly in another Namespace. 14 - Accepts multiple services within a single route and load balances traffic across them. 15 - Natively allows defining service weighting and load balancing strategy without annotations. 16 - Validation of HTTPProxy objects at creation time and status reporting for post-creation validity. 17 18 ## Ingress to HTTPProxy 19 20 A minimal Ingress object might look like: 21 22 ```yaml 23 # ingress.yaml 24 apiVersion: networking.k8s.io/v1beta1 25 kind: Ingress 26 metadata: 27 name: basic 28 spec: 29 rules: 30 - host: foo-basic.bar.com 31 http: 32 paths: 33 - backend: 34 serviceName: s1 35 servicePort: 80 36 ``` 37 38 This Ingress object, named `basic`, will route incoming HTTP traffic with a `Host:` header for `foo-basic.bar.com` to a Service named `s1` on port `80`. 39 Implementing similar behavior using an HTTPProxy looks like this: 40 41 {% highlight yaml linenos %} 42 # httpproxy.yaml 43 apiVersion: projectcontour.io/v1 44 kind: HTTPProxy 45 metadata: 46 name: basic 47 spec: 48 virtualhost: 49 fqdn: foo-basic.bar.com 50 routes: 51 - conditions: 52 - prefix: / 53 services: 54 - name: s1 55 port: 80 56 {% endhighlight %} 57 58 **Lines 1-5**: As with all other Kubernetes objects, an HTTPProxy needs apiVersion, kind, and metadata fields. 59 60 **Lines 7-8**: The presence of the `virtualhost` field indicates that this is a root HTTPProxy that is the top level entry point for this domain. 61 The `fqdn` field specifies the fully qualified domain name that will be used to match against `Host:` HTTP headers. 62 63 **Lines 9-14**: Each HTTPProxy **must** have one or more routes, each of which **must** have one or more services which will handle the HTTP traffic. In addition, each route **may** have one or more conditions to match against. 64 65 **Lines 12-14**: The `services` field is an array of named Service & Port combinations that will be used for this HTTPProxy path. 66 HTTP traffic will be sent directly to the Endpoints corresponding to the Service. 67 68 ## Interacting with HTTPProxies 69 70 As with all Kubernetes objects, you can use `kubectl` to create, list, describe, edit, and delete HTTPProxy CRDs. 71 72 Creating an HTTPProxy: 73 74 ```bash 75 $ kubectl create -f basic.httpproxy.yaml 76 httpproxy "basic" created 77 ``` 78 79 Listing HTTPProxies: 80 81 ```bash 82 $ kubectl get httpproxy 83 NAME AGE 84 basic 24s 85 ``` 86 87 Describing HTTPProxy: 88 89 ```bash 90 $ kubectl describe httpproxy basic 91 Name: basic 92 Namespace: default 93 Labels: <none> 94 API Version: projectcontour.io/v1 95 Kind: HTTPProxy 96 Metadata: 97 Cluster Name: 98 Creation Timestamp: 2019-07-05T19:26:54Z 99 Resource Version: 19373717 100 Self Link: /apis/projectcontour.io/v1/namespaces/default/httpproxy/basic 101 UID: 6036a9d7-8089-11e8-ab00-f80f4182762e 102 Spec: 103 Routes: 104 Conditions: 105 Prefix: / 106 Services: 107 Name: s1 108 Port: 80 109 Virtualhost: 110 Fqdn: foo-basic.bar.com 111 Events: <none> 112 ``` 113 114 Deleting HTTPProxies: 115 116 ```bash 117 $ kubectl delete httpproxy basic 118 httpproxy "basic" deleted 119 ``` 120 121 ## HTTPProxy API Specification 122 123 There are a number of [working examples][3] of HTTPProxy objects in the `examples/example-workload` directory. 124 125 We will use these examples as a mechanism to describe HTTPProxy API functionality. 126 127 ### Virtual Host Configuration 128 129 #### Fully Qualified Domain Name 130 131 Similar to Ingress, HTTPProxy support name-based virtual hosting. 132 Name-based virtual hosts use multiple host names with the same IP address. 133 134 ``` 135 foo.bar.com --| |-> foo.bar.com s1:80 136 | 178.91.123.132 | 137 bar.foo.com --| |-> bar.foo.com s2:80 138 ``` 139 140 Unlike Ingress, HTTPProxy only support a single root domain per HTTPProxy object. 141 As an example, this Ingress object: 142 143 ```yaml 144 # ingress-name.yaml 145 apiVersion: extensions/v1beta1 146 kind: Ingress 147 metadata: 148 name: name-example 149 spec: 150 rules: 151 - host: foo1.bar.com 152 http: 153 paths: 154 - backend: 155 serviceName: s1 156 servicePort: 80 157 - host: bar1.bar.com 158 http: 159 paths: 160 - backend: 161 serviceName: s2 162 servicePort: 80 163 ``` 164 165 must be represented by two different HTTPProxy objects: 166 167 ```yaml 168 # httpproxy-name.yaml 169 apiVersion: projectcontour.io/v1 170 kind: HTTPProxy 171 metadata: 172 name: name-example-foo 173 namespace: default 174 spec: 175 virtualhost: 176 fqdn: foo1.bar.com 177 routes: 178 - services: 179 - name: s1 180 port: 80 181 --- 182 apiVersion: projectcontour.io/v1 183 kind: HTTPProxy 184 metadata: 185 name: name-example-bar 186 namespace: default 187 spec: 188 virtualhost: 189 fqdn: bar1.bar.com 190 routes: 191 - services: 192 - name: s2 193 port: 80 194 ``` 195 196 #### TLS 197 198 HTTPProxy follows a similar pattern to Ingress for configuring TLS credentials. 199 200 You can secure a HTTPProxy by specifying a Secret that contains TLS private key and certificate information. 201 If multiple HTTPProxies utilize the same Secret, the certificate must include the necessary Subject Authority Name (SAN) for each fqdn. 202 203 Contour (via Envoy) requires that clients send the Server Name Indication (SNI) TLS extension so that requests can be routed to the correct virtual host. 204 Virtual hosts are strongly bound to SNI names. 205 This means that the Host header in HTTP requests must match the SNI name that was sent at the start of the TLS session. 206 207 Contour also follows a "secure first" approach. 208 When TLS is enabled for a virtual host, any request to the insecure port is redirected to the secure interface with a 301 redirect. 209 Specific routes can be configured to override this behavior and handle insecure requests by enabling the `spec.routes.permitInsecure` parameter on a Route. 210 211 The TLS secret must contain keys named tls.crt and tls.key that contain the certificate and private key to use for TLS, e.g.: 212 213 ```yaml 214 # ingress-tls.secret.yaml 215 apiVersion: v1 216 data: 217 tls.crt: base64 encoded cert 218 tls.key: base64 encoded key 219 kind: Secret 220 metadata: 221 name: testsecret 222 namespace: default 223 type: kubernetes.io/tls 224 ``` 225 226 The HTTPProxy can be configured to use this secret using `tls.secretName` property: 227 228 ```yaml 229 # httpproxy-tls.yaml 230 apiVersion: projectcontour.io/v1 231 kind: HTTPProxy 232 metadata: 233 name: tls-example 234 namespace: default 235 spec: 236 virtualhost: 237 fqdn: foo2.bar.com 238 tls: 239 secretName: testsecret 240 routes: 241 - services: 242 - name: s1 243 port: 80 244 ``` 245 246 If the `tls.secretName` property contains a slash, eg. `somenamespace/somesecret` then, subject to TLS Certificate Delegation, the TLS certificate will be read from `somesecret` in `somenamespace`. 247 See TLS Certificate Delegation below for more information. 248 249 The TLS **Minimum Protocol Version** a vhost should negotiate can be specified by setting the `spec.virtualhost.tls.minimumProtocolVersion`: 250 251 - 1.3 252 - 1.2 253 - 1.1 (Default) 254 255 #### Upstream TLS 256 257 A HTTPProxy can proxy to an upstream TLS connection by first annotating the upstream Kubernetes service with: `projectcontour.io/upstream-protocol.tls: "443,https"`. 258 This annotation tells Contour which port should be used for the TLS connection. 259 In this example, the upstream service is named `https` and uses port `443`. 260 Additionally, it is possible for Envoy to verify the backend service's certificate. 261 The service of an HTTPProxy can optionally specify a `validation` struct which has a mandatory `caSecret` key as well as an mandatory `subjectName`. 262 263 Note: If `spec.routes.services[].validation` is present, `spec.routes.services[].{name,port}` must point to a Service with a matching `projectcontour.io/upstream-protocol.tls` Service annotation. 264 265 ##### Sample YAML 266 267 ```yaml 268 apiVersion: projectcontour.io/v1 269 kind: HTTPProxy 270 metadata: 271 name: secure-backend 272 spec: 273 virtualhost: 274 fqdn: www.example.com 275 routes: 276 - services: 277 - name: service 278 port: 8443 279 validation: 280 caSecret: my-certificate-authority 281 subjectName: backend.example.com 282 ``` 283 284 ##### Error conditions 285 286 If the `validation` spec is defined on a service, but the secret which it references does not exist, Contour will reject the update and set the status of the HTTPProxy object accordingly. 287 This helps prevent the case of proxying to an upstream where validation is requested, but not yet available. 288 289 ```yaml 290 Status: 291 Current Status: invalid 292 Description: route "/": service "tls-nginx": upstreamValidation requested but secret not found or misconfigured 293 ``` 294 295 #### TLS Certificate Delegation 296 297 In order to support wildcard certificates, TLS certificates for a `*.somedomain.com`, which are stored in a namespace controlled by the cluster administrator, Contour supports a facility known as TLS Certificate Delegation. 298 This facility allows the owner of a TLS certificate to delegate, for the purposes of referencing the TLS certificate, permission to Contour to read the Secret object from another namespace. 299 300 The `TLSCertificateDelegation` resource defines a set of `delegations` in the `spec`. 301 Each delegation references a `secretName` from the namespace where the `TLSCertificateDelegation` is created as well as describing a set of `targetNamespaces` in which the certificate can be referenced. 302 If all namespaces should be able to reference the secret, then set `"*"` as the value of `targetNamespaces` (see example below). 303 304 ```yaml 305 apiVersion: projectcontour.io/v1 306 kind: TLSCertificateDelegation 307 metadata: 308 name: example-com-wildcard 309 namespace: www-admin 310 spec: 311 delegations: 312 - secretName: example-com-wildcard 313 targetNamespaces: 314 - example-com 315 - secretName: another-com-wildcard 316 targetNamespaces: 317 - "*" 318 --- 319 apiVersion: projectcontour.io/v1 320 kind: HTTPProxy 321 metadata: 322 name: www 323 namespace: example-com 324 spec: 325 virtualhost: 326 fqdn: foo2.bar.com 327 tls: 328 secretName: www-admin/example-com-wildcard 329 routes: 330 - services: 331 - name: s1 332 port: 80 333 ``` 334 335 In this example, the permission for Contour to reference the Secret `example-com-wildcard` in the `admin` namespace has been delegated to HTTPProxy objects in the `example-com` namespace. 336 Also, the permission for Contour to reference the Secret `another-com-wildcard` from all namespaces has been delegated to all HTTPProxy objects in the cluster. 337 338 ### Conditions 339 340 Each Route entry in a HTTPProxy **may** contain one or more conditions. 341 These conditions are combined with an AND operator on the route passed to Envoy. 342 343 Conditions can be either a `prefix` or a `header` condition. 344 345 #### Prefix conditions 346 347 For `prefix`, this adds a path prefix. 348 349 Up to one prefix condition may be present in any condition block. 350 351 Prefix conditions **must** start with a `/` if they are present. 352 353 #### Header conditions 354 355 For `header` conditions there is one required field, `name`, and five operator fields: `present`, `contains`, `notcontains`, `exact`, and `notexact`. 356 357 - `present` is a boolean and checks that the header is present. The value will not be checked. 358 359 - `contains` is a string, and checks that the header contains the string. `notcontains` similarly checks that the header does *not* contain the string. 360 361 - `exact` is a string, and checks that the header exactly matches the whole string. `notexact` checks that the header does *not* exactly match the whole string. 362 363 ### Routes 364 365 HTTPProxy must have at least one route or include defined. 366 Paths defined are matched using prefix conditions. 367 In this example, any requests to `multi-path.bar.com/blog` or `multi-path.bar.com/blog/*` will be routed to the Service `s2`. 368 All other requests to the host `multi-path.bar.com` will be routed to the Service `s1`. 369 370 ```yaml 371 # httpproxy-multiple-paths.yaml 372 apiVersion: projectcontour.io/v1 373 kind: HTTPProxy 374 metadata: 375 name: multiple-paths 376 namespace: default 377 spec: 378 virtualhost: 379 fqdn: multi-path.bar.com 380 routes: 381 - conditions: 382 - prefix: / # matches everything else 383 services: 384 - name: s1 385 port: 80 386 - conditions: 387 - prefix: /blog # matches `multi-path.bar.com/blog` or `multi-path.bar.com/blog/*` 388 services: 389 - name: s2 390 port: 80 391 ``` 392 393 In the following example, we match on headers and send to different services, with a default route if those do not match. 394 395 ```yaml 396 # httpproxy-multiple-headers.yaml 397 apiVersion: projectcontour.io/v1 398 kind: HTTPProxy 399 metadata: 400 name: multiple-paths 401 namespace: default 402 spec: 403 virtualhost: 404 fqdn: multi-path.bar.com 405 routes: 406 - conditions: 407 - header: 408 name: x-os 409 contains: ios 410 services: 411 - name: s1 412 port: 80 413 - conditions: 414 - header: 415 name: x-os 416 contains: android 417 services: 418 - name: s2 419 port: 80 420 - services: 421 - name: s3 422 port: 80 423 ``` 424 425 #### Multiple Upstreams 426 427 One of the key HTTPProxy features is the ability to support multiple services for a given path: 428 429 ```yaml 430 # httpproxy-multiple-upstreams.yaml 431 apiVersion: projectcontour.io/v1 432 kind: HTTPProxy 433 metadata: 434 name: multiple-upstreams 435 namespace: default 436 spec: 437 virtualhost: 438 fqdn: multi.bar.com 439 routes: 440 - services: 441 - name: s1 442 port: 80 443 - name: s2 444 port: 80 445 ``` 446 447 In this example, requests for `multi.bar.com/` will be load balanced across two Kubernetes Services, `s1`, and `s2`. 448 This is helpful when you need to split traffic for a given URL across two different versions of an application. 449 450 #### Upstream Weighting 451 452 Building on multiple upstreams is the ability to define relative weights for upstream Services. 453 This is commonly used for canary testing of new versions of an application when you want to send a small fraction of traffic to a specific Service. 454 455 ```yaml 456 # httpproxy-weight-shfiting.yaml 457 apiVersion: projectcontour.io/v1 458 kind: HTTPProxy 459 metadata: 460 name: weight-shifting 461 namespace: default 462 spec: 463 virtualhost: 464 fqdn: weights.bar.com 465 routes: 466 - services: 467 - name: s1 468 port: 80 469 weight: 10 470 - name: s2 471 port: 80 472 weight: 90 473 ``` 474 475 In this example, we are sending 10% of the traffic to Service `s1`, while Service `s2` receives the remaining 90% of traffic. 476 477 HTTPProxy weighting follows some specific rules: 478 479 - If no weights are specified for a given route, it's assumed even distribution across the Services. 480 - Weights are relative and do not need to add up to 100. If all weights for a route are specified, then the "total" weight is the sum of those specified. As an example, if weights are 20, 30, 20 for three upstreams, the total weight would be 70. In this example, a weight of 30 would receive approximately 42.9% of traffic (30/70 = .4285). 481 - If some weights are specified but others are not, then it's assumed that upstreams without weights have an implicit weight of zero, and thus will not receive traffic. 482 483 #### Request and Response Header Policies 484 485 Manipulating headers is also supported per-Service or per-Route. Headers can be set or 486 removed from the request or response as follows: 487 488 per-Service: 489 490 ```yaml 491 apiVersion: projectcontour.io/v1 492 kind: HTTPProxy 493 metadata: 494 name: header-manipulation 495 namespace: default 496 spec: 497 virtualhost: 498 fqdn: headers.bar.com 499 routes: 500 - services: 501 - name: s1 502 port: 80 503 requestHeadersPolicy: 504 set: 505 - name: X-Foo 506 value: bar 507 remove: 508 - X-Baz 509 responseHeadersPolicy: 510 set: 511 - name: X-Service-Name 512 value: s1 513 remove: 514 - X-Internal-Secret 515 ``` 516 517 per-Route: 518 519 ```yaml 520 apiVersion: projectcontour.io/v1 521 kind: HTTPProxy 522 metadata: 523 name: header-manipulation 524 namespace: default 525 spec: 526 virtualhost: 527 fqdn: headers.bar.com 528 routes: 529 - services: 530 - name: s1 531 port: 80 532 requestHeadersPolicy: 533 set: 534 - name: X-Foo 535 value: bar 536 remove: 537 - X-Baz 538 responseHeadersPolicy: 539 set: 540 - name: X-Service-Name 541 value: s1 542 remove: 543 - X-Internal-Secret 544 ``` 545 546 In these examples we are setting the header `X-Foo` with value `baz` on requests 547 and stripping `X-Baz`. We are then setting `X-Service-Name` on the response with 548 value `s1`, and removing `X-Internal-Secret`. 549 550 #### Traffic mirroring 551 552 Per route a service can be nominated as a mirror. 553 The mirror service will receive a copy of the read traffic sent to any non mirror service. 554 The mirror traffic is considered _read only_, any response by the mirror will be discarded. 555 556 This service can be useful for recording traffic for later replay or for smoke testing new deployments. 557 558 ```yaml 559 apiVersion: projectcontour.io/v1 560 kind: HTTPProxy 561 metadata: 562 name: traffic-mirror 563 namespace: default 564 spec: 565 virtualhost: 566 fqdn: www.example.com 567 routes: 568 - conditions: 569 - prefix: / 570 services: 571 - name: www 572 port: 80 573 - name: www-mirror 574 port: 80 575 mirror: true 576 ``` 577 578 #### Response Timeout 579 580 Each Route can be configured to have a timeout policy and a retry policy as shown: 581 582 ```yaml 583 # httpproxy-response-timeout.yaml 584 apiVersion: projectcontour.io/v1 585 kind: HTTPProxy 586 metadata: 587 name: response-timeout 588 namespace: default 589 spec: 590 virtualhost: 591 fqdn: timeout.bar.com 592 routes: 593 - timeoutPolicy: 594 response: 1s 595 idle: 10s 596 retryPolicy: 597 count: 3 598 perTryTimeout: 150ms 599 services: 600 - name: s1 601 port: 80 602 ``` 603 604 In this example, requests to `timeout.bar.com/` will have a response timeout policy of 1s. 605 This refers to the time that spans between the point at which complete client request has been processed by the proxy, and when the response from the server has been completely processed. 606 607 - `timeoutPolicy.response` This field can be any positive time period or "infinity". 608 The time period of **0s** will also be treated as infinity. 609 This timeout covers the time from the *end of the client request* to the *end of the upstream response*. 610 By default, Envoy has a 15 second value for this timeout. 611 More information can be found in [Envoy's documentation][4]. 612 - `timeoutPolicy.idle` This field can be any positive time period or "infinity". 613 The time period of **0s** will also be treated as infinity. 614 By default, there is no per-route idle timeout. 615 Note that the default connection manager idle timeout of 5 minutes will apply if this is not set. 616 617 TimeoutPolicy durations are expressed as per the format specified in the [ParseDuration documentation][5]. 618 Example input values: "300ms", "5s", "1m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". 619 The string 'infinity' is also a valid input and specifies no timeout. 620 621 More information can be found in [Envoy's documentation][6] 622 - `retryPolicy`: A retry will be attempted if the server returns an error code in the 5xx range, or if the server takes more than `retryPolicy.perTryTimeout` to process a request. 623 - `retryPolicy.count` specifies the maximum number of retries allowed. This parameter is optional and defaults to 1. 624 - `retryPolicy.perTryTimeout` specifies the timeout per retry. If this field is greater than the request timeout, it is ignored. This parameter is optional. 625 If left unspecified, `timeoutPolicy.request` will be used. 626 627 #### Load Balancing Strategy 628 629 Each route can have a load balancing strategy applied to determine which of its Endpoints is selected for the request. 630 The following list are the options available to choose from: 631 632 - `RoundRobin`: Each healthy upstream Endpoint is selected in round robin order (Default strategy if none selected). 633 - `WeightedLeastRequest`: The least request strategy uses an O(1) algorithm which selects two random healthy Endpoints and picks the Endpoint which has fewer active requests. Note: This algorithm is simple and sufficient for load testing. It should not be used where true weighted least request behavior is desired. 634 - `Random`: The random strategy selects a random healthy Endpoints. 635 636 More information on the load balancing strategy can be found in [Envoy's documentation][7]. 637 638 The following example defines the strategy for the route `/` as `WeightedLeastRequest`. 639 640 ```yaml 641 # httpproxy-lb-strategy.yaml 642 apiVersion: projectcontour.io/v1 643 kind: HTTPProxy 644 metadata: 645 name: lb-strategy 646 namespace: default 647 spec: 648 virtualhost: 649 fqdn: strategy.bar.com 650 routes: 651 - conditions: 652 - prefix: / 653 services: 654 - name: s1-strategy 655 port: 80 656 - name: s2-strategy 657 port: 80 658 loadBalancerPolicy: 659 strategy: WeightedLeastRequest 660 ``` 661 662 #### Session Affinity 663 664 Session affinity, also known as _sticky sessions_, is a load balancing strategy whereby a sequence of requests from a single client are consistently routed to the same application backend. 665 Contour supports session affinity on a per route basis with `loadBalancerPolicy` `strategy: Cookie`. 666 667 ```yaml 668 # httpproxy-sticky-sessions.yaml 669 apiVersion: projectcontour.io/v1 670 kind: HTTPProxy 671 metadata: 672 name: httpbin 673 namespace: default 674 spec: 675 virtualhost: 676 fqdn: httpbin.davecheney.com 677 routes: 678 - services: 679 - name: httpbin 680 port: 8080 681 loadBalancerPolicy: 682 strategy: Cookie 683 ``` 684 685 ##### Limitations 686 687 Session affinity is based on the premise that the backend servers are robust, do not change ordering, or grow and shrink according to load. 688 None of these properties are guaranteed by a Kubernetes cluster and will be visible to applications that rely heavily on session affinity. 689 690 Any perturbation in the set of pods backing a service risks redistributing backends around the hash ring. 691 692 #### Per route health checking 693 694 Active health checking can be configured on a per route basis. 695 Contour supports HTTP health checking and can be configured with various settings to tune the behavior. 696 697 During HTTP health checking Envoy will send an HTTP request to the upstream Endpoints. 698 It expects a 200 response if the host is healthy. 699 The upstream host can return 503 if it wants to immediately notify Envoy to no longer forward traffic to it. 700 It is important to note that these are health checks which Envoy implements and are separate from any other system such as those that exist in Kubernetes. 701 702 ```yaml 703 # httpproxy-health-checks.yaml 704 apiVersion: projectcontour.io/v1 705 kind: HTTPProxy 706 metadata: 707 name: health-check 708 namespace: default 709 spec: 710 virtualhost: 711 fqdn: health.bar.com 712 routes: 713 - conditions: 714 - prefix: / 715 healthCheckPolicy: 716 path: /healthy 717 intervalSeconds: 5 718 timeoutSeconds: 2 719 unhealthyThresholdCount: 3 720 healthyThresholdCount: 5 721 services: 722 - name: s1-health 723 port: 80 724 - name: s2-health 725 port: 80 726 ``` 727 728 Health check configuration parameters: 729 730 - `path`: HTTP endpoint used to perform health checks on upstream service (e.g. `/healthz`). It expects a 200 response if the host is healthy. The upstream host can return 503 if it wants to immediately notify downstream hosts to no longer forward traffic to it. 731 - `host`: The value of the host header in the HTTP health check request. If left empty (default value), the name "contour-envoy-healthcheck" will be used. 732 - `intervalSeconds`: The interval (seconds) between health checks. Defaults to 5 seconds if not set. 733 - `timeoutSeconds`: The time to wait (seconds) for a health check response. If the timeout is reached the health check attempt will be considered a failure. Defaults to 2 seconds if not set. 734 - `unhealthyThresholdCount`: The number of unhealthy health checks required before a host is marked unhealthy. Note that for http health checking if a host responds with 503 this threshold is ignored and the host is considered unhealthy immediately. Defaults to 3 if not defined. 735 - `healthyThresholdCount`: The number of healthy health checks required before a host is marked healthy. Note that during startup, only a single successful health check is required to mark a host healthy. 736 737 #### WebSocket Support 738 739 WebSocket support can be enabled on specific routes using the `enableWebsockets` field: 740 741 ```yaml 742 # httpproxy-websockets.yaml 743 apiVersion: projectcontour.io/v1 744 kind: HTTPProxy 745 metadata: 746 name: chat 747 namespace: default 748 spec: 749 virtualhost: 750 fqdn: chat.example.com 751 routes: 752 - services: 753 - name: chat-app 754 port: 80 755 - conditions: 756 - prefix: /websocket 757 enableWebsockets: true # Setting this to true enables websocket for all paths that match /websocket 758 services: 759 - name: chat-app 760 port: 80 761 ``` 762 763 #### Permit Insecure 764 765 A HTTPProxy can be configured to permit insecure requests to specific Routes. 766 In this example, any request to `foo2.bar.com/blog` will not receive a 301 redirect to HTTPS, but the `/` route will: 767 768 ```yaml 769 apiVersion: projectcontour.io/v1 770 kind: HTTPProxy 771 metadata: 772 name: tls-example-insecure 773 namespace: default 774 spec: 775 virtualhost: 776 fqdn: foo2.bar.com 777 tls: 778 secretName: testsecret 779 routes: 780 - services: 781 - name: s1 782 port: 80 783 - conditions: 784 - prefix: /blog 785 permitInsecure: true 786 services: 787 - name: s2 788 port: 80 789 ``` 790 791 #### Path Rewriting 792 793 HTTPProxy supports rewriting the HTTP request URL path prior to delivering the request to the backend service. 794 Rewriting is performed after a routing decision has been made, and never changes the request destination. 795 796 The `pathRewritePolicy` field specifies how the path prefix should be rewritten. 797 The `replacePrefix` rewrite policy specifies a replacement string for a HTTP request path prefix match. 798 When this field is present, the path prefix that the request matched is replaced by the text specified in the `replacement` field. 799 If the HTTP request path is longer than the matched prefix, the remainder of the path is unchanged. 800 801 ```yaml 802 apiVersion: projectcontour.io/v1 803 kind: HTTPProxy 804 metadata: 805 name: rewrite-example 806 namespace: default 807 spec: 808 virtualhost: 809 fqdn: rewrite.bar.com 810 routes: 811 - services: 812 - name: s1 813 port: 80 814 pathRewritePolicy: 815 replacePrefix: 816 - replacement: /new/prefix 817 ``` 818 819 The `replacePrefix` field accepts an array of possible replacements. 820 When more than one `replacePrefix` array element is present, the `prefix` field can be used to disambiguate which replacement to apply. 821 822 If no `prefix` field is present, the replacement is applied to all prefix matches made against the route. 823 If a `prefix` field is present, the replacement is applied only to routes that have an exactly matching [prefix condition](#prefix-conditions). 824 Specifying more than one `replacePrefix` entry is mainly useful when a HTTPProxy document is included into multiple parent documents. 825 826 ```yaml 827 apiVersion: projectcontour.io/v1 828 kind: HTTPProxy 829 metadata: 830 name: rewrite-example 831 namespace: default 832 spec: 833 virtualhost: 834 fqdn: rewrite.bar.com 835 routes: 836 - services: 837 - name: s1 838 port: 80 839 conditions: 840 - prefix: /v1/api 841 pathRewritePolicy: 842 replacePrefix: 843 - prefix: /v1/api 844 replacement: /app/api/v1 845 - prefix: / 846 replacement: /app 847 ``` 848 849 ### Header Policy 850 851 HTTPProxy supports rewriting the `Host` header after first handling a request and before proxying to an upstream service. 852 A common use-case for this is to use Contour to proxy to a resource outside the cluster referenced by an `externalName` service. 853 854 The `requestHeadersPolicy` supports a list of `Set` options that currently only supports rewriting `Host` headers defined via a `name` and `value`. 855 856 ```yaml 857 apiVersion: projectcontour.io/v1 858 kind: HTTPProxy 859 metadata: 860 name: header-rewrite-example 861 spec: 862 virtualhost: 863 fqdn: header.bar.com 864 routes: 865 - services: 866 - name: s1 867 port: 80 868 requestHeadersPolicy: 869 set: 870 - name: Host 871 value: external.dev 872 ``` 873 874 ### ExternalName 875 876 HTTPProxy supports routing traffic to service types `ExternalName`. 877 Contour looks at the `spec.externalName` field of the service and configures the route to use that DNS name instead of utilizing EDS. 878 879 There's nothing specific in the HTTPProxy object that needs to be configured other than referencing a service of type `ExternalName`. 880 881 NOTE: The ports are required to be specified. 882 883 ```yaml 884 # httpproxy-externalname.yaml 885 apiVersion: v1 886 kind: Service 887 metadata: 888 labels: 889 run: externaldns 890 name: externaldns 891 namespace: default 892 spec: 893 externalName: foo-basic.bar.com 894 ports: 895 - name: http 896 port: 80 897 protocol: TCP 898 targetPort: 80 899 type: ExternalName 900 ``` 901 902 #### Proxy to external resource 903 904 To proxy to another resource outside the cluster (e.g. A hosted object store bucket for example), configure that external resource in a service type `externalName`. 905 Then define a `requestHeadersPolicy` which replaces the `Host` header with the value of the external name service defined previously. 906 Finally, if the upstream service is served over TLS, set the `protocol` field on the service to `tls` or annotate the external name service with: `projectcontour.io/upstream-protocol.tls: 443,https` assuming your service had a port 443 and name `https`. 907 908 ## HTTPProxy inclusion 909 910 HTTPProxy permits the splitting of a system's configuration into separate HTTPProxy instances using **inclusion**. 911 912 Inclusion, as the name implies, allows for one HTTPProxy object to be included in another, optionally with some conditions inherited from the parent. 913 Contour reads the inclusion tree and merges the included routes into one big object internally before rendering Envoy config. 914 Importantly, the included HTTPProxy objects do not have to be in the same namespace, so this is functionally the same as the delegation feature of the now-deprecated IngressRoute. 915 916 Each tree of HTTPProxy starts with a root, the top level object of the configuration for a particular virtual host. 917 Each root HTTPProxy defines a `virtualhost` key, which describes properties such as the fully qualified name of the virtual host, TLS configuration, etc. 918 919 HTTPProxies included from the root must not contain a virtualhost key. 920 Root objects cannot include other roots either transitively or directly. 921 This permits the owner of an HTTPProxy root to allow the inclusion of a portion of the route space inside a virtual host, and to allow that route space to be further subdivided with inclusions. 922 Because the path is not necessarily used as the only key, the route space can be multi-dimensional. 923 924 ### Conditions and Inclusion 925 926 Like Routes, Inclusion may specify a set of [conditions][8]. 927 These conditions are added to any conditions on the routes included. 928 This process is recursive. 929 930 Conditions are sets of individual condition statements, for example `prefix: /blog` is the condition that the matching request's path must start with `/blog`. 931 When conditions are combined through inclusion Contour merges the conditions inherited via inclusion with any conditions specified on the route. 932 This may result in duplicates, for example two `prefix:` conditions, or two header match conditions with the same name and value. 933 To resolve this Contour applies the following logic. 934 935 - `prefix:` conditions are concatenated together in the order they were applied from the root object. For example the conditions, `prefix: /api`, `prefix: /v1` becomes a single `prefix: /api/v1` conditions. Note: Multiple prefixes cannot be supplied on a single set of Route conditions. 936 - Proxies with repeated identical `header:` conditions of type "exact match" (the same header keys exactly) are marked as "Invalid" since they create an un-routable configuration. 937 938 ### Configuring inclusion 939 940 Inclusion is a top-level part of the HTTPProxy `spec` element. 941 It requires one field, `name`, and has two optional fields: 942 943 - `namespace`. This will assume the included HTTPProxy is in the same namespace if it's not specified. 944 - a `conditions` block. 945 946 #### Within the same namespace 947 948 HTTPProxies can include other HTTPProxy objects in the namespace by specifying the name of the object and its namespace in the top-level `includes` block. 949 Note that `includes` is a list, and so it must use the YAML list construct. 950 951 In this example, the HTTPProxy `include-root` has included the configuration for paths matching `/service2` from the HTTPPRoxy named `service2` in the same namespace as `include-root` (the `default` namespace). 952 It's important to note that `service2` HTTPProxy has not defined a `virtualhost` property as it is NOT a root HTTPProxy. 953 954 ```yaml 955 # httpproxy-inclusion-samenamespace.yaml 956 apiVersion: projectcontour.io/v1 957 kind: HTTPProxy 958 metadata: 959 name: include-root 960 namespace: default 961 spec: 962 virtualhost: 963 fqdn: root.bar.com 964 includes: 965 # Includes the /service2 path from service2 in the same namespace 966 - name: www 967 namespace: default 968 conditions: 969 - prefix: /service2 970 routes: 971 - conditions: 972 - prefix: / 973 services: 974 - name: s1 975 port: 80 976 --- 977 apiVersion: projectcontour.io/v1 978 kind: HTTPProxy 979 metadata: 980 name: service2 981 namespace: default 982 spec: 983 routes: 984 - conditions: 985 - prefix: / # matches /service2 986 services: 987 - name: s2 988 port: 80 989 - conditions: 990 - prefix: /blog # matches /service2/blog 991 services: 992 - name: blog 993 port: 80 994 ``` 995 996 #### Virtualhost aliases 997 998 To present the same set of routes under multiple dns entries, for example www.example.com and example.com, including a service with a `prefix` condition of `/` can be used. 999 1000 ```yaml 1001 # httpproxy-inclusion-multipleroots.yaml 1002 --- 1003 apiVersion: projectcontour.io/v1 1004 kind: HTTPProxy 1005 metadata: 1006 name: multiple-root 1007 namespace: default 1008 spec: 1009 virtualhost: 1010 fqdn: bar.com 1011 includes: 1012 - name: main 1013 namespace: default 1014 --- 1015 apiVersion: projectcontour.io/v1 1016 kind: HTTPProxy 1017 metadata: 1018 name: multiple-root-www 1019 namespace: default 1020 spec: 1021 virtualhost: 1022 fqdn: www.bar.com 1023 includes: 1024 - name: main 1025 namespace: default 1026 --- 1027 apiVersion: projectcontour.io/v1 1028 kind: HTTPProxy 1029 metadata: 1030 name: main 1031 namespace: default 1032 spec: 1033 routes: 1034 - services: 1035 - name: s2 1036 port: 80 1037 ``` 1038 1039 #### Across namespaces 1040 1041 Inclusion can also happen across Namespaces by specifying a `namespace` in the `inclusion`. 1042 This is a particularly powerful paradigm for enabling multi-team Ingress management. 1043 1044 In this example, the root HTTPProxy has included configuration for paths matching `/blog` to the `blog` HTTPProxy object in the `marketing` namespace. 1045 1046 ```yaml 1047 # httpproxy-inclusion-across-namespaces.yaml 1048 --- 1049 apiVersion: projectcontour.io/v1 1050 kind: HTTPProxy 1051 metadata: 1052 name: namespace-include-root 1053 namespace: default 1054 spec: 1055 virtualhost: 1056 fqdn: ns-root.bar.com 1057 includes: 1058 # delegate the subpath, `/blog` to the IngressRoute object in the marketing namespace with the name `blog` 1059 - name: blog 1060 namespace: marketing 1061 conditions: 1062 - prefix: /blog 1063 routes: 1064 - services: 1065 - name: s1 1066 port: 80 1067 1068 --- 1069 apiVersion: projectcontour.io/v1 1070 kind: HTTPProxy 1071 metadata: 1072 name: blog 1073 namespace: marketing 1074 spec: 1075 routes: 1076 - services: 1077 - name: s2 1078 port: 80 1079 ``` 1080 1081 ### Orphaned HTTPProxy children 1082 1083 It is possible for HTTPProxy objects to exist that have not been delegated to by another HTTPProxy. 1084 These objects are considered "orphaned" and will be ignored by Contour in determining ingress configuration. 1085 1086 ### Restricted root namespaces 1087 1088 HTTPProxy inclusion allows for Administrators to limit which users/namespaces may configure routes for a given domain, but it does not restrict where root HTTPProxy may be created. 1089 Contour has an enforcing mode which accepts a list of namespaces where root HTTPProxy are valid. 1090 Only users permitted to operate in those namespaces can therefore create HTTPProxy with the `virtualhost` field. 1091 1092 This restricted mode is enabled in Contour by specifying a command line flag, `--root-namespaces`, which will restrict Contour to only searching the defined namespaces for root HTTPProxy. This CLI flag accepts a comma separated list of namespaces where HTTPProxy are valid (e.g. `--root-namespaces=default,kube-system,my-admin-namespace`). 1093 1094 HTTPProxy with a defined `virtualhost` field that are not in one of the allowed root namespaces will be flagged as `invalid` and will be ignored by Contour. 1095 1096 Additionally, when defined, Contour will only watch for Kubernetes secrets in these namespaces ignoring changes in all other namespaces. 1097 Proper RBAC rules should also be created to restrict what namespaces Contour has access matching the namespaces passed to the command line flag. 1098 An example of this is included in the [examples directory][1] and shows how you might create a namespace called `root-httproxies`. 1099 1100 > **NOTE: The restricted root namespace feature is only supported for HTTPProxy CRDs. 1101 > `--root-namespaces` does not affect the operation of `v1beta1.Ingress` objects** 1102 1103 ## TCP Proxying 1104 1105 HTTPProxy supports proxying of TLS encapsulated TCP sessions. 1106 1107 _Note_: The TCP session must be encrypted with TLS. 1108 This is necessary so that Envoy can use SNI to route the incoming request to the correct service. 1109 1110 ### TLS Termination at the edge 1111 1112 If `spec.virtualhost.tls.secretName` is present then that secret will be used to decrypt the TCP traffic at the edge. 1113 1114 ```yaml 1115 # httpproxy-tls-termination.yaml 1116 apiVersion: projectcontour.io/v1 1117 kind: HTTPProxy 1118 metadata: 1119 name: example 1120 namespace: default 1121 spec: 1122 virtualhost: 1123 fqdn: tcp.example.com 1124 tls: 1125 secretName: secret 1126 tcpproxy: 1127 services: 1128 - name: tcpservice 1129 port: 8080 1130 - name: otherservice 1131 port: 9999 1132 weight: 20 1133 ``` 1134 1135 The `spec.tcpproxy` key indicates that this _root_ HTTPProxy will forward the de-encrypted TCP traffic to the backend service. 1136 1137 ### TLS passthrough to the backend service 1138 1139 If you wish to handle the TLS handshake at the backend service set `spec.virtualhost.tls.passthrough: true` indicates that once SNI demuxing is performed, the encrypted connection will be forwarded to the backend service. 1140 The backend service is expected to have a key which matches the SNI header received at the edge, and be capable of completing the TLS handshake. This is called SSL/TLS Passthrough. 1141 1142 ```yaml 1143 # httpproxy-tls-passthrough.yaml 1144 apiVersion: projectcontour.io/v1 1145 kind: HTTPProxy 1146 metadata: 1147 name: example 1148 namespace: default 1149 spec: 1150 virtualhost: 1151 fqdn: tcp.example.com 1152 tls: 1153 passthrough: true 1154 tcpproxy: 1155 services: 1156 - name: tcpservice 1157 port: 8080 1158 - name: otherservice 1159 port: 9999 1160 weight: 20 1161 ``` 1162 1163 ### TCPProxy delegation 1164 1165 There can be at most one TCPProxy stanza per root HTTPProxy, however that TCPProxy does not need to be defined in the root HTTPProxy object. 1166 HTTPProxy authors can delegate the configuration of a TCPProxy to the TCPProxy configuration defined in a HTTPProxy child object. 1167 1168 ```yaml 1169 # httpproxy-parent-termination.yaml 1170 apiVersion: projectcontour.io/v1 1171 kind: HTTPProxy 1172 metadata: 1173 name: parent 1174 namespace: default 1175 spec: 1176 virtualhost: 1177 fqdn: tcp.example.com 1178 tls: 1179 secretName: secret 1180 tcpproxy: 1181 include: 1182 name: child 1183 namespace: app 1184 --- 1185 # httpproxy-child-termination.yaml 1186 apiVersion: projectcontour.io/v1 1187 kind: HTTPProxy 1188 metadata: 1189 name: child 1190 namespace: app 1191 spec: 1192 tcpproxy: 1193 services: 1194 - name: tcpservice 1195 port: 8080 1196 - name: otherservice 1197 port: 9999 1198 weight: 20 1199 ``` 1200 In this example `default/parent` delegates the configuration of the TCPProxy services to `app/child`. 1201 1202 #### TCP Proxy health checking 1203 1204 Active health checking can be configured on a per route basis. 1205 Contour supports TCP health checking and can be configured with various settings to tune the behavior. 1206 1207 During TCP health checking Envoy will send a connect-only health check to the upstream Endpoints. 1208 It is important to note that these are health checks which Envoy implements and are separate from any 1209 other system such as those that exist in Kubernetes. 1210 1211 ```yaml 1212 apiVersion: projectcontour.io/v1 1213 kind: HTTPProxy 1214 metadata: 1215 name: tcp-health-check 1216 namespace: default 1217 spec: 1218 virtualhost: 1219 fqdn: health.bar.com 1220 tcpproxy: 1221 healthCheckPolicy: 1222 intervalSeconds: 5 1223 timeoutSeconds: 2 1224 unhealthyThresholdCount: 3 1225 healthyThresholdCount: 5 1226 services: 1227 - name: s1-health 1228 port: 80 1229 - name: s2-health 1230 port: 80 1231 ``` 1232 1233 TCP Health check policy configuration parameters: 1234 1235 - `intervalSeconds`: The interval (seconds) between health checks. Defaults to 5 seconds if not set. 1236 - `timeoutSeconds`: The time to wait (seconds) for a health check response. If the timeout is reached the health check attempt will be considered a failure. Defaults to 2 seconds if not set. 1237 - `unhealthyThresholdCount`: The number of unhealthy health checks required before a host is marked unhealthy. Note that for http health checking if a host responds with 503 this threshold is ignored and the host is considered unhealthy immediately. Defaults to 3 if not defined. 1238 - `healthyThresholdCount`: The number of healthy health checks required before a host is marked healthy. Note that during startup, only a single successful health check is required to mark a host healthy. 1239 1240 ## Upstream Validation 1241 1242 When defining upstream services on a route, it's possible to configure the connection from Envoy to the backend endpoint to communicate over TLS. 1243 Two configuration items are required, a CA certificate and a `SubjectName` which are both used to verify the backend endpoint's identity. 1244 1245 The CA certificate bundle for the backend service should be supplied in a Kubernetes Secret. 1246 The referenced Secret must be of type "Opaque" and have a data key named `ca.crt`. 1247 This data value must be a PEM-encoded certificate bundle. 1248 1249 In addition to the CA certificate and the subject name, the Kubernetes service must also be annotated with a Contour specific annotation: `projectcontour.io/upstream-protocol.tls: <port>` ([see annotations section][9]) 1250 1251 _Note: This annotation is applied to the Service not the Ingress or HTTPProxy object._ 1252 1253 ```yaml 1254 apiVersion: projectcontour.io/v1 1255 kind: HTTPProxy 1256 metadata: 1257 name: blog 1258 namespace: marketing 1259 spec: 1260 routes: 1261 - services: 1262 - name: s2 1263 port: 80 1264 validation: 1265 caSecret: foo-ca-cert 1266 subjectName: foo.marketing 1267 ``` 1268 1269 ## Client Certificate Validation 1270 1271 It is possible to protect the backend service from unauthorized external clients by requiring the client to present a valid TLS certificate. 1272 Envoy will validate the client certificate by verifying that it is not expired and that a chain of trust can be established to the configured trusted root CA certificate. 1273 Only those requests with a valid client certificate will be accepted and forwarded to the backend service. 1274 1275 ```yaml 1276 apiVersion: projectcontour.io/v1 1277 kind: HTTPProxy 1278 metadata: 1279 name: with-client-auth 1280 spec: 1281 virtualhost: 1282 fqdn: www.example.com 1283 tls: 1284 secretName: secret 1285 clientValidation: 1286 caSecret: client-root-ca 1287 routes: 1288 - services: 1289 - name: s1 1290 port: 80 1291 ``` 1292 1293 The preceding example enables validation by setting the optional `clientValidation` attribute. 1294 Its mandatory attribute `caSecret` contains a name of an existing Kubernetes Secret that must be of type "Opaque" and have a data key named `ca.crt`. 1295 The data value of the key `ca.crt` must be a PEM-encoded certificate bundle and it must contain all the trusted CA certificates that are to be used for validating the client certificate. 1296 1297 ## Status Reporting 1298 1299 There are many misconfigurations that could cause an HTTPProxy or delegation to be invalid. 1300 To aid users in resolving these issues, Contour updates a `status` field in all HTTPProxy objects. 1301 In the current specification, invalid HTTPProxy are ignored by Contour and will not be used in the ingress routing configuration. 1302 1303 If an HTTPProxy object is valid, it will have a status property that looks like this: 1304 1305 ```yaml 1306 status: 1307 currentStatus: valid 1308 description: valid HTTPProxy 1309 ``` 1310 1311 If the HTTPProxy is invalid, the `currentStatus` field will be `invalid` and the `description` field will provide a description of the issue. 1312 1313 As an example, if an HTTPProxy object has specified a negative value for weighting, the HTTPProxy status will be: 1314 1315 ```yaml 1316 status: 1317 currentStatus: invalid 1318 description: "route '/foo': service 'home': weight must be greater than or equal to zero" 1319 ``` 1320 1321 Some examples of invalid configurations that Contour provides statuses for: 1322 1323 - Negative weight provided in the route definition. 1324 - Invalid port number provided for service. 1325 - Prefix in parent does not match route in delegated route. 1326 - Root HTTPProxy created in a namespace other than the allowed root namespaces. 1327 - A given Route of an HTTPProxy both delegates to another HTTPProxy and has a list of services. 1328 - Orphaned route. 1329 - Delegation chain produces a cycle. 1330 - Root HTTPProxy does not specify fqdn. 1331 - Multiple prefixes cannot be specified on the same set of route conditions. 1332 - Multiple header conditions of type "exact match" with the same header key. 1333 1334 [1]: https://kubernetes.io/docs/concepts/services-networking/ingress/ 1335 [2]: https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md 1336 [3]: {{< param github_url >}}/tree/{{page.version}}/examples/example-workload/httpproxy 1337 [4]: https://www.envoyproxy.io/docs/envoy/v1.11.2/api-v2/api/v2/route/route.proto.html#envoy-api-field-route-routeaction-timeout 1338 [5]: https://godoc.org/time#ParseDuration 1339 [6]: https://www.envoyproxy.io/docs/envoy/v1.11.2/api-v2/api/v2/route/route.proto.html#envoy-api-field-route-routeaction-idle-timeout 1340 [7]: https://www.envoyproxy.io/docs/envoy/v1.11.2/intro/arch_overview/upstream/load_balancing/overview 1341 [8]: #conditions 1342 [9]: {% link docs/{{page.version}}/annotations.md %}