Channing He
Channing He
Articles16
Tags9
Categories0
Tinyauth 自托管 身份验证 中间件

Tinyauth 自托管 身份验证 中间件

Source && Doc

https://github.com/steveiliop56/tinyauth?tab=readme-ov-file
https://tinyauth.app/docs/about.html
强烈建议阅读,此文章只是个推荐,重复造轮子

介绍

首先说一下需求,在Selfhost 缺少身份验证或者是类似PHP等这种很容易存在漏洞应用,需要多一层验证(当然最佳实践应该是直接使用VPN内部访问,不公开到公网,但是有些应用还是存在这种使用场景)。
本身其实有大量的身份验证应用比如Authelia/Authentik/Keycloack之类。

原因1

大部分这些工具为了企业级生产力需求会十分复杂。比如之前使用的Authentik,他的compose需要简简单单147行(

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
services:
  authentik-postgresql:
    image: docker.io/library/postgres:16-alpine
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 5s
    volumes:
      - ./database:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: ${PG_PASS:?database password required}
      POSTGRES_USER: ${PG_USER:-authentik}
      POSTGRES_DB: ${PG_DB:-authentik}
    env_file:
      - .env
    networks:
      - default

  authentik-redis:
    image: docker.io/library/redis:alpine
    command: --save 60 1 --loglevel warning
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 3s
    volumes:
      - redis_authentik:/data
    networks:
      - default
  authentik-server:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG}
    restart: unless-stopped
    command: server
    environment:
      AUTHENTIK_REDIS__HOST: authentik-redis
      AUTHENTIK_POSTGRESQL__HOST: authentik-postgresql
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
    volumes:
      - ./authentik/media:/media
      - ./authentik/custom-templates:/templates
      # - /var/run/docker.sock:/var/run/docker.sock
    env_file:
      - .env
    # ports:
    #   - "${COMPOSE_PORT_HTTP:-9000}:9000"
    #   - "${COMPOSE_PORT_HTTPS:-9443}:9443"
    networks:
      - public_web
      - default
    depends_on:
      authentik-postgresql:
        condition: service_healthy
      authentik-redis:
        condition: service_healthy
    labels:
      homepage.group: Networking
      homepage.name: Authentik
      homepage.icon: authentik
      homepage.href: "https://auth.CHANGEME.com"
      traefik.enable: true
      traefik.http.routers.authentik.rule: Host(`auth.CHANGEME.com`)
      traefik.http.services.authentik.loadbalancer.server.port: 9000
      traefik.docker.network: public_web
      traefik.public: true
  authentik-proxy:
    image: ghcr.io/goauthentik/proxy:${AUTHENTIK_TAG:-2024.10.5}
    # ports:
    #     - 9000:9000
    #     - 9443:9443
    networks:
      - public_web
      - default
    environment:
        AUTHENTIK_REDIS__HOST: authentik-redis
        AUTHENTIK_HOST: http://authentik-server:9000
        AUTHENTIK_INSECURE: "true"
        AUTHENTIK_TOKEN: ${AUTHENTIK_TRAEFIK_EXT_OUTPOST_TOKEN}
        # Starting with 2021.9, you can optionally set this too
        # when authentik_host for internal communication doesn't match the public URL
        AUTHENTIK_HOST_BROWSER: https://auth.CHANGEME.com
        # for logging edit log_level in outpost config from ui
    labels:
        traefik.enable: true
        traefik.port: 9000
        traefik.http.routers.authentik-proxy.rule: Host(`CHANGEME.com`) && PathPrefix(`/outpost.goauthentik.io/`)
        # `authentik-proxy` refers to the service name in the compose file.
        traefik.http.middlewares.authentik-proxy.forwardauth.address: http://authentik-proxy:9000/outpost.goauthentik.io/auth/traefik
        traefik.http.middlewares.authentik-proxy.forwardauth.trustForwardHeader: true
        traefik.http.middlewares.authentik-proxy.forwardauth.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
        traefik.public: true
        kop.namespace: none

    restart: unless-stopped
  worker:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.10.5}
    restart: unless-stopped
    command: worker
    environment:
      AUTHENTIK_REDIS__HOST: authentik-redis
      AUTHENTIK_POSTGRESQL__HOST: authentik-postgresql
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
    # `user: root` and the docker socket volume are optional.
    # See more for the docker socket integration here:
    # https://goauthentik.io/docs/outposts/integrations/docker
    # Removing `user: root` also prevents the worker from fixing the permissions
    # on the mounted folders, so when removing this make sure the folders have the correct UID/GID
    # (1000:1000 by default)
    user: root
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./authentik/media:/media
      - ./authentik/certs:/certs
      - ./authentik/custom-templates:/templates
    env_file:
      - .env
    depends_on:
      authentik-postgresql:
        condition: service_healthy
      authentik-redis:
        condition: service_healthy
    networks:
      - default
        
networks:
  default:
    internal: true
  public_web:
    external: true

volumes:
  redis_authentik:
    driver: local

原因2

最近把家里的架构由Nginx手动创建变成了Compose + Traefik,现在我创建一个服务的反向代理,只需要向下面这样,在docker compose,反向代理将自动化生成。所以支持通过labels描述,并且自动加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
labels:
  traefik.enable: true
  traefik.public: true
  traefik.docker.network: traefik_external_public_web
  #-----
  traefik.http.routers.hlpj-alist.rule: Host(`alist.homelabproject.cc`)||Host(`file.homelabproject.cc`)
  traefik.http.routers.hlpj-alist.entrypoints: cf
  traefik.http.services.hlpj-alist.loadbalancer.server.port: 5244
  traefik.http.routers.hlpj-alist.service: hlpj-alist
  #---cloudflared---
  cloudflare.tunnel.enable: "true"
  cloudflare.tunnel.0.hostname: alist.homelabproject.cc
  cloudflare.tunnel.0.service: http://traefik:808
  cloudflare.tunnel.0.zonename: homelabproject.cc
  cloudflare.tunnel.1.hostname: file.homelabproject.cc
  cloudflare.tunnel.1.service: http://traefik:808
  cloudflare.tunnel.1.zonename: homelabproject.cc

配置

基础容器

首先你需要最基础3个条件

  • SECERT变量
    直接在命令行行随机生成一个32字节的随机密钥
1
openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 32
  • USERS
    你的用户名密码,命令行输入下面,会进入交互,记得在问你是否使用docker的时候选择yes
1
docker run -i -t --rm ghcr.io/steveiliop56/tinyauth:v3 user create --interactive

你就会得到转换完用于登陆的账号密码的bcrypt 哈希。如果你有多个账号密码用,隔开

  • 用于验证的域名
    tinyauth的访问流程:当你访问需要身份验证的域名,他会转条到tinyauth.你的域名.com验证账号密码,然后你再回到你服务的域名就能正常访问了。
    所以需要提前配置好你的域名

最后,配置你下面的环境变量,启动即可

1
2
3
4
5
6
7
8
9
10
11
12
tinyauth:
  image: ghcr.io/steveiliop56/tinyauth:v3
  container_name: tinyauth
  restart: unless-stopped
  environment:
    - SECRET=some-random-32-chars-string
    - APP_URL=https://tinyauth.你的域名.com
    - USERS=your-username-password-hash
  labels:
    traefik.enable: true
    traefik.http.routers.tinyauth.rule: Host(`tinyauth.你的域名.com`)
    traefik.http.middlewares.tinyauth.forwardauth.address: http://tinyauth:3000/api/auth/traefik

配置需要验证的应用

你只需要附带Label,添加Router的中间件,即可访问

1
2
labels:
	traefik.http.routers.[你的服务].middlewares: tinyauth@docker

总结

tinyauth的目的本身就不是为了生产力,对于Homelab来说就是简洁高效,个人觉得还是挺好用。

Author:Channing He
Link:https://homelabproject.cc/Container/Tinyauth%20%E8%87%AA%E6%89%98%E7%AE%A1%20%E8%BA%AB%E4%BB%BD%E9%AA%8C%E8%AF%81%20%E4%B8%AD%E9%97%B4%E4%BB%B6/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可