使用 Authentik 保护任何通过 Traefik 反代的应用

推荐观看 Christian Lempa 的视频,然后跳过阅读这篇文章

动机

Traefik 是我很喜欢的反代程序,Authentik 是一个我最近开始尝试的支持自建的身份认证系统。Authentik 的 Outpost是一种可以部署在外部的组件,提供了非常大的灵活性。通过与 Traefik 的集成,可以为任何被 Traefik 反代的应用提供认证。

假设

*如果所有东西都是部署在同一台主机上的话,简单的创建一个本地 Outpost 即可

通过HTTPS连接Docker Socket

Authentik需要通过"integration"与Docker进行通信,因此我们首先需要在服务器 A 上配置Docker守护进程,使其支持安全的HTTPS连接。这遵循Docker官方的保护Docker守护进程安全的最佳实践

准备证书

在运行Traefik的服务器上,我们需要创建一套TLS证书,包括CA证书、服务端证书和客户端证书。

1. 创建证书存储目录

mkdir -p /docker/certs
cd /docker/certs

2. 创建CA证书和密钥

# 创建CA私钥
openssl genrsa -out ca-key.pem 4096

# 创建CA证书,有效期10年(自行调整)
openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem

在创建CA证书时,系统会提示您输入一些信息。特别注意Common Name (CN)字段,填入服务器的FQDN。

3. 创建服务端证书和密钥

# 创建服务端私钥
openssl genrsa -out server-key.pem 4096

# 创建签名请求,将CN替换为您的服务器FQDN
openssl req -subj "/CN=host1.example.com" -sha256 -new -key server-key.pem -out server.csr

# 添加签名配置
echo subjectAltName = DNS:host1.example.com,IP:1.2.3.4,IP:127.0.0.1 > extfile.cnf
echo extendedKeyUsage = serverAuth >> extfile.cnf

# 签发服务端证书,有效期10年(3650天)
openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf

重要提示:请将DNS:host1.example.com,IP:1.2.3.4替换为您服务器的实际域名和IP地址。保留IP:127.0.0.1以支持本地连接。

4. 创建客户端证书和密钥

# 创建客户端私钥
openssl genrsa -out client-key.pem 4096

# 创建签名请求
openssl req -subj "/CN=client" -sha256 -new -key client-key.pem -out client.csr

# 添加客户端扩展配置
echo extendedKeyUsage = clientAuth > extfile-client.cnf

# 签发客户端证书,有效期10年(3650天)
openssl x509 -req -days 3650 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf

5. 清理临时文件

生成所有证书后,您应该有以下文件:

├── ca-key.pem       # CA私钥
├── ca.pem           # CA证书
├── ca.srl           # CA序列号文件
├── cert.pem         # 客户端证书
├── client-key.pem   # 客户端私钥
├── client.csr       # 客户端证书请求(可删除)
├── extfile-client.cnf # 客户端扩展配置(可删除)
├── extfile.cnf      # 服务端扩展配置(可删除)
├── server-cert.pem  # 服务端证书
├── server-key.pem   # 服务端私钥
└── server.csr       # 服务端证书请求(可删除)

接下来,删除不再需要的临时文件:

rm -v client.csr server.csr extfile.cnf extfile-client.cnf

6. 设置正确的文件权限

为了安全起见,设置适当的文件权限:

chmod -v 0400 ca-key.pem client-key.pem server-key.pem  # 仅所有者可读
chmod -v 0444 ca.pem server-cert.pem cert.pem           # 所有用户可读

为Docker守护进程配置远程访问

接下来,我们需要配置Docker守护进程,使其支持TLS加密的远程访问。我们将通过systemd的override机制修改Docker的配置,而不是直接编辑原始的服务文件。

1. 创建override目录

mkdir -p /etc/systemd/system/docker.service.d

2. 创建override配置文件

vim /etc/systemd/system/docker.service.d/override.conf

3. 添加配置内容

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://YOUR_SERVER_IP:PORT --tlsverify --tlscacert=/docker/certs/ca.pem --tlscert=/docker/certs/server-cert.pem --tlskey=/docker/certs/server-key.pem

重要提示

  • 请将YOUR_SERVER_IP替换为您服务器的实际IP地址
  • 确保证书路径正确对应您存储证书的位置
  • 端口PORT可以根据需要自定义,但请确保防火墙允许此端口的TCP连接

4. 重载systemd配置并重启Docker

sudo systemctl daemon-reload
sudo systemctl restart docker

5. 验证Docker守护进程是否正在监听

sudo netstat -lntp | grep dockerd

在Authentik中配置集成

现在Docker守护进程已经配置为支持TLS连接,我们需要在Authentik中配置相应的证书和集成。

添加证书到Authentik

  1. 登录到Authentik管理界面
  2. 导航到System > Certificates
  3. 点击Create按钮

添加CA证书

添加客户端证书

创建Docker集成

  1. 导航到System > Outpost Integrations
  2. 点击Create > Docker Service-Connection
  3. 填写以下信息:
    • Name: host1-docker
    • Docker URL: https://YOUR_SERVER_IP:PORT
    • TLS Verification Certificate: 选择host1-docker-ca
    • TLS Authentication Certificate/SSH Keypair: 选择host1-docker-client
  4. 点击Create保存
  5. 点击Refresh按钮,状态(State)应显示绿色

创建Provider和Application

我们以Traefik自带的Dashboard为例,配置一个受Authentik保护的应用。

创建Provider

  1. 导航到Applications > Providers
  2. 点击Create
  3. 选择Forward auth (single application)
  4. 填写以下信息:
    • Name: traefik-host1
    • 根据需要配置其他选项如外部主机、转发身份验证URL等
  5. 点击Create保存

创建Application

  1. 导航到Applications > Applications
  2. 点击Create
  3. 填写以下信息:
    • Name: Traefik Dashboard
    • Slug: traefik-dashboard
    • Provider: 选择刚才创建的traefik-host1
  4. 配置其他选项如策略、元数据等
  5. 点击Create保存

创建Outpost

Outpost是Authentik的代理组件,负责处理认证请求。

  1. 导航到Applications > Outposts

  2. 点击Create

  3. 填写以下信息:

    • Name: host1-authentik-outpost
    • Type: Proxy
    • Integration: 选择前面创建的host1-docker
    • Applications: 将traefik-host1添加到右侧列表
  4. 点击Advanced settings,添加以下配置:

    authentik_host: https://authentik.your-domain.com/
    object_naming_template: host1-authentik-outpost
    docker_network: frontend
    

    注意:请将authentik.your-domain.com替换为您的Authentik实例的实际URL

  5. 点击Create保存

创建完成后,Docker集成会在远程服务器上自动创建一个名为host1-authentik-outpost的容器。刷新页面后,Outpost的状态应显示为绿色对勾。

注意:有时容器创建可能需要一些时间。如果容器已创建但未自动启动,可在远程服务器上运行docker ps -a查看状态,并通过docker start host1-authentik-outpost手动启动。

配置Traefik集成

最后,我们需要配置Traefik以使用Authentik进行身份验证。

添加Authentik中间件

参考Authentik官方文档,在Traefik配置中添加以下中间件定义:

http:
  middlewares:
    authentik:
      forwardAuth:
        address: http://host1-authentik-outpost:9000/outpost.goauthentik.io/auth/traefik
        trustForwardHeader: true
        authResponseHeaders:
          - X-authentik-username
          - X-authentik-groups
          - X-authentik-entitlements
          - X-authentik-email
          - X-authentik-name
          - X-authentik-uid
          - X-authentik-jwt
          - X-authentik-meta-jwks
          - X-authentik-meta-outpost
          - X-authentik-meta-provider
          - X-authentik-meta-app
          - X-authentik-meta-version

重要提示:请将 host1-authentik-outpost替换为实际的Outpost容器名称。

应用中间件到Traefik路由

如果使用 Docker Compose 管理Traefik,在Traefik服务的标签中添加中间件配置:

services:
  traefik:
    # ... 其他配置 ...
    labels:
      # ... 其他标签 ...
      - traefik.http.routers.traefik-dashboard.middlewares=authentik@file

添加另一个应用?

通过上面的步骤,我们就将 Authentik 认证添加到了 Traefik Dashboard。 如果想要将同在 A 服务器上另一个被 Traefik 反代的应用 App1 也用 Authentik 保护起来的话,需要:

  1. App1 创建另一个 Application (和 Provider),比如叫做 app1-host1
  2. 进入 Application/Outposts,编辑 host1-authentik-outpost,将 app1-host1 也添加到右边

参考资料