diff --git a/cmd/nginx-auth/README.md b/cmd/nginx-auth/README.md
index ec6d6527f..66b7cd963 100644
--- a/cmd/nginx-auth/README.md
+++ b/cmd/nginx-auth/README.md
@@ -117,10 +117,32 @@ 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. You will
-need to be sure to check this in your application code. If you use OpenResty,
-you may be able to do more complicated access controls than you can with NGINX
-alone.
+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 "tailscale.com";
+}
+```
+
+If a user from a different tailnet tries to use that service, this will return a
+generic "forbidden" error page:
+
+```html
+
+
403 Forbidden
+
+403 Forbidden
+
nginx/1.18.0 (Ubuntu)
+
+
+```
## Building
diff --git a/cmd/nginx-auth/deb/postinst.sh b/cmd/nginx-auth/deb/postinst.sh
new file mode 100755
index 000000000..d352a8488
--- /dev/null
+++ b/cmd/nginx-auth/deb/postinst.sh
@@ -0,0 +1,14 @@
+if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
+ deb-systemd-helper unmask 'tailscale.nginx-auth.socket' >/dev/null || true
+ if deb-systemd-helper --quiet was-enabled 'tailscale.nginx-auth.socket'; then
+ deb-systemd-helper enable 'tailscale.nginx-auth.socket' >/dev/null || true
+ else
+ deb-systemd-helper update-state 'tailscale.nginx-auth.socket' >/dev/null || true
+ fi
+
+ if systemctl is-active tailscale.nginx-auth.socket >/dev/null; then
+ systemctl --system daemon-reload >/dev/null || true
+ deb-systemd-invoke stop 'tailscale.nginx-auth.service' >/dev/null || true
+ deb-systemd-invoke restart 'tailscale.nginx-auth.socket' >/dev/null || true
+ fi
+fi
diff --git a/cmd/nginx-auth/deb/postrm.sh b/cmd/nginx-auth/deb/postrm.sh
new file mode 100755
index 000000000..4bce86139
--- /dev/null
+++ b/cmd/nginx-auth/deb/postrm.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+set -e
+if [ -d /run/systemd/system ] ; then
+ systemctl --system daemon-reload >/dev/null || true
+fi
+
+if [ -x "/usr/bin/deb-systemd-helper" ]; then
+ if [ "$1" = "remove" ]; then
+ deb-systemd-helper mask 'tailscale.nginx-auth.socket' >/dev/null || true
+ deb-systemd-helper mask 'tailscale.nginx-auth.service' >/dev/null || true
+ fi
+
+ if [ "$1" = "purge" ]; then
+ deb-systemd-helper purge 'tailscale.nginx-auth.socket' >/dev/null || true
+ deb-systemd-helper unmask 'tailscale.nginx-auth.socket' >/dev/null || true
+ deb-systemd-helper purge 'tailscale.nginx-auth.service' >/dev/null || true
+ deb-systemd-helper unmask 'tailscale.nginx-auth.service' >/dev/null || true
+ fi
+fi
diff --git a/cmd/nginx-auth/deb/prerm.sh b/cmd/nginx-auth/deb/prerm.sh
new file mode 100755
index 000000000..e4becd170
--- /dev/null
+++ b/cmd/nginx-auth/deb/prerm.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+set -e
+if [ "$1" = "remove" ]; then
+ if [ -d /run/systemd/system ]; then
+ deb-systemd-invoke stop 'tailscale.nginx-auth.service' >/dev/null || true
+ deb-systemd-invoke stop 'tailscale.nginx-auth.socket' >/dev/null || true
+ fi
+fi
diff --git a/cmd/nginx-auth/mkdeb.sh b/cmd/nginx-auth/mkdeb.sh
index 2bdf41c48..c47ec2522 100755
--- a/cmd/nginx-auth/mkdeb.sh
+++ b/cmd/nginx-auth/mkdeb.sh
@@ -4,20 +4,28 @@ set -e
CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -o tailscale.nginx-auth .
-mkpkg \
- --out tailscale-nginx-auth-0.1.0-amd64.deb \
- --name=tailscale-nginx-auth \
- --version=0.1.0 \
- --type=deb\
- --arch=amd64 \
- --description="Tailscale NGINX authentication protocol handler" \
- --files=./tailscale.nginx-auth:/usr/sbin/tailscale.nginx-auth,./tailscale.nginx-auth.socket:/lib/systemd/system/tailscale.nginx-auth.socket,./tailscale.nginx-auth.service:/lib/systemd/system/tailscale.nginx-auth.service
+VERSION=0.1.1
mkpkg \
- --out tailscale-nginx-auth-0.1.0-amd64.rpm \
+ --out=tailscale-nginx-auth-${VERSION}-amd64.deb \
--name=tailscale-nginx-auth \
- --version=0.1.0 \
+ --version=${VERSION} \
+ --type=deb \
+ --arch=amd64 \
+ --postinst=deb/postinst.sh \
+ --postrm=deb/postrm.sh \
+ --prerm=deb/prerm.sh \
+ --description="Tailscale NGINX authentication protocol handler" \
+ --files=./tailscale.nginx-auth:/usr/sbin/tailscale.nginx-auth,./tailscale.nginx-auth.socket:/lib/systemd/system/tailscale.nginx-auth.socket,./tailscale.nginx-auth.service:/lib/systemd/system/tailscale.nginx-auth.service,./README.md:/usr/share/tailscale/nginx-auth/README.md
+
+mkpkg \
+ --out=tailscale-nginx-auth-${VERSION}-amd64.rpm \
+ --name=tailscale-nginx-auth \
+ --version=${VERSION} \
--type=rpm \
--arch=amd64 \
+ --postinst=rpm/postinst.sh \
+ --postrm=rpm/postrm.sh \
+ --prerm=rpm/prerm.sh \
--description="Tailscale NGINX authentication protocol handler" \
- --files=./tailscale.nginx-auth:/usr/sbin/tailscale.nginx-auth,./tailscale.nginx-auth.socket:/lib/systemd/system/tailscale.nginx-auth.socket,./tailscale.nginx-auth.service:/lib/systemd/system/tailscale.nginx-auth.service
+ --files=./tailscale.nginx-auth:/usr/sbin/tailscale.nginx-auth,./tailscale.nginx-auth.socket:/lib/systemd/system/tailscale.nginx-auth.socket,./tailscale.nginx-auth.service:/lib/systemd/system/tailscale.nginx-auth.service,./README.md:/usr/share/tailscale/nginx-auth/README.md
diff --git a/cmd/nginx-auth/nginx-auth.go b/cmd/nginx-auth/nginx-auth.go
index a64df80cc..439dd3e6d 100644
--- a/cmd/nginx-auth/nginx-auth.go
+++ b/cmd/nginx-auth/nginx-auth.go
@@ -17,6 +17,7 @@ import (
"net"
"net/http"
"net/netip"
+ "net/url"
"os"
"strings"
@@ -75,6 +76,12 @@ func main() {
return
}
+ if expectedTailnet := r.Header.Get("Expected-Tailnet"); expectedTailnet != "" && expectedTailnet != tailnet {
+ w.WriteHeader(http.StatusForbidden)
+ log.Printf("user is part of tailnet %s, wanted: %s", tailnet, url.QueryEscape(expectedTailnet))
+ return
+ }
+
h := w.Header()
h.Set("Tailscale-Login", strings.Split(info.UserProfile.LoginName, "@")[0])
h.Set("Tailscale-User", info.UserProfile.LoginName)
diff --git a/cmd/nginx-auth/rpm/postinst.sh b/cmd/nginx-auth/rpm/postinst.sh
new file mode 100755
index 000000000..e69de29bb
diff --git a/cmd/nginx-auth/rpm/postrm.sh b/cmd/nginx-auth/rpm/postrm.sh
new file mode 100755
index 000000000..3d0abfb19
--- /dev/null
+++ b/cmd/nginx-auth/rpm/postrm.sh
@@ -0,0 +1,9 @@
+# $1 == 0 for uninstallation.
+# $1 == 1 for removing old package during upgrade.
+
+systemctl daemon-reload >/dev/null 2>&1 || :
+if [ $1 -ge 1 ] ; then
+ # Package upgrade, not uninstall
+ systemctl stop tailscale.nginx-auth.service >/dev/null 2>&1 || :
+ systemctl try-restart tailscale.nginx-auth.socket >/dev/null 2>&1 || :
+fi
diff --git a/cmd/nginx-auth/rpm/prerm.sh b/cmd/nginx-auth/rpm/prerm.sh
new file mode 100755
index 000000000..1f198d829
--- /dev/null
+++ b/cmd/nginx-auth/rpm/prerm.sh
@@ -0,0 +1,9 @@
+# $1 == 0 for uninstallation.
+# $1 == 1 for removing old package during upgrade.
+
+if [ $1 -eq 0 ] ; then
+ # Package removal, not upgrade
+ systemctl --no-reload disable tailscale.nginx-auth.socket > /dev/null 2>&1 || :
+ systemctl stop tailscale.nginx-auth.socket > /dev/null 2>&1 || :
+ systemctl stop tailscale.nginx-auth.service > /dev/null 2>&1 || :
+fi