mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-12 19:24:40 +00:00
038d25bd04
Signed-off-by: Xe Iaso <xe@tailscale.com>
162 lines
5.5 KiB
Markdown
162 lines
5.5 KiB
Markdown
# nginx-auth
|
|
|
|
[![status: experimental](https://img.shields.io/badge/status-experimental-blue)](https://tailscale.com/kb/1167/release-stages/#experimental)
|
|
|
|
This is a tool that allows users to use Tailscale Whois authentication with
|
|
NGINX as a reverse proxy. This allows users that already have a bunch of
|
|
services hosted on an internal NGINX server to point those domains to the
|
|
Tailscale IP of the NGINX server and then seamlessly use Tailscale for
|
|
authentication.
|
|
|
|
Many thanks to [@zrail](https://twitter.com/zrail/status/1511788463586222087) on
|
|
Twitter for introducing the basic idea and offering some sample code. This
|
|
program is based on that sample code with security enhancements. Namely:
|
|
|
|
* This listens over a UNIX socket instead of a TCP socket, to prevent
|
|
leakage to the network
|
|
* This uses systemd socket activation so that systemd owns the socket
|
|
and can then lock down the service to the bare minimum required to do
|
|
its job without having to worry about dropping permissions
|
|
* This provides additional information in HTTP response headers that can
|
|
be useful for integrating with various services
|
|
|
|
## Configuration
|
|
|
|
In order to protect a service with this tool, do the following in the respective
|
|
`server` block:
|
|
|
|
Create an authentication location with the `internal` flag set:
|
|
|
|
```nginx
|
|
location /auth {
|
|
internal;
|
|
|
|
proxy_pass http://unix:/run/tailscale.nginx-auth.sock;
|
|
proxy_pass_request_body off;
|
|
|
|
proxy_set_header Host $http_host;
|
|
proxy_set_header Remote-Addr $remote_addr;
|
|
proxy_set_header Remote-Port $remote_port;
|
|
proxy_set_header Original-URI $request_uri;
|
|
}
|
|
```
|
|
|
|
Then add the following to the `location /` block:
|
|
|
|
```
|
|
auth_request /auth;
|
|
auth_request_set $auth_user $upstream_http_tailscale_user;
|
|
auth_request_set $auth_name $upstream_http_tailscale_name;
|
|
auth_request_set $auth_login $upstream_http_tailscale_login;
|
|
auth_request_set $auth_tailnet $upstream_http_tailscale_tailnet;
|
|
auth_request_set $auth_profile_picture $upstream_http_tailscale_profile_picture;
|
|
|
|
proxy_set_header X-Webauth-User "$auth_user";
|
|
proxy_set_header X-Webauth-Name "$auth_name";
|
|
proxy_set_header X-Webauth-Login "$auth_login";
|
|
proxy_set_header X-Webauth-Tailnet "$auth_tailnet";
|
|
proxy_set_header X-Webauth-Profile-Picture "$auth_profile_picture";
|
|
```
|
|
|
|
When this configuration is used with a Go HTTP handler such as this:
|
|
|
|
```go
|
|
http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
|
|
e := json.NewEncoder(w)
|
|
e.SetIndent("", " ")
|
|
e.Encode(r.Header)
|
|
})
|
|
```
|
|
|
|
You will get output like this:
|
|
|
|
```json
|
|
{
|
|
"Accept": [
|
|
"*/*"
|
|
],
|
|
"Connection": [
|
|
"upgrade"
|
|
],
|
|
"User-Agent": [
|
|
"curl/7.82.0"
|
|
],
|
|
"X-Webauth-Login": [
|
|
"Xe"
|
|
],
|
|
"X-Webauth-Name": [
|
|
"Xe Iaso"
|
|
],
|
|
"X-Webauth-Profile-Picture": [
|
|
"https://avatars.githubusercontent.com/u/529003?v=4"
|
|
],
|
|
"X-Webauth-Tailnet": [
|
|
"cetacean.org.github"
|
|
]
|
|
"X-Webauth-User": [
|
|
"Xe@github"
|
|
]
|
|
}
|
|
```
|
|
|
|
## Headers
|
|
|
|
The authentication service provides the following headers to decorate your
|
|
proxied requests:
|
|
|
|
| Header | Example Value | Description |
|
|
| :------ | :-------------- | :---------- |
|
|
| `Tailscale-User` | `azurediamond@hunter2.net` | The Tailscale username the remote machine is logged in as in user@host form |
|
|
| `Tailscale-Login` | `azurediamond` | The user portion of the Tailscale username the remote machine is logged in as |
|
|
| `Tailscale-Name` | `Azure Diamond` | The "real name" of the Tailscale user the machine is logged in as |
|
|
| `Tailscale-Profile-Picture` | `https://i.kym-cdn.com/photos/images/newsfeed/001/065/963/ae0.png` | The profile picture provided by the Identity Provider your tailnet uses |
|
|
| `Tailscale-Tailnet` | `hunter2.net` | The tailnet name |
|
|
|
|
Most of the time you can set `X-Webauth-User` to the contents of the
|
|
`Tailscale-User` header, but some services may not accept a username with an `@`
|
|
symbol in it. If this is the case, set `X-Webauth-User` to the `Tailscale-Login`
|
|
header.
|
|
|
|
The `Tailscale-Tailnet` header can help you identify which tailnet the session
|
|
is coming from. If you are using node sharing, this can help you make sure that
|
|
you aren't giving administrative access to people outside your tailnet.
|
|
|
|
### Allow Requests From Only One Tailnet
|
|
|
|
If you want to prevent node sharing from allowing users to access a service, add
|
|
the `Expected-Tailnet` header to your auth request:
|
|
|
|
```nginx
|
|
location /auth {
|
|
# ...
|
|
proxy_set_header Expected-Tailnet "tailnet012345.ts.net";
|
|
}
|
|
```
|
|
|
|
If a user from a different tailnet tries to use that service, this will return a
|
|
generic "forbidden" error page:
|
|
|
|
```html
|
|
<html>
|
|
<head><title>403 Forbidden</title></head>
|
|
<body>
|
|
<center><h1>403 Forbidden</h1></center>
|
|
<hr><center>nginx/1.18.0 (Ubuntu)</center>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
You can get the tailnet name from [the admin panel](https://login.tailscale.com/admin/dns).
|
|
|
|
## Building
|
|
|
|
Install `cmd/mkpkg`:
|
|
|
|
```
|
|
cd .. && go install ./mkpkg
|
|
```
|
|
|
|
Then run `./mkdeb.sh`. It will emit a `.deb` and `.rpm` package for amd64
|
|
machines (Linux uname flag: `x86_64`). You can add these to your deployment
|
|
methods as you see fit.
|