diff --git a/_images/router_model.png b/_images/router_model.png new file mode 100644 index 000000000000..1d25fd816a0e Binary files /dev/null and b/_images/router_model.png differ diff --git a/architecture/openshift_model.adoc b/architecture/openshift_model.adoc index 2965cefc4757..a71a5e61702d 100644 --- a/architecture/openshift_model.adoc +++ b/architecture/openshift_model.adoc @@ -317,6 +317,24 @@ Sample Template: ---- == Route +An OpenShift route is a way to announce your service to the world. A route, consumed by a router in conjunction with + service endpoints provides named connectivity from external sources to your applications. Each route provides a name, service + selector, and optionally security configuration. + +Sample Route: + +---- +{ + "kind": "Route", + "apiVersion": "v1beta1", + "metadata": { + "name": "route-unsecure" + }, + "id": "route-unsecure", + "host": "www.example.com", + "serviceName": "hello-nginx" +} +---- == Project diff --git a/architecture/routing.adoc b/architecture/routing.adoc index 0eee4c5fde73..9a3093e0831f 100644 --- a/architecture/routing.adoc +++ b/architecture/routing.adoc @@ -10,6 +10,263 @@ toc::[] == Overview -Routers provide external DNS mapping and load balancing to services over protocols that pass distinguishing information directly to the router (HTTP, HTTPS, and TLS with SNI). Routers subscribe to configuration changes and automatically update themselves with new configuration, and routers may be containerized or virtual (converting those changes to API calls to a system like an F5). +Routers provide external DNS mapping and load balancing to services over protocols that pass distinguishing information +directly to the router (HTTP, HTTPS, and TLS with SNI). Routers subscribe to configuration changes and automatically +update themselves with new configuration, and routers may be containerized or virtual (converting those changes to API calls to a system like an F5). -Other automatic capabilities exist to load balance individual services within the cluster exposed via configuration on link relations between services and would ensure a set of services would be available. Implementations may choose to implement these as local proxies per host, or to reuse the shared routing infrastructure. \ No newline at end of file +Other automatic capabilities exist to load balance individual services within the cluster exposed via configuration on +link relations between services and would ensure a set of services would be available. Implementations may choose to +implement these as local proxies per host, or to reuse the shared routing infrastructure. + +== Route Types +Routes come in two flavors: secure and unsecure. Secure routes provide the ability to use different types of TLS termination +to serve certificates to the client. When creating a route, specifying the TLS termination of the route indicates you are +creating a secure route. + + +Example unsecure route + +---- +{ + "kind": "Route", + "apiVersion": "v1beta1", + "metadata": { + "name": "route-unsecure" + }, + "id": "route-unsecure", + "host": "www.example.com", + "serviceName": "hello-nginx" +} +---- + + +Example secure route (using edge termination) + +---- +{ + "metadata": { + "name": "route-edge" + }, + "id": "route-edge", + "apiVersion": "v1beta1", + "kind": "Route", + "host": "www.example.com", + "serviceName": "hello-nginx", + "tls": { + "termination": "edge", + "certificate": "CERT TEXT OMITTED FOR READABILITY", + "key": "CERT TEXT OMITTED FOR READABILITY", + "caCertificate": "CERT TEXT OMITTED FOR READABILITY" + } +} +---- + +== Securing Routes +Creating a secure route to your pods can be accomplished by specifying the TLS Termination of the route and, optionally, +providing certificates to use. As of writing, OpenShift beta1 TLS termination relies on SNI for serving custom certificates (in the reference HAProxy implementation). +Any non-SNI traffic received on port 443 will have TLS terminated with a generic certificate. In the future, the ability +to create custom frontends within the router will allow all traffic to serve custom certificates. + +There are three types of TLS termination: + +=== Edge Termination +Edge termination means that TLS termination occurs prior to traffic reaching the destination. TLS certificates are served by the frontend of the router. + +Edge termination is configured by setting `TLS.Termination` to edge on your route and by specifying the `CACertificatFile`, `CertificateFile` +and `KeyFile`. + +---- +{ + "metadata": { + "name": "route-edge" + }, + "id": "route-edge", + "apiVersion": "v1beta1", + "kind": "Route", + "host": "www.example.com", + "serviceName": "hello-nginx", + "tls": { + "termination": "edge", + "certificate": "CERT TEXT OMITTED FOR READABILITY", + "key": "CERT TEXT OMITTED FOR READABILITY", + "caCertificate": "CERT TEXT OMITTED FOR READABILITY" + } +} +---- + +=== Passthrough Termination +Passthrough termination is a mechanism to send encrypted traffic straight to the destination without the router providing TLS termination. + +Passthrough termination is configured by setting `TLS.Termination` to passthrough on your route. No other information is required. +The destination (such as an Nginx, Apache, or another HAProxy instance) will be responsible for serving certificates for the traffic. + +---- +{ + "metadata": { + "name": "route-secure" + }, + "id": "route-secure", + "apiVersion": "v1beta1", + "kind": "Route", + "host": "www.example.com", + "serviceName": "hello-nginx-secure", + "tls": { "termination" : "passthrough" } +} +---- + +=== Re-encryption Termination +Re-encryption is a special case of edge termination where the traffic is first decrypted with certificate A and then +re-encrypted with certificate B when sending the traffic to the destination. + +Re-encryption termination is configured by setting `TLS.Termination` to reencrypt and providing the `CertificateFile`, +`KeyFile`, the `CACertificateFile`, and a `DestinationCACertificateFile`. The edge certificates remain the same as in the edge +termination use case. The `DestinationCACertificateFile` is used in order to validate the secure connection from the router +to the destination (implemenation specific). + +---- +{ + "metadata": { + "name": "route-reencrypt" + }, + "id": "route-reencrypt", + "apiVersion": "v1beta1", + "kind": "Route", + "host": "www.example2.com", + "serviceName": "hello-nginx-secure", + "tls": { + "termination": "reencrypt", + "certificate": "CERT TEXT OMITTED FOR READABILITY", + "key": "CERT TEXT OMITTED FOR READABILITY", + "caCertificate": "CERT TEXT OMITTED FOR READABILITY", + "destinationCaCertificate": "CERT TEXT OMITTED FOR READABILITY" + } +} +---- + +=== Special Notes About Secure Routes + +At this point, password protected key files are not supported. HAProxy prompts you for a password when starting up and +does not have a way to automate this process. We will need a follow up for KeyPassPhrase. To remove a passphrase from a +keyfile you may run `openssl rsa -in passwordProtectedKey.key -out new.key` + +When creating a secure route you must include your certificate files as a single line of text. To do this you simply replace +the existing line breaks with `\\n`. Please note the double slash which is required by the json spec. + + +== Routers +Currently, there is a single type of router plugin available in OpenShift, a template router. A template router provides +some infrastructure to the underlying router implementation: + +* Provides a wrapper that watches endpoints and routes +* Saves endpoint and route data into a consumable form +* Passes the internal state to a configurable template and executes the template +* Calls a reload script + +Router plugins make the assumption that they can bind to host ports 80 and 443. This is to allow external traffic to be +routed to the host and subsequently through the router. Routers also assume that networking is setup such that the router +can access all other pods in the cluster. + +=== The HAProxy Template Router + +The HAProxy template router implementation is the reference implementation for a template router plugin. This router implementation +uses the `openshift/origin-haproxy-router` to run an HAProxy instance alongside the template router plugin. To help test +routes, an install script is provided in `hack/install-router.sh`. The route script requires two parameters, the router +id and the full url to the master. + +The script will attempt to create the router based on the generated json file if it can find the `osc` executable on the +path. If it cannot find the executable it will simply create the json file and notify the user of the location. You can +then manually run the create command. + +---- +[vagrant@openshiftdev origin]$ hack/install-router.sh router https://10.0.2.15:8443 +Creating router file and starting pod... +router +---- + +==== Data Flow + +The following diagram illustrates how data flows from the master through the plugin and finally into a HAProxy configuration. + +image:../../_images/router_model.png["HAProxy Router Data Flow",link="../../_images/router_model.png"] + +== HA Routers + +Highly available router setups can be accomplished by running multiple instances of the router pod and fronting them +with a balancing tier. This could be something as simple as DNS round robin or as complex as multiple load balancing layers. + +=== DNS Round Robin + +As a simple example, you may create a zone file for a DNS server like BIND that maps +multiple A records for a single domain name. When clients do a lookup they will be given one of the many records, in order, +as a round robin scheme. The files below illustrate an example of using wild card DNS with multiple A records to achieve +the desired round robin. The wild card could be further distributed into shards with `*.`. Finally, a test using +`dig` (available in the `bind-utils` package) is shown from the vagrant environment that shows multiple answers for the +same lookup. Doing multiple pings show the resolution swapping between IP addresses. + + + +---- +#### named.conf - add a new zone that points to your file + zone "v3.rhcloud.com" IN { + type master; + file "v3.rhcloud.com.zone"; + }; + + +#### v3.rhcloud.com.zone - contains the round robin mappings for the DNS lookup + $ORIGIN v3.rhcloud.com. + + @ IN SOA . v3.rhcloud.com. ( + 2009092001 ; Serial + 604800 ; Refresh + 86400 ; Retry + 1206900 ; Expire + 300 ) ; Negative Cache TTL + IN NS ns1.v3.rhcloud.com. + ns1 IN A 127.0.0.1 + * IN A 10.245.2.2 + IN A 10.245.2.3 + +#### Testing the entry + + + [vagrant@openshift-master ~]$ dig hello-openshift.shard1.v3.rhcloud.com + + ; <<>> DiG 9.9.4-P2-RedHat-9.9.4-16.P2.fc20 <<>> hello-openshift.shard1.v3.rhcloud.com + ;; global options: +cmd + ;; Got answer: + ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36389 + ;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 1, ADDITIONAL: 2 + ;; WARNING: recursion requested but not available + + ;; OPT PSEUDOSECTION: + ; EDNS: version: 0, flags:; udp: 4096 + ;; QUESTION SECTION: + ;hello-openshift.shard1.v3.rhcloud.com. IN A + + ;; ANSWER SECTION: + hello-openshift.shard1.v3.rhcloud.com. 300 IN A 10.245.2.2 + hello-openshift.shard1.v3.rhcloud.com. 300 IN A 10.245.2.3 + + ;; AUTHORITY SECTION: + v3.rhcloud.com. 300 IN NS ns1.v3.rhcloud.com. + + ;; ADDITIONAL SECTION: + ns1.v3.rhcloud.com. 300 IN A 127.0.0.1 + + ;; Query time: 5 msec + ;; SERVER: 10.245.2.3#53(10.245.2.3) + ;; WHEN: Wed Nov 19 19:01:32 UTC 2014 + ;; MSG SIZE rcvd: 132 + + [vagrant@openshift-master ~]$ ping hello-openshift.shard1.v3.rhcloud.com + PING hello-openshift.shard1.v3.rhcloud.com (10.245.2.3) 56(84) bytes of data. + ... + ^C + --- hello-openshift.shard1.v3.rhcloud.com ping statistics --- + 2 packets transmitted, 2 received, 0% packet loss, time 1000ms + rtt min/avg/max/mdev = 0.272/0.573/0.874/0.301 ms + [vagrant@openshift-master ~]$ ping hello-openshift.shard1.v3.rhcloud.com + ... + +----