目录
- 简介
- 服务架构
- 部署Authelia
- 准备工作
- 安装Authelia
- 为Authelia配置Nginx反向代理
- 为Web应用配置Nginx反向代理
- 全站加速DCDN配置
- 一些个人考虑
- DCDN及DNS配置
- 脚注
- 参考资料
简介
Authelia是一款开源的单点登录SSO(Single Sign On)认证软件,用户通过在服务器上部署Authelia,搭配1例如Nginx,Nginx Proxy Manager,Traefik等可以提供反向代理服务的软件,即可为没有配备独立身份认证系统的自托管网页应用如Homepage,Suwayomi-Server,Stable Diffusion等暴露在公网之前提供一层较为强力的安全保障。
同时,因为Authelia的SSO属性,用户可以通过完成单个网关认证来一次性方便的访问到任何部署在Authelia之后的网页应用而无需二次认证2,可以在一定程度上减少用户的重复性负荷。
因为老K这几天在研究Homepage这一类的个人导航页Web应用,部署完成之后才恍然发现直接将服务暴露到公网是一个非常不明智的决定,所以才顺便研究了一下相对简单易行的认证网关方案。其间参考了Authelia、Keycloak等开源项目。最后出于部署难度,管理学习成本等等综合考虑选择了利用Docker部署Authelia这一项目,再搭配Nginx反向代理作为自托管Web服务的SSO网关认证系统。
再来谈谈DCDN,也就是阿里云所提供的全站加速服务(在其他云服务商可能有其他缩写名,如腾讯云叫做ECDN),全站加速也是一种按量付费或者订阅制的内容分发网络服务,可以简单理解为把内容缓存的服务范围扩展到了整个目标加速域名,同时可以提供隐藏真实IP以及一定的反DDoS的能力,用户将Authelia和Web应用部署到服务器之后,如果直接使用A或AAAA记录解析服务,还是存在一定的被打的风险。(虽然使用了DCDN服务也还是可能被打,但总比直接把攻击目标明着摆出来要好很多)对于个人站点来说,这样的安全架构选型属于比较够用和靠谱了。
服务架构
博主虽然不是特别专业,但可以用一张自制的简化流程图来帮助大家简单理解初步部署完成之后的完整服务架构:
用户访问网页应用B的请求通过Nginx转发到Authelia进行用户身份认证,这一步体现为:用户访问B.example.com的时候,请求将被转发到Authelia的域名(如auth.example.com)。用户被引导到并在Authelia的域名完成用户认证后,Authelia会将用户的原始请求附加上鉴权信息并送回Nginx,鉴权信息由用户留存,原始请求再最后通过第二次反向代理发送给在Nginx后的真实应用B的域名B.example.com。到此,一次用户认证和网页应用访问完成。
在这样一次用户认证之后,认证有效时间内(如1小时),用户访问在同一根域名example.com下的其他受Authelia保护的网站时,将不再需要认证,虽然请求还是会经过Authelia的域名转发,但是Authelia这一次将直接放行同一用户的请求直达目标应用(如图中的应用C),到此实现了SSO单点登录的功能。
部署Authelia
准备工作
安装Authelia
docker pull authelia/authelia:master # 最新版本,发布时间较新
docker pull authelia/authelia:latest # v4.37.5正式版,22年发布
docker run --name authelia -p 9091:9091 -d --restart="unless-stopped" -e PUID=1000 -e PGID=1000 -e TZ="Asia/Shanghai" -v <你指定的宿主机目录>/config:/config authelia/authelia:master
---
# 此处指定 Authelia 的默认 2FA 认证方式(totp为动态口令)
default_2fa_method: 'totp'
# 此处指定 Authelia 服务器(docker容器)的访问地址,默认为 tcp 协议,9091端口
server:
address: 'tcp://0.0.0.0:9091/'
disable_healthcheck: false
# 此处指定用于 Authelia 存放日志的目录
log:
file_path: '/config/authelia.log'
# 2FA-动态口令的相关配置
totp:
disable: false
issuer: '你自定的TOTP令牌签发者名字' # 此处设置会在例如 Google/Microsoft Authenticator 等应用中显示为动态口令的标题
algorithm: 'sha1' # 动态口令的加密算法,默认为 SHA1,也支持 SHA256/512
digits: 6 # 动态口令位数
period: 30 # 口令的刷新周期,单位秒
skew: 0 # 有效口令的相位差,若设置为 1,则当前周期 ±1 周期内的口令都会被视作正确口令,谨慎调整
secret_size: 32 # 公钥长度,保持 32 默认即可
# 2FA-WebAuthn 的相关配置
webauthn:
disable: false # 保持默认以开启 WebAuthn 认证方式即可
# 访客身份认证相关配置
identity_validation:
reset_password: # 密码重置相关设置,除 JWT 密钥外保持默认即可
expiration: '5m'
jwt_algorithm: 'HS256'
jwt_secret: '你自定的JWT加密密钥#1,尽量多于20个随机字符,很重要'
elevated_session: # Authelia 发送的一次性验证码相关设置
expiration: '5m' # 一次性验证码的过期时间
elevation_expiration: '10m'
characters: 6 # 验证码长度
# 时钟校准设置,由于 TOTP 依赖时间计算口令,不准确的系统时钟可能会造成认证错误
ntp:
address: 'udp://ntp.aliyun.com:123' # 你指定的授时服务器
max_desync: '3s' # 与授时服务器时间差的最大容错
# Authelia 后端认证配置
authentication_backend:
password_reset:
disable: false # 开启密码重置功能
file:
path: '/config/users_database.yml' # Authelia 用于保存已注册用户信息的目录
# 访问控制配置
access_control:
default_policy: 'deny' # 默认拒绝所有未授权的访问
rules:
- domain: '你准备的Authelia域名,如auth.example.com' # 此处填写 Authelia 的域名用于绕过认证自己
policy: 'bypass'
- domain: # 此处填写仅需要 Authelia 提供用户名及密码认证的受保护的域名
- '仅需要密码验证的服务域名 #1'
- '仅需要密码验证的服务域名 #2,3...'
policy: 'one_factor'
- domain: # 此处填写需要 Authelia 提供 2FA 两步验证的受保护的域名
- '需要两步验证2FA的服务域名 #1,如图中的B.exmaple.com'
- '需要两步验证2FA的服务域名 #2,3...'
policy: 'two_factor'
# 浏览器 Session 设置
session:
secret: '你自定的Session加密密钥#2,尽量多于20个随机字符,推荐和上一个不一样'
cookies:
domain: '你的根域名,如example.com' # 请务必填写你的根域名
authelia_url: 'https://你准备的Authelia域名' # 请务必要填 https,否则 Authelia 会自检不通过
inactivity: '30m' # Authelia 判定用户转为不活跃状态前的等待时间
expiration: '2h' # 用户未勾选 “记住我” 选项时的 Session 过期时间
remember_me: '6h' # 用户勾选 “记住我” 选项时的 Session 过期时间
# Authelia 本地存储配置
storage:
encryption_key: '你自定的数据加密密钥#3,尽量多于20个随机字符'
local:
path: '/config/db.sqlite3' # 默认的 Sqlite 数据库文件位置,如需要配置 Postgresql 或者 MySQL 请参考官网
# Authelia 一次性验证码相关配置
notifier:
disable_startup_check: false
filesystem:
filename: '/config/notification.txt' # 当未配置 SMTP 服务时,请配置本地文件位置以接收一次性验证码
...
---
users:
<你的用户名>: # 用于登录的用户名
disabled: false
displayname: "<你的用户显示名称>" # 显示在 Authelia 网页中的名字,不是用于登录的用户名
password: "$argon2id$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 请前往网站 https://argon2.online/ 在线计算你的密码,默认的密码生成配置如下图,请手动填写并生成,复制 Encoded Form 并粘贴至此处
email: "<你的邮箱>"
groups:
- admins
- dev
...
为 Authelia 配置 Nginx 反向代理
经过了以上的操作,你现在应该有一个运行正常的Authelia容器。现在你需要把Authelia服务暴露到公网并测试其工作情况,在添加Web应用反向代理到Authelia之前,最好先调试Authelia自身,确认其可以正常进行用户身份认证。下表列出了这一节以及下一节需要用到的说法及其指代内容。以下内容以1Panel作为面板工具演示,其他面板请进行相应操作即可。
项目 | 服务地址/主机名 | 域名 |
根域名 | X | example.com |
云服务器A本机 | 127.0.0.1/111.2.3.4(公网)/ServerA | X |
Authelia服务 | 127.0.0.1:9091(9091未暴露到公网)/ServerA | auth.example.com |
Web应用A(不受保护) | 127.0.0.1:1111(1111未暴露到公网)/ServerA | a.example.com |
Web应用B(受保护) | 127.0.0.1:2222(2222未暴露到公网)/ServerA | b.example.com |
Web应用C(受保护) | 222.3.4.5:3333(3333未暴露到公网)/ServerB | c.example.com3 |
location / {
set $upstream_authelia http://127.0.0.1:9091;
proxy_pass $upstream_authelia;
client_body_buffer_size 128k;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
send_timeout 5m;
proxy_read_timeout 360;
proxy_send_timeout 360;
proxy_connect_timeout 360;
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;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect http:// $scheme://;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 64 256k;
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.0.0.0/8;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from fc00::/7;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
}
为Web应用配置Nginx反向代理
# 此处以在 ServerA 上的应用 B 为例进行配置
location /authelia {
internal;
set $upstream_authelia http://127.0.0.1:9091/api/verify; # 配置 Authelia 服务的地址
proxy_pass_request_body off;
proxy_pass $upstream_authelia;
proxy_set_header Content-Length "";
client_body_buffer_size 128k;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
send_timeout 5m;
proxy_read_timeout 360;
proxy_send_timeout 360;
proxy_connect_timeout 360;
proxy_set_header Host $http_host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect http:// $scheme://;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 4 32k;
add_header Strict-Transport-Security "max-age=31536000";
}
location / {
set $upstream_webapp_b http://127.0.0.1:2222; # upstreamm_webapp_b 请自行更改为自己方便识别的名称,后面是你的 Web 应用的地址
proxy_pass $upstream_webapp_b; # 同上
auth_request /authelia;
auth_request_set $target_url $scheme://$http_host$request_uri;
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
error_page 401 = 302 https://auth.example.com/?rd=$target_url; # 修改成你的 Authelia 服务域名,注意是 HTTPS
client_body_buffer_size 128k;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
send_timeout 5m;
proxy_read_timeout 360;
proxy_send_timeout 360;
proxy_connect_timeout 360;
proxy_set_header Host $http_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;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect http:// $scheme://;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 64 256k;
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.0.0.0/8;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from fc00::/7;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
}
全站加速DCDN配置
一些个人考虑
互联网险恶,做个人文章分享还好,做点其他带点商业性质的,稍有不慎就会被打。在公网上暴露服务器的真实IP是很危险的一个操作,如何隐藏自己服务器的真实IP就显得非常重要。目前主流中简单易操作的方式就是利用CDN来给服务器嵌套一层壳,让CDN服务器挡在你的真实服务器之前。
DCDN及DNS配置
(重要)回源配置-回源SNI:auth.example.com (添加的加速域名是什么就填什么)
动静态加速规则-动态内容回源配置-动态内容协议跟随回源:HTTPS
并修改HTTPS配置-强制跳转:HTTP -> HTTPS
脚注
- 请注意Authelia对不同的反向代理服务应用的支持情况不一,请参考官方提供的兼容性表格。 ↩︎
- 在Authelia配置的有效认证策略或认证有效时间内(如1小时内)无需二次认证,认证信息过期后仍需要重新认证。 ↩︎
- 此处的应用C虽然部署在另一台服务器上,但由于使用了*.example.com的域名,同样可以被同一个Authelia网关所保护,但如果应用C使用了其他域名如c.elpmaxe.com等,则需要更复杂的跨域SSO配置,本文不做讨论。 ↩︎
参考资料
- 单点登录服务Authelia(上篇) | 老苏的blog (laosu.cf)
- Authelia – SSO and 2FA portal (blackvoid.club)
- Prologue – Configuration – Authelia
- 什么是SNI以及如何配置回源SNI_CDN(CDN)-阿里云帮助中心 (aliyun.com)