headscale专有网络及其ACL控制

news2024/11/16 13:50:59

如何使用 Headscale ( Tailscale 开源版 ) 快速搭建一个私有专属的 P2P 内网穿透网络
 

内网穿透简述

由于国内网络环境问题, 普遍家庭用户宽带都没有分配到公网 IP(我有固定公网 IP, 嘿嘿); 这时候一般我们需要从外部访问家庭网络时就需要通过一些魔法手段, 比如 VPN、远程软件(向日葵…)等; 但是这些工具都有一个普遍存在的问题: 慢+卡!

1.1、传统星型拓扑

究其根本因素在于, 在传统架构中如果两个位于多层 NAT(简单理解为多个路由器)之后的设备, 只能通过一些中央(VPN/远程软件)中转服务器进行链接, 这时网络连接速度取决于中央服务器带宽和速度; 这种网络架构我这里简称为: 星型拓扑

640?wx_fmt=png&tp=wxpic&wxfrom=5&wx_lazy=1&wx_co=1

从这张图上可以看出, 你的 “工作笔记本” 和 “家庭 NAS” 之间通讯的最大传输速度为 Up/Down: 512K/s; 因为流量经过了中央服务器中转, 由于网络木桶效应存在, 即使你两侧的网络速度再高也没用, 整体的速度取决于这个链路中最低的一个设备网速而不是你两端的设备.

在这种拓扑下, 想提高速度只有一个办法: 加钱! 在不使用 “钞能力” 的情况下, 普遍免费的软件提供商不可能给予过多的资源来让用户白嫖, 而自己弄大带宽的中央服务器成本又过高.

1.2、NAT 穿透与网状拓扑

本部分只做简述, 具体里面有大量细节和规则可能描述不准确, 细节部分推荐阅读 How NAT traversal works.

既然传统的星型拓扑有这么多问题, 那么有没有其他骚操作可以解决呢? 答案是有的, 简单来说就是利用 NAT 穿透原理. NAT 穿透简单理解如下: 在 A 设备主动向 B 设备发送流量后, 整个链路上的防火墙会短时间打开一个映射规则, 该规则允许 B 设备短暂的从这个路径上反向向 A 设备发送流量. 更通俗的讲大概就是所谓的: “顺着网线来打你”

640?wx_fmt=png&tp=wxpic&wxfrom=5&wx_lazy=1&wx_co=1

搞清了这个规则以后, 我们就可以弄一台 “低配” 的中央服务器, 让中央服务器来帮助我们协商两边的设备谁先访问谁(或者说是访问规则); 两个设备一起无脑访问对方, 然后触发防火墙的 NAT 穿透规则(防火墙打开), 此后两个设备就可以不通过中央服务器源源不断的通讯了. 在这种架构下我们的设备其实就组成了一个非标准的网状拓扑:

640?wx_fmt=png&tp=wxpic&wxfrom=5&wx_lazy=1&wx_co=1

在这种拓扑下, 两个设备之间的通讯速度已经不在取决于中央服务器, 而是直接取决于两端设备的带宽, 也就是说达到了设备网络带宽峰值. 当然 NAT 穿透也不是百分百能够成功的, 在复杂网络情况下有些防火墙不会按照预期工作或者说有更严格的限制; 比如 IP、端口、协议限制等等, 所以为了保证可靠性可以让中央服务器中转做后备方案, 即尽量尝试 NAT 穿透, 如果不行走中央服务器中继.

Tailscale 简介

第一部分是为了方便读者理解一些新型内网穿透的大致基本原理, 现在回到本文重点: Tailscale

Tailscale 就是一种利用 NAT 穿透(aka: P2P 穿透)技术的 VPN 工具. Tailscale 客户端等是开源的, 不过遗憾的是中央控制服务器目前并不开源; Tailscale 目前也提供免费的额度给用户使用, 在 NAT 穿透成功的情况下也能保证满速运行.

不过一旦无法 NAT 穿透需要做中转时, Tailscale 官方的服务器由于众所周知的原因在国内访问速度很拉胯; 不过万幸的是开源社区大佬们搓了一个开源版本的中央控制服务器(Headscale), 也就是说: 我们可以自己搭建中央服务器啦, 完全 “自主可控” 啦.

搭建 Headscale 服务端

以下命令假设安装系统为 Ubuntu 22.04, 其他系统请自行调整.

3.1、宿主机安装

Headscale 是采用 Go 语言编写的, 所以只有一个二进制文件, 在 Github Releases 页面下载最新版本即可:

# 下载
wget https://github.com/juanfont/headscale/releases/download/v0.16.4/headscale_0.16.4_linux_amd64 -O /usr/local/bin/headscale

# 增加可执行权限
chmod +x /usr/local/bin/headscale

下载完成后为了安全性我们需要创建单独的用户和目录用于 Headscale 运行

# 配置目录
mkdir -p /etc/headscale

# 创建用户
useradd \
 --create-home \
 --home-dir /var/lib/headscale/ \
 --system \
 --user-group \
 --shell /usr/sbin/nologin \
 headscale

为了保证 Headscale 能持久运行, 我们需要创建 SystemD 配置文件

# /lib/systemd/system/headscale.service
[Unit]
Description=headscale controller
After=syslog.target
After=network.target

[Service]
Type=simple
User=headscale
Group=headscale
ExecStart=/usr/local/bin/headscale serve
Restart=always
RestartSec=5

# Optional security enhancements
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/headscale /var/run/headscale
AmbientCapabilities=CAP_NET_BIND_SERVICE
RuntimeDirectory=headscale

[Install]
WantedBy=multi-user.target

3.2、配置 Headscale

安装完成以后我们需要在 /etc/headscale/config.yaml 中配置 Headscale 的启动配置, 以下为配置样例以及解释(仅列出重要配置):

---
# Headscale 服务器的访问地址
# 
# 这个地址是告诉客户端需要访问的地址, 即使你需要在跑在
# 负载均衡器之后这个地址也必须写成负载均衡器的访问地址
server_url: https://your.domain.com

# Headscale 实际监听的地址
listen_addr: 0.0.0.0:8080

# 监控地址
metrics_listen_addr: 127.0.0.1:9090

# grpc 监听地址
grpc_listen_addr: 0.0.0.0:50443

# 是否允许不安全的 grpc 连接(非 TLS)
grpc_allow_insecure: false

# 客户端分配的内网网段
ip_prefixes:
  - fd7a:115c:a1e0::/48
  - 100.64.0.0/10

# 中继服务器相关配置
derp:
  server:
    # 关闭内嵌的 derper 中继服务(可能不安全, 还没去看代码)
    enabled: false

  # 下发给客户端的中继服务器列表(默认走官方的中继节点)
  urls:
    - https://controlplane.tailscale.com/derpmap/default

  # 可以在本地通过 yaml 配置定义自己的中继接待你
  paths: []

# SQLite config
db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite

# 使用自动签发证书是的域名
tls_letsencrypt_hostname: ""

# 使用自定义证书时的证书路径
tls_cert_path: ""
tls_key_path: ""

# 是否让客户端使用随机端口, 默认使用 41641/UDP
randomize_client_port: false

3.3、证书及反向代理

可能很多人和我一样, 希望使用 ACME 自动证书, 又不想占用 80/443 端口, 又想通过负载均衡器负载, 配置又看的一头雾水; 所以这里详细说明一下 Headscale 证书相关配置和工作逻辑:

  • 1、Headscale 的 ACME 只支持 HTTP/TLS 挑战, 所以使用后必定占用 80/443

  • 2、当配置了 tls_letsencrypt_hostname 时一定会进行 ACME 申请

  • 3、在不配置 tls_letsencrypt_hostname 时如果配置了 tls_cert_path 则使用自定义证书

  • 4、两者都不配置则不使用任何证书, 服务端监听 HTTP 请求

  • 5、三种情况下(ACME 证书、自定义证书、无证书)主服务都只监听 listen_addr 地址, 与 server_url 没半毛钱关系

  • 6、只有在有证书(ACME 证书或自定义证书)的情况下或者手动开启了 grpc_allow_insecure 才会监听 grpc 远程调用服务

综上所述, 如果你想通过 Nginx、Caddy 反向代理 Headscale, 则你需要满足以下配置:

  • 1、删除掉 tls_letsencrypt_hostname 或留空, 防止 ACME 启动

  • 2、删除掉 tls_cert_path 或留空, 防止加载自定义证书

  • 3、server_url 填写 Nginx 或 Caddy 被访问的 HTTPS 地址

  • 4、在你的 Nginx 或 Caddy 中反向代理填写 listen_addr 的 HTTP 地址

Nginx 配置参考 官方 Wiki, Caddy 只需要一行 reverse_proxy headscale:8080 即可(地址自行替换).

至于 ACME 证书你可以通过使用 acme.sh 自动配置 Nginx 或者使用 Caddy 自动申请等方式, 这些已经与 Headscale 无关了, 不在本文探讨范围内.

3.4、内网地址分配

请尽量不要将 ip_prefixes 配置为默认的 100.64.0.0/10 网段, 如果你有兴趣查询了该地址段, 那么你应该明白它叫 CGNAT; 很不幸的是例如 Aliyun 底层的 apt 源等都在这个范围内, 可能会有一些奇怪问题.

3.5、启动 Headscale

在处理完证书等配置后, 只需要愉快的启动一下即可:

# 开机自启动 并 立即启动
systemctl enable headscale --now

再啰嗦一嘴, 如果你期望使用 Headscale ACME 自动申请证书, 你的关键配置应该像这样:

server_url: https://your.domain.com
listen_addr: 0.0.0.0:443
tls_letsencrypt_hostname: "your.domain.com"
tls_cert_path: ""
tls_key_path: ""

如果你期望使用自定义证书, 则你的关键配置应该像这样:

server_url: https://your.domain.com
listen_addr: 0.0.0.0:443
tls_letsencrypt_hostname: ""
tls_cert_path: "/path/to/cert"
tls_key_path: "/path/to/key"

如果你期望使用负载均衡器, 那么你的关键配置应该像这样:

server_url: https://your.domain.com
listen_addr: 0.0.0.0:8080
tls_letsencrypt_hostname: ""
tls_cert_path: ""
tls_key_path: ""

在使用负载均衡器配置时, 启动后会有一行警告日志, 忽略即可:

2022-09-18T07:57:36Z WRN Listening without TLS but ServerURL does not start with http://

3.6、Docker Compose 安装

Compose 配置样例文件如下:

# docker-compose.yaml
version: "3.9"

services:
  headscale:
    container_name: headscale
    image: headscale/headscale:0.16.4
    ports:
      - "8080:8080"
    cap_add:
      - NET_ADMIN
      - NET_RAW
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv6.conf.all.forwarding=1
    restart: always
    volumes:
      - ./conf:/etc/headscale
      - data:/var/lib/headscale
    command: ["headscale", "serve"]
volumes:
  config:
  data:

你需要在与 docker-compose.yaml 同级目录下创建 conf 目录用于存储配置文件; 具体配置请参考上面的配置详解等部分, 最后不要忘记你的 Compose 文件端口映射需要和配置文件保持一致.

客户端安装

对于客户端来说, Tailscale 提供了多个平台和发行版的预编译安装包, 并且部分客户端直接支持设置自定义的中央控制服务器.

4.1、Linux 客户端

Linux 用户目前只需要使用以下命令安装即可:

curl -fsSL https://tailscale.com/install.sh | sh

默认该脚本会检测相关的 Linux 系统发行版并使用对应的包管理器安装 Tailscale, 安装完成后使用以下命令启动:

tailscale up --login-server https://your.domain.com --advertise-routes=192.168.11.0/24 --accept-routes=true --accept-dns=false

关于选项设置:

  • --login-server: 指定使用的中央服务器地址(必填)

  • --advertise-routes: 向中央服务器报告当前客户端处于哪个内网网段下, 便于中央服务器让同内网设备直接内网直连(可选的)或者将其他设备指定流量路由到当前内网(可选)

  • --accept-routes: 是否接受中央服务器下发的用于路由到其他客户端内网的路由规则(可选)

  • --accept-dns: 是否使用中央服务器下发的 DNS 相关配置(可选, 推荐关闭)

启动完成后, tailscale 将会卡住, 并打印一个你的服务器访问地址; 浏览器访问该地址后将会得到一条命令:

640?wx_fmt=png&tp=wxpic&wxfrom=5&wx_lazy=1&wx_co=1

640?wx_fmt=png&tp=wxpic&wxfrom=5&wx_lazy=1&wx_co=1

注意: 浏览器上显示的命令需要在中央控制服务器执行(Headscale), NAMESAPCE 位置应该替换为一个具体的 Namespace, 可以使用以下命令创建 Namespace (名字随意)并让设备加入:

640?wx_fmt=png&tp=wxpic&wxfrom=5&wx_lazy=1&wx_co=1

在 Headscale 服务器上执行命令成功后客户端命令行在稍等片刻便会执行完成, 此时该客户端已经被加入 Headscale 网络并分配了特定的内网 IP; 多个客户端加入后在 NAT 穿透成功时就可以互相 ping 通, 如果出现问题请阅读后面的调试细节, 只要能注册成功就算是成功了一半, 暂时不要慌.

4.2、MacOS 客户端

MacOS 客户端安装目前有两种方式, 一种是使用标准的 AppStore 版本(好像还有一个可以直接下载的), 需要先设置服务器地址然后再启动 App:

首先访问你的 Headscale 地址 https://your.domain.com/apple:

640?wx_fmt=png&tp=wxpic&wxfrom=5&wx_lazy=1&wx_co=1

复制倒数第二行命令到命令行执行(可能需要 sudo 执行), 然后去 AppStore 搜索 Hailscale 安装并启动; 启动后会自动打开浏览器页面, 与 Linux 安装类似, 复制命令到 Headscale 服务器执行即可(Namespace 创建一次就行).

第二种方式也是比较推荐的方式, 直接编译客户端源码安装, 体验与 Linux 版本一致:

# 安装 go
brew install go

# 编译命令行客户端
go install tailscale.com/cmd/tailscale{,d}@main

# 安装为系统服务
sudo tailscaled install-system-daemon

安装完成后同样通过 tailscale up 命令启动并注册即可, 具体请参考 Linux 客户端安装部分.

4.3、其他客户端

关于 Windows 客户端大致流程就是创建一个注册表, 然后同样安装官方 App 启动, 接着浏览器复制命令注册即可. 至于移动端本人没有需求, 所以暂未研究. Windows 具体的安装流程请访问 https://your.domain.com/windows 地址查看(基本与 MacOS AppStore 版本安装类似).

中继服务器搭建

在上面的 Headscale 搭建完成并添加客户端后, 某些客户端可能无法联通; 这是由于网络复杂情况下导致了 NAT 穿透失败; 为此我们可以搭建一个中继服务器来进行传统的星型拓扑通信.

5.1、搭建 DERP Server

首先需要注意的是, 在需要搭建 DERP Server 的服务器上, 请先安装一个 Tailscale 客户端并注册到 Headscale; 这样做的目的是让搭建的 DERP Server 开启客户端认证, 否则你的 DERP Server 可以被任何人白嫖.

目前 Tailscale 官方并未提供 DERP Server 的安装包, 所以需要我们自行编译安装; 在编译之前请确保安装了最新版本的 Go 语言及其编译环境.

# 编译 DERP Server
go install tailscale.com/cmd/derper@main

# 复制到系统可执行目录
mv ${GOPATH}/bin/derper /usr/local/bin

# 创建用户和运行目录
useradd \
        --create-home \
        --home-dir /var/lib/derper/ \
        --system \
        --user-group \
        --shell /usr/sbin/nologin \
        derper

接下来创建一个 SystemD 配置:

# /lib/systemd/system/derper.service
[Unit]
Description=tailscale derper server
After=syslog.target
After=network.target

[Service]
Type=simple
User=derper
Group=derper
ExecStart=/usr/local/bin/derper -c=/var/lib/derper/private.key -a=:8989 -stun-port=3456 -verify-clients
Restart=always
RestartSec=5

# Optional security enhancements
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/derper /var/run/derper
AmbientCapabilities=CAP_NET_BIND_SERVICE
RuntimeDirectory=derper

[Install]
WantedBy=multi-user.target

最后使用以下命令启动 Derper Server 即可:

systemctl enable derper --now

注意: 默认情况下 Derper Server 会监听在 :443 上, 同时会触发自动 ACME 申请证书. 关于证书逻辑如下:

  • 1、如果不指定 -a 参数, 则默认监听 :443

  • 2、如果监听 :443 并且未指定 --certmode=manual 则会强制使用 --hostname 指定的域名进行 ACME 申请证书

  • 3、如果指定了 --certmode=manual 则会使用 --certmode 指定目录下的证书开启 HTTPS

  • 4、如果指定了 -a 为非 :443 端口, 且没有指定 --certmode=manual 则只监听 HTTP

如果期望使用 ACME 自动申请只需要不增加 -a 选项即可(占用 443 端口), 如果期望通过负载均衡器负载, 则需要将 -a 选项指定到非 443 端口, 然后配置 Nginx、Caddy 等 LB 软件即可. 最后一点 stun 监听的是 UDP 端口, 请确保防火墙打开此端口.

5.2、配置 Headscale

在创建完 Derper 中继服务器后, 我们还需要配置 Headscale 来告诉所有客户端在必要时可以使用此中继节点进行通信; 为了达到这个目的, 我们需要在 Headscale 服务器上创建以下配置:

# /etc/headscale/derper.yaml

regions:
  901:
    regionid: 901
    regioncode: private-derper
    regionname: "My Private Derper Server"
    nodes:
      - name: private-derper
        regionid: 901
        # 自行更改为自己的域名
        hostname: derper.xxxxx.com
        # Derper 节点的 IP
        ipv4: 123.123.123.123
        # Derper 设置的 STUN 端口
        stunport: 3456

在创建好基本的 Derper Server 节点信息配置后, 我们需要调整主配置来让 Headscale 加载:

derp:
  server:
    # 这里关闭 Headscale 默认的 Derper Server
    enabled: false
  # urls 留空, 保证不加载官方的默认 Derper
  urls: []
  # 这里填写 Derper 节点信息配置的绝对路径
  paths:
  - /etc/headscale/derper.yaml

  # If enabled, a worker will be set up to periodically
  # refresh the given sources and update the derpmap
  # will be set up.
  auto_update_enabled: true

  # How often should we check for DERP updates?
  update_frequency: 24h

接下来重启 Headscale 并重启 client 上的 tailscale 即可看到中继节点:

~ ❯❯❯ tailscale netcheck

Report:
        * UDP: true
        * IPv4: yes, 124.111.111.111:58630
        * IPv6: no, but OS has support
        * MappingVariesByDestIP: false
        * HairPinning: false
        * PortMapping: UPnP, NAT-PMP, PCP
        * CaptivePortal: true
        * Nearest DERP: XXXX Derper Server
        * DERP latency:
                - XXXX: 10.1ms  (XXXX Derper Server)

到此中继节点搭建完成.

5.3、Docker Compose 安装

目前官方似乎也没有提供 Docker 镜像, 我自己通过 GitHub Action 编译了一个 Docker 镜像, 以下是使用此镜像的 Compose 文件样例:

version: '3.9'
services:
  derper:
    image: mritd/derper
    container_name: derper
    restart: always
    ports:
      - "8080:8080/tcp"
      - "3456:3456/udp"
    environment:
      TZ: Asia/Shanghai
    volumes:
      - /etc/timezone:/etc/timezone
      - /var/run/tailscale:/var/run/tailscale
      - data:/var/lib/derper
volumes:
  data:

该镜像默认开启了客户端验证, 所以请确保 /var/run/tailscale 内存在已加入 Headscale 成功的 tailscaled 实例的 sock 文件. 其他具体环境变量等参数配置请参考 Earthfile.

客户端网络调试

在调试中继节点或者不确定网络情况时, 可以使用一些 Tailscale 内置的命令来调试网络.

6.1、Ping 命令

tailscale ping 命令可以用于测试 IP 连通性, 同时可以看到时如何连接目标节点的. 默认情况下 Ping 命令首先会使用 Derper 中继节点通信, 然后尝试 P2P 连接; 一旦 P2P 连接成功则自动停止 Ping:

~ ❯❯❯ tailscale ping 10.24.0.5
pong from k8s13 (10.24.0.5) via DERP(XXXXX) in 14ms
pong from k8s13 (10.24.0.5) via DERP(XXXXX) in 13ms
pong from k8s13 (10.24.0.5) via DERP(XXXXX) in 14ms
pong from k8s13 (10.24.0.5) via DERP(XXXXX) in 12ms
pong from k8s13 (10.24.0.5) via DERP(XXXXX) in 12ms
pong from k8s13 (10.24.0.5) via 3.4.170.23:2495 in 9ms

由于其先走 Derper 的特性也可以用来测试 Derper 连通性.

6.2、Status 命令

通过 tailscale status 命令可以查看当前节点与其他对等节点的连接方式, 通过此命令可以查看到当前节点可连接的节点以及是否走了 Derper 中继:

~ ❯❯❯ tailscale status
10.24.0.8       xmac                 kovacs       macOS   -
                alivpn               kovacs       linux   active; direct 4.3.4.5:41644, tx 1264 rx 944
                aliyun               kovacs       linux   -
                bob                  kovacs       macOS   offline
                bob-imac             kovacs       macOS   offline
                company              kovacs       linux   active; direct 114.114.114.114:41642, tx 1296 rx 880

6.3、NetCheck 命令

有些情况下我们可以确认是当前主机的网络问题导致没法走 P2P 连接, 但是我们又想了解一下当前的网络环境; 此时可以使用 tailscale netcheck 命令来检测当前的网络环境, 此命令将会打印出详细的网络环境报告:

~ ❯❯❯ tailscale netcheck
2022/10/19 21:15:27 portmap: [v1] Got PMP response; IP: 123.123.123.123, epoch: 297671
2022/10/19 21:15:27 portmap: [v1] Got PCP response: epoch: 297671
2022/10/19 21:15:27 portmap: [v1] UPnP reply {Location:http://192.168.11.1:39735/rootDesc.xml Server:AsusWRT/386 UPnP/1.1 MiniUPnPd/2.2.0 USN:uuid:23345-2380-45f5-34534-04421abwb7cf0::urn:schemas-upnp-org:device:InternetGatewayDevice:1}, "HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\nUSN: uuid:34564645-2380-45f5-b069-sdfdght3245....."
2022/10/19 21:15:27 portmap: UPnP meta changed: {Location:http://192.168.11.1:39735/rootDesc.xml Server:AsusWRT/386 UPnP/1.1 MiniUPnPd/2.2.0 USN:uuid:23345-2380-45f5-b069-04421abwb7cf0::urn:schemas-upnp-org:device:InternetGatewayDevice:1}

Report:
        * UDP: true
        * IPv4: yes, 123.123.123.123:5935
        * IPv6: no, but OS has support
        * MappingVariesByDestIP: false
        * HairPinning: true
        * PortMapping: UPnP, NAT-PMP, PCP
        * CaptivePortal: true
        * Nearest DERP: XXXXX Aliyun
        * DERP latency:
                - XXXXX: 9.5ms   (XXXXX Aliyun)
                - XXXXX: 53.1ms  (XXXXX BandwagonHost)

其他补充

7.1、某些代理工具兼容性

MacOS 下使用一些增强代理工具时, 如果安装 App Store 的官方图形化客户端, 则可能与这些软件冲突, 推荐使用纯命令行版本并添加进程规则匹配 tailscale 和 tailscaled 两个进程, 让它们始终走 DIRECT 规则即可.

7.2、MacOS 下 CPU 占用突然起飞

在使用一些网络代理工具时, 网络工具会设置默认路由; 这可能导致 tailscaled 无法获取到默认路由接口, 然后进入死循环并把 CPU 吃满, 同时会与 Derper 服务器产生大量上传流量. 截止本文发布此问题已修复, 请使用 mian 分支编译安装, 具体见 ISSUE/5879.

7.3、阿里云安装客户端后无法更新软件

Tailscale 默认使用 CGNAT(100.64.0.0/10) 网段作为内部地址分配网段, 目前 Tailscale 仅允许自己的接口使用此网段, 不巧的是阿里云的 DNS、Apt 源等也采用此网段. 这会导致阿里云服务器安装客户端后 DNS、Apt 等不可用, 解决方案目前只能修改源码删除掉这两个 DROP 规则并重新编译.

640?wx_fmt=png&tp=wxpic&wxfrom=5&wx_lazy=1&wx_co=1

7.4、开启路由转发

大多数时候我们可能并不会在每个服务器上都安装 Tailscale 客户端, 通常只安装 2、3 台, 然后想通过这两三台转发该内网的所有流量. 此时你需要

  • 启动 tailscale 时设置正确的路由提示 --advertise-routes=192.168.1.0/24 来告诉 Headscale 服务器 “我这个节点可以转发这些地址的路由”

  • 其他节点启动时需要增加 --accept-routes=true 选项来声明 “我接受外部其他节点发布的路由”

以上两个选项配置后, 只需要 Headscale 服务器上使用 headscale node route enable -a -i XX(ID) 开启即可. 开启后目标节点(ID)的路由就会发布到接受外部路由的所有节点, 想要关闭的话去掉 -a 即可.

7.5、其他问题

以上也只是我个人遇到的一些问题, 如果有其他问题推荐先搜索然后查看 ISSUE, 最后不行可以看看源码. 目前来说 Tailscale 很多选项很模糊, 可能需要阅读源码以后才能知道到底应该怎么做.

640?wx_fmt=png&tp=wxpic&wxfrom=5&wx_lazy=1&wx_co=1

 

Tailscale ACL 访问控制策略完全指南!

前面几篇文章给大家给介绍了 Tailscale 和 Headscale,包括 👉Headscale 的安装部署和各个平台客户端的接入,以及如何打通各个节点所在的局域网。同时还介绍了👉如何自建私有的 DERP 服务器,并让 Tailscale 使用我们自建的 DERP 服务器。

 

还没看的赶紧去看!👇

 

芜湖,Tailscale 开源版本让你的 WireGuard 直接起飞~

 

 

自建 DERP 中继服务器,从此 Tailscale 畅通无阻

 

 

今天我们来探索一下更复杂的场景。想象有这么一个场景,我系统通过 Tailscale 方便的连接一台不完全属于我的设备, 这台设备可能还有其他人也在使用。如果我仅仅是安装一个 Tailscale, 那么所有能登录这台设备的人都可以通过 Tailscale 连接我所有的设备。

 

我能不能实现这样一种需求:我可以连接这台节点,但是这台节点不能连接我的其他节点?

 

这就是 Tailscale ACL(Access Control List)干的事情。ACL 可以严格限制特定用户或设备在 Tailscale 网络上访问的内容。

 

虽然 Headscale 兼容 Tailscale 的 ACL,但还是有些许差异的。本文所讲的 ACL 只适用于 Headscale,如果你使用的是官方的控制服务器,有些地方可能跟预期不符,请自行参考 Tailscale 的官方文档。

 

Tailscale/Headscale 的默认访问规则是 default deny,也就是黑名单模式,只有在访问规则明确允许的情况下设备之间才能通信。所以 Tailscale/Headscale 默认会使用 allowall 访问策略进行初始化,该策略允许加入到 Tailscale 网络的所有设备之间可以相互访问。

 

Tailscale/Headscale 通过使用 group 这种概念,可以只用非常少的规则就能表达大部分安全策略。除了 group 之外,还可以为设备打 tag 来进一步扩展访问策略。结合 group 和 tag 就可以构建出强大的基于角色的访问控制(RBAC)策略。

 

关于 Tailscale 访问控制系统的详情可以参考这篇文章:基于角色的访问控制(RBAC):演进历史、设计理念及简洁实现[1]。这篇文章深入探讨了访问控制系统的历史,从设计层面分析了 DAC -> MAC -> RBAC -> ABAC 的演进历程及各模型的优缺点、适用场景等, 然后从实际需求出发,一步步地设计出一个实用、简洁、真正符合 RBAC 理念的访问控制系统。

 

Tailscale ACL 语法

Tailscale ACL 需要保存为 HuJSON 格式,也就是 human JSON[2]。HuJSON 是 JSON 的超集,允许添加注释以及结尾处添加逗号。这种格式更易于维护,对人类和机器都很友好。

 

Headscale 除了支持 HuJSON 之外,还支持使用 YAML 来编写 ACL。本文如不作特殊说明,默认都使用 YAML 格式。

 

Headscale 的 ACL 策略主要包含以下几个部分:

 

acls:ACL 策略定义。

groups:用户的集合。Tailscale 官方控制器的“用户”指的是登录名,必须是邮箱格式。而 Headscale 的用户就是 namesapce。

hosts:定义 IP 地址或者 CIDR 的别名。

tagOwners:指定哪些用户有权限给设备打 tag。

autoApprovers:允许哪些用户不需要控制端确认就可以宣告 Subnet 路由和 Exit Node。

ACL 规则

acls 部分是 ACL 规则主体,每个规则都是一个 HuJSON 对象,它授予从一组访问来源到一组访问目标的访问权限。

 

所有的 ACL 规则最终表示的都是允许从特定源 IP 地址到特定目标 IP 地址和端口的流量。虽然可以直接使用 IP 地址来编写 ACL 规则,但为了可读性以及方便维护,建议使用用户、Group 以及 tag 来编写规则,Tailscale 最终会将其转换为具体的 IP 地址和端口。

 

每一个 ACL 访问规则长这个样子:

 

  - action: accept

    src:

      - xxx

      - xxx

      - ...

    dst:

      - xxx

      - xxx

      - ...

    proto: protocol # 可选参数

Tailscale/Headscale 的默认访问规则是 default deny,也就是黑名单模式,只有在访问规则明确允许的情况下设备之间才能通信。所以 ACL 规则中的 action 值一般都写 accept,毕竟默认是 deny 嘛。

 

src 字段表示访问来源列表,该字段可以填的值都在这个表格里:

 

类型 示例 含义

Any * 无限制(即所有来源)

用户(Namespace) dev1 Headscale namespace 中的所有设备

Group (ref)[3] group:example Group 中的所有用户

Tailscale IP 100.101.102.103 拥有给定 Tailscale IP 的设备

Subnet CIDR (ref)[4] 192.168.1.0/24 CIDR 中的任意 IP

Hosts (ref)[5] my-host hosts 字段中定义的任意 IP

Tags (ref)[6] tag:production 分配指定 tag 的所有设备

Tailnet members autogroup:members Tailscale 网络中的任意成员(设备)

proto 字段是可选的,指定允许访问的协议。如歌不指定,默认可以访问所有 TCP 和 UDP 流量。

 

proto 可以指定为 IANA IP 协议编号[7] 1-255(例如 16)或以下命名别名之一(例如 sctp):

 

协议 proto IANA 协议编号

Internet Group Management (IGMP) igmp 2

IPv4 encapsulation ipv4, ip-in-ip 4

Transmission Control (TCP) tcp 6

Exterior Gateway Protocol (EGP) egp 8

Any private interior gateway igp 9

User Datagram (UDP) udp 17

Generic Routing Encapsulation (GRE) gre 47

Encap Security Payload (ESP) esp 50

Authentication Header (AH) ah 51

Stream Control Transmission Protocol (SCTP) sctp 132

只有 TCP、UDP 和 SCTP 流量支持指定端口,其他协议的端口必须指定为 *。

 

dst 字段表示访问目标列表,列表中的每个元素都用 hosts:ports 来表示。hosts 的取值范围如下:

 

类型 示例 含义

Any * 无限制(即所有访问目标)

用户(Namespace) dev1 Headscale namespace 中的所有设备

Group (ref)[8] group:example Group 中的所有用户

Tailscale IP 100.101.102.103 拥有给定 Tailscale IP 的设备

Hosts (ref)[9] my-host hosts 字段中定义的任意 IP

Subnet CIDR (ref)[10] 192.168.1.0/24 CIDR 中的任意 IP

Tags (ref)[11] tag:production 分配指定 tag 的所有设备

Internet access (ref)[12] autogroup:internet 通过 Exit Node 访问互联网

Own devices autogroup:self 允许 src 中定义的来源访问自己(不包含分配了 tag 的设备)

Tailnet devices autogroup:members Tailscale 网络中的任意成员(设备)

ports 的取值范围:

 

类型 示例

Any *

Single 22

Multiple 80,443

Range 1000-2000

Groups

groups 定义了一组用户的集合,YAML 格式示例配置如下:

 

groups:

  group:admin:

    - "admin1"

  group:dev:

    - "dev1"

    - "dev2"

huJSON 格式:

 

"groups": {

  "group:admin": ["admin1"],

  "group:dev": ["dev1", "dev2"],

},

每个 Group 必须以 group: 开头,Group 之间也不能相互嵌套。

 

Autogroups

autogroup 是一个特殊的 group,它自动包含具有相同属性的用户或者访问目标,可以在 ACL 规则中调用 autogroup。

 

Autogroup 允许在 ACL 的哪个字段调用 含义

autogroup:internet dst 用来允许任何用户通过任意 Exit Node 访问你的 Tailscale 网络

autogroup:members src 或者 dst 用来允许 Tailscale 网络中的任意成员(设备)访问别人或者被访问

autogroup:self dst 用来允许 src 中定义的来源访问自己

示例配置:

 

acls:

  # 允许所有员工访问自己的设备

  - action: accept

    src:

      - "autogroup:members"

    dst:

      - "autogroup:self:*"

  # 允许所有员工访问打了标签 tag:corp 的设备

  - action: accept

    src:

      - "autogroup:members"

    dst:

      - "tag:corp:*"

Hosts

Hosts 用来定义 IP 地址或者 CIDR 的别名,使 ACL 可读性更强。示例配置:

 

hosts:

  example-host-1: "100.100.100.100"

  example-network-1: "100.100.101.100/24

Tag Owners

tagOwners 定义了哪些用户有权限给设备分配指定的 tag。示例配置:

 

tagOwners:

  tag:webserver:

    - group:engineering

  tag:secure-server:

    - group:security-admins

    - dev1

  tag:corp:

    - autogroup:members

这里表示的是允许 Group group:engineering 给设备添加 tag tag:webserver;允许 Group group:security-admins 和用户(也就是 namespace)dev1 给设备添加 tag tag:secure-server;允许 Tailscale 网络中的任意成员(设备)给设备添加 tag tag

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/689947.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

未来的编程语言「GitHub 热点速览」

作者:HelloGitHub-小鱼干 又一个编程语言火了,不算新,因为它已经开发了一段时间。不过在本周 Hacker News 上风头十足,DreamBerd 除了有点意思的改 ; 分隔符为 !,之外,它还能让你用问号来标注一段你也不确定…

通过adb获取ANR日志

1、命令行输入:adb bugreport 2、等待日志下载完毕,解压bugreport文件 3、进入FS-->data-->anr

【架构治理工具】在代码存储库中记录软件架构

Markdown 是一种标准的简单语法,用于创建具有专业外观的文档。它比 HTML 更简单,无需专门的编写编辑器即可进行管理。Git配置管理工具也支持markdown格式。在 Git 环境中,markdown 一般用于项目的简单介绍和构建说明。(自述文件&a…

CSS 渐变

CSS 渐变 01 CSS 渐变基础 颜色的几种表示 渐变的几种方式 02 特殊的渐变举例 水平渐变 垂直渐变(矩形四个点三种颜色) 线性渐变只能在一个方向上渐变,要想实现这种渐变,可以使用两个标签进行叠加:一个负责水平…

npm运行没反应的问题

npm 遇到的问题 我们在经常切换node版的时候会遇到npm命令失效的问题。 我们不管运行npm的什么命令都是一闪然后就没有任何输出,效果如下: 主要原因是因为npm config set prefix 改包的路径出问题了 解决方法是:打开系统盘找到下列目录&am…

水力发电在可再生能源中的地位和潜力

可再生能源的发展已成为全球能源领域的重要趋势,而作为最古老、最成熟的可再生能源形式之一,水力发电在能源供应和环境保护方面发挥着重要作用。本文将深入探讨水力发电在可再生能源中的地位和潜力,包括其技术特点、发展趋势以及面临的挑战和…

多线程/std::thread线程退出方式详解

文章目录 概述不 join 也不 detach执行了detach并不能万事大吉建议使用 join 函数 概述 这里默认你已经了解 std::thread 类的基本使用,和WinAPI多线程编程中 “如何优雅的退出线程” 等相关知识。阅读该文前,建议先看看《多线程 /C 11 std::thread 类深…

考场作弊行为自动抓拍告警算法 yolov7

考场作弊行为自动抓拍告警系统通过yolov7python网络模型算法,考场作弊行为自动抓拍告警算法实时监测考场内所有考生的行为,对考生的行为进行自动抓拍,并分析判断是否存在作弊行为。YOLOv7 的发展方向与当前主流的实时目标检测器不同&#xff…

ChatGLM2本地部署的实战方案

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

PHP wangEditor插件打包(包含公式、上传附件)完整版

注意&#xff1a;js,css文件引用路径需要修改 先看效果 index.html文件 <!-- 新版编辑器 --> <script type"text/javascript" src"js/editor/dist/index.js"></script> <link href"js/editor/dist/css/style.css" rel&qu…

Mysql_5.7下载及安装(CentOS7)

文章目录 安装MySQL的几种方式一、 使用docker安装MySQL1.1 卸载旧版本&#xff08;如果存在docker&#xff0c;需先卸载旧版本&#xff09;1.2 安装Docker使用存储库安装(推荐使用) 1.3 安装mysql5.7.35(普通用户下)*** 安装MySQL:5.7.35镜像*** 进入容器中查看配置文件以及数…

Vue----Vue条件渲染

【原文链接】Vue----Vue条件渲染 &#xff08;1&#xff09;在components文件夹下新建一个Ifdemo.vue文件。 &#xff08;2&#xff09;然后在文件中编写如下内容&#xff0c;即写入一个标题 <template><h3>条件渲染</h3> </template> <script&…

Go语言开发者的Apache Arrow使用指南:数据类型

如果你不是做大数据分析的&#xff0c;提到Arrow这个词&#xff0c;你可能会以为我要聊聊那个箭牌卫浴或是箭牌口香糖(注&#xff1a;其实箭牌口香糖使用的单词并非Arrow)。其实我要聊的是Apache的一个顶级项目&#xff1a;Arrow[1]。 为什么要聊这个项目呢&#xff1f;说来话长…

【吴恩达deeplearning.ai】基于ChatGPT API打造应用系统(上)

以下内容均整理来自deeplearning.ai的同名课程 Location 课程访问地址 DLAI - Learning Platform Beta (deeplearning.ai) 一、大语言模型基础知识 本篇内容将围绕api接口的调用、token的介绍、定义角色场景 调用api接口 import os import openai import tiktoken from dote…

使用 MediaPipe 身体跟踪构建不良身体姿势检测和警报系统

文末附实现相关源代码下载链接 正确的身体姿势是一个人整体健康的关键。然而,保持正确的身体姿势可能很困难,因为我们经常忘记这一点。这篇博文将引导您完成为此构建解决方案所需的步骤。最近,我们在使用 MediaPipe POSE 进行身体姿势检测方面玩得很开心。 使用 MediaPipe P…

el-form复杂表单嵌套el-table实现复制字段并校验删除等功能

功能&#xff1a;表单项全部复制&#xff0c;表单项根据el-table选择后复制部分内容&#xff0c;做所有表单项的校验&#xff0c;部分表单项删除功能 点击添加饮品爱好后弹出el-table表单 选择好后点确定如下图&#xff0c;并且实现删除功能&#xff0c;删除仅仅删除饮品和爱好…

Excel 插入对象选PDF文件后,跳出图像数据不充分对话框,怎么解决

环境&#xff1a; excel 2021 Win10 专业版 问题描述&#xff1a; Excel 插入对象选PDF文件后&#xff0c;跳出图像数据不充分对话框 解决方案&#xff1a; 1.打开文件-选项-高级-不压缩文件中的图像&#xff0c;前面打勾 2.重启excel&#xff0c;再此插入解决&#xf…

Kears-4-深度学习用于计算机视觉-使用预训练的卷积网络

0. 说明&#xff1a; 本篇学习记录主要包括&#xff1a;《Python深度学习》的第5章&#xff08;深度学习用于计算机视觉&#xff09;的第3节&#xff08;使用预训练的卷积神经网络&#xff09;内容。 相关知识点&#xff1a; 预训练模型的复用方法&#xff1b;预训练网络 (p…

ResNet网络结构

Deep Residual Learning for Image Recognition 论文&#xff1a;https://arxiv.org/abs/1512.03385 代码&#xff1a;ResNet网络详解及Pytorch代码实现&#xff08;超详细帮助你掌握ResNet原理及实现&#xff09;_basic block结构图_武晨的博客-CSDN博客 【DL系列】ResNet网…