diff options
Diffstat (limited to 'docs/operations.md')
| -rw-r--r-- | docs/operations.md | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/docs/operations.md b/docs/operations.md index fae3b6c..2fd8e7f 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -105,12 +105,32 @@ One node at a time, restarting each with its files. What to know: ## Behind a reverse proxy -The HTTP API speaks plain HTTP on `127.0.0.1:3000`; a reverse proxy in front adds TLS, -and can authenticate users itself (single sign-on, client certificates, its own -password file). It then names the user in a header, which the node believes from where -the proxy connects alone (`--user-header`, `--trusted-proxies`); requests from -elsewhere still need `--htpasswd`, which becomes optional. The proxy must set or clear -that header on every request, or a client could set it itself. +The HTTP API speaks plain HTTP on `127.0.0.1:3000`; a reverse proxy in front adds TLS. +Let the node check who users are, as it does: its `--htpasswd`, and the tokens of +logging in on any node of the swarm ([`access.md`](access.md), Tokens). The proxy then only +passes requests on, their `Authorization` header with them: + +```sh +continuum --bind-addr unix:/run/continuum/api.sock --htpasswd htpasswd ... +``` + +```nginx +location / { + proxy_pass http://unix:/run/continuum/api.sock; +} +``` + +Without `--user-header`, no header names a user, so nothing a client sends through the +proxy can. + +### The proxy authenticating + +A proxy can authenticate users itself instead (single sign-on through OpenID Connect, +client certificates, its own password file), and name the user in a header, which the +node believes from where the proxy connects alone (`--user-header`, +`--trusted-proxies`); requests from elsewhere still need `--htpasswd`, which becomes +optional. The proxy must set or clear that header on every request, or a client could +set it itself. Where the proxy connects decides who can pose as it. Every user of a host connects from its loopback addresses, so trusting those (as `--trusted-proxies` does by @@ -126,14 +146,32 @@ continuum --bind-addr 127.0.0.1:3000,unix:/run/continuum/api.sock \ ``` ```nginx -location / { - auth_basic "continuum"; - auth_basic_user_file /etc/nginx/continuum.htpasswd; - proxy_set_header X-Remote-User $remote_user; - proxy_pass http://unix:/run/continuum/api.sock; +# A request with a token (`Authorization: Bearer`, from logging in on any node of the +# swarm: access.md, Tokens) goes to the node as it is, which checks the token; any +# other must pass nginx's own login. +map $http_authorization $continuum_auth { + "~^Bearer " off; + default "continuum"; +} + +server { + # ... + location / { + auth_basic $continuum_auth; + auth_basic_user_file /etc/nginx/continuum.htpasswd; + # Empty for a request with a token: then nginx sends no such header. + proxy_set_header X-Remote-User $remote_user; + proxy_pass http://unix:/run/continuum/api.sock; + } } ``` +Without the `map`, nginx answers a request with a token `401` itself, as `auth_basic` +takes only a password, and the dashboard's subscriptions and tokens from other nodes +fail. With it, a client that sets the header itself on a request with a token gets +nothing from it: nginx sends `X-Remote-User` only as it sets it, empty there, and the +node takes no user from an empty one. + The directory of the socket must exist and let the proxy's user through (with systemd, `RuntimeDirectory=continuum` and `RuntimeDirectoryMode=0750`, the proxy's user in the node's group). A socket left behind by an earlier run is replaced, and the node removes @@ -158,8 +196,8 @@ REJECT`). The loopback addresses can then stay trusted; root can still get past can past a socket's permissions. Every address of the API on loopback is trusted alike, so a command-line tool of another user goes through the proxy then. -The names the proxy gives are the users of `--protocol-writers` and of who wrote what -([`api.md`](api.md)). +The names the proxy gives are the users of the registry ([`access.md`](access.md)), of +`--protocol-writers`, and of who wrote what ([`api.md`](api.md)). What streams (`/stream`, the dashboard's events) says `X-Accel-Buffering: no`, so nginx passes it on as it comes, and says it's alive while nothing changes: the dashboard's |
