Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added _images/router_model.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions architecture/openshift_model.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
261 changes: 259 additions & 2 deletions architecture/routing.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
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 `*.<shard>`. 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
...

----