前言:为什么需要零信任?
传统网络安全模型基于"内网可信、外网不可信"的边界思维,但随着远程办公、云原生架构和BYOD的普及,这种模型已经千疮百孔。零信任网络访问(ZTNA)的核心理念是"永不信任,始终验证"——无论用户身处公司内网还是咖啡厅WiFi,都必须经过身份验证和设备合规检查才能访问资源。
商业方案如 Zscaler ZPA 年费 $120-200/用户,Palo Alto Prisma Access 价格不透明但据估算也在类似区间,Cloudflare Access 相对便宜但仍需 $7/用户/月。对于中小团队或个人项目,这些成本可能难以承受。
本文将带你用 Keycloak + Headscale 搭建一套完全开源的零信任方案,覆盖身份认证、网络隧道、策略控制三大核心能力。
一、付费工具定价对比
| 工具 | 定价模型 | 价格范围 | 核心优势 | 适用场景 |
|---|---|---|---|---|
| Zscaler ZPA | 按用户/年 | $120-200/用户/年 | 全球150+ PoP节点,SASE集成 | 大型企业 |
| Palo Alto Prisma Access | 按用户计费 | 价格不公开(估算$150+/用户/年) | 深度威胁检测,SASE全栈 | 合规要求高的企业 |
| Cloudflare Access | 按用户/月 | $7/用户/月 | CDN+安全一体化,低延迟 | 中小团队,SaaS应用 |
| Cloudflare One | 按用户/月 | $7-20/用户/月 | 网关+接入+浏览器隔离 | 需要完整SASE的团队 |
关键差距:商业方案的核心价值在于全球边缘节点、内置威胁情报、与SASE/SSE平台的深度集成。开源方案需要自行搭建这些能力,但完全可控且零授权费用。
二、免费替代方案介绍
2.1 Keycloak —— 身份与访问管理(IAM)
Keycloak 是 Red Hat 主导的开源 IAM 解决方案,提供:
- SAML 2.0 / OpenID Connect / OAuth 2.0 协议支持
- 用户联邦(LDAP/AD集成)
- 多因素认证(TOTP、WebAuthn/FIDO2)
- 细粒度授权策略(基于属性的访问控制ABAC)
- 单点登录(SSO)
GitHub: https://github.com/keycloak/keycloak (19k+ Stars)
2.2 Headscale —— 自托管控制服务器
Headscale 是 Tailscale 控制服务器的开源替代实现:
GitHub: https://github.com/juanfont/headscale (22k+ Stars)
2.3 其他替代方案
- freeIPA: 完整的Linux身份管理方案(LDAP+Kerberos+DNS+CA),适合纯Linux环境
- Pomerium: 开源零信任代理,支持OIDC,与Keycloak无缝集成
- WireGuard + LDAP: 直接使用WireGuard,通过脚本集成LDAP认证
三、完整部署实战
3.1 环境准备
# 系统要求:Ubuntu 22.04 LTS / Debian 12
# 最低配置:2核4GB内存(Keycloak较吃内存),50GB磁盘
# 更新系统
sudo apt update && sudo apt upgrade -y
# 安装必要工具
sudo apt install -y curl wget gnupg2 software-properties-common apt-transport-https ca-certificates
# 安装Docker(用于Keycloak)
curl -fsSL https://get.docker.com | sudo bash
sudo usermod -aG docker $USER
# 安装Docker Compose
sudo apt install -y docker-compose-plugin
3.2 部署 Keycloak
创建项目目录和配置:
mkdir -p /opt/keycloak && cd /opt/keycloak
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
keycloak-db:
image: postgres:16-alpine
container_name: keycloak-db
restart: unless-stopped
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: ChangeMeStrongPass2024!
volumes:
- keycloak-db-data:/var/lib/postgresql/data
networks:
- keycloak-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak"]
interval: 10s
timeout: 5s
retries: 5
keycloak:
image: quay.io/keycloak/keycloak:24.0
container_name: keycloak
restart: unless-stopped
depends_on:
keycloak-db:
condition: service_healthy
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://keycloak-db:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: ChangeMeStrongPass2024!
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: AdminPass2024!
KC_HOSTNAME: auth.example.com
KC_PROXY: edge
KC_HTTP_ENABLED: "true"
command: start
ports:
- "8080:8080"
networks:
- keycloak-net
volumes:
keycloak-db-data:
networks:
keycloak-net:
driver: bridge
EOF
# 启动Keycloak
docker compose up -d
# 等待启动完成
sleep 30
docker compose logs keycloak | tail -20
配置Keycloak领域(Realm)和客户端:
# 获取admin token
KC_TOKEN=$(curl -s -X POST "http://localhost:8080/realms/master/protocol/openid-connect/token" \
-d "client_id=admin-cli" \
-d "username=admin" \
-d "password=AdminPass2024!" \
-d "grant_type=password" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
# 创建ZTNA领域
curl -s -X POST "http://localhost:8080/admin/realms" \
-H "Authorization: Bearer $KC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"realm": "ztna",
"enabled": true,
"displayName": "ZTNA Zero Trust",
"registrationAllowed": false,
"loginWithEmailAllowed": true,
"duplicateEmailsAllowed": false,
"resetPasswordAllowed": true,
"bruteForceProtected": true,
"maxFailureWaitSeconds": 900,
"permanentLockout": false
}'
# 创建Headscale OIDC客户端
curl -s -X POST "http://localhost:8080/admin/realms/ztna/clients" \
-H "Authorization: Bearer $KC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clientId": "headscale",
"name": "Headscale VPN",
"enabled": true,
"protocol": "openid-connect",
"publicClient": false,
"secret": "headscale-oidc-secret-2024",
"redirectUris": ["https://vpn.example.com/oidc/callback"],
"webOrigins": ["https://vpn.example.com"],
"standardFlowEnabled": true,
"directAccessGrantsEnabled": true,
"attributes": {
"post.logout.redirect.uris": "https://vpn.example.com/"
}
}'
# 启用TOTP二因素认证(推荐)
curl -s -X PUT "http://localhost:8080/admin/realms/ztna/authentication/required-actions" \
-H "Authorization: Bearer $KC_TOKEN" \
-H "Content-Type: application/json" \
-d '[
{"alias":"CONFIGURE_TOTP","enabled":true,"priority":1},
{"alias":"webauthn-register","enabled":true,"priority":2}
]'
3.3 部署 Headscale
# 创建Headscale目录
mkdir -p /opt/headscale && cd /opt/headscale
# 下载最新版Headscale
HS_VERSION="0.23.0"
wget "https://github.com/juanfont/headscale/releases/download/v${HS_VERSION}/headscale_${HS_VERSION}_linux_amd64"
chmod +x "headscale_${HS_VERSION}_linux_amd64"
sudo mv "headscale_${HS_VERSION}_linux_amd64" /usr/local/bin/headscale
# 创建数据目录
sudo mkdir -p /etc/headscale /var/lib/headscale
# 生成配置
headscale configdump > /etc/headscale/config.yaml
# 编辑核心配置
cat > /etc/headscale/config.yaml << 'EOF'
server_url: https://vpn.example.com
listen_addr: 0.0.0.0:8443
metrics_listen_addr: 127.0.0.1:9090
# DERP中继(自建)
derp:
server:
enabled: true
region_id: 999
region_code: "selfhosted"
region_name: "Self-hosted DERP"
stun_listen_addr: "0.0.0.0:3478"
urls: []
paths: []
# 数据库(SQLite足够中小规模)
db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite
# OIDC配置(指向Keycloak)
oidc:
issuer: https://auth.example.com/realms/ztna
client_id: headscale
client_secret: headscale-oidc-secret-2024
scope: ["openid", "profile", "email"]
allowed_domains: ["example.com"]
strip_email_domain: true
# DNS配置
dns_config:
override_local_dns: true
nameservers:
- 1.1.1.1
- 8.8.8.8
domains: []
magic_dns: true
# IP分配
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
EOF
# 创建systemd服务
sudo cat > /etc/systemd/system/headscale.service << 'EOF'
[Unit]
Description=Headscale control server
After=syslog.target
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/headscale serve
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now headscale
sudo systemctl status headscale
3.4 配置反向代理(Nginx)
sudo apt install -y nginx certbot python3-certbot-nginx
cat > /etc/nginx/sites-available/ztna << 'EOF'
# Keycloak (auth.example.com)
server {
listen 443 ssl http2;
server_name auth.example.com;
ssl_certificate /etc/letsencrypt/live/auth.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Headscale (vpn.example.com)
server {
listen 443 ssl http2;
server_name vpn.example.com;
ssl_certificate /etc/letsencrypt/live/vpn.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vpn.example.com/privkey.pem;
location / {
grpc_pass grpc://127.0.0.1:50443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /web {
proxy_pass http://127.0.0.1:8443;
proxy_set_header Host $host;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/ztna /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
3.5 客户端接入
# 安装Tailscale客户端(与Headscale兼容)
curl -fsSL https://tailscale.com/install.sh | sh
# 注册到自托管控制服务器
sudo tailscale up --login-server=https://vpn.example.com --accept-routes
# 在服务器端批准节点
headscale -n example nodes list
headscale -n example nodes approve --identifier <node-id>
# 配置ACL策略
cat > /etc/headscale/acl.hujson << 'EOF'
{
"acls": [
{
"action": "accept",
"src": ["group:developers"],
"dst": ["tag:internal:*"]
},
{
"action": "accept",
"src": ["group:ops"],
"dst": ["*:*"]
}
],
"groups": {
"group:developers": ["[email protected]", "[email protected]"],
"group:ops": ["[email protected]"]
},
"tagOwners": {
"tag:internal": ["group:ops"]
}
}
EOF
headscale -n example policy set /etc/headscale/acl.hujson
四、功能对比表
| 功能维度 | Zscaler ZPA | Cloudflare Access | Keycloak+Headscale |
|---|---|---|---|
| 身份认证 | 内置+SSO | 内置+SSO | Keycloak全功能 |
| MFA支持 | ✅ 内置 | ✅ 内置 | ✅ TOTP/WebAuthn |
| 网络隧道 | ✅ 专用 | ✅ WARP | ✅ WireGuard |
| 全球PoP | 150+ | 300+ | 需自建DERP |
| ACL策略 | ✅ 细粒度 | ✅ 细粒度 | ✅ ACL文件 |
| SASE集成 | ✅ 全栈 | ✅ 网关+DLP | ❌ 需额外集成 |
| 日志审计 | ✅ 详细 | ✅ 详细 | ✅ 需配置 |
| 设备合规检查 | ✅ 内置 | ✅ 内置 | 需自行实现 |
| 部署复杂度 | 中 | 低 | 中高 |
| 年成本(50用户) | $6,000-10,000 | $4,200 | $0(服务器成本另计) |
五、生产环境注意事项
- 高可用:Headscale 目前不支持集群模式,需通过备份+故障转移实现HA
- 证书管理:建议使用 certbot 自动续期 Let's Encrypt 证书
- 监控:Headscale 暴露 Prometheus metrics,配合 Grafana 监控节点状态
- 备份策略:定期备份
/var/lib/headscale/db.sqlite和 Keycloak PostgreSQL 数据库 - 安全加固:Keycloak 生产环境务必启用 HTTPS、配置速率限制、定期更新
总结
Keycloak + Headscale 组合为中小团队提供了一套可行的零信任网络方案。虽然缺少商业方案的全球边缘网络和SASE集成能力,但核心的"身份验证+加密隧道+策略控制"三大支柱完全可以覆盖。对于预算有限但安全意识强的团队,这是目前最成熟的开源ZTNA方案。
评论