Introduction

I would like to showcase an internet-accessible, hardened homelab some time in 2026. Before I forget, I need to document how to let people log into my Proxmox nodes with their Google accounts as auditors. This post assumes that network access has been provided one way or another.

Ingredients

  1. A domain name (managed by CloudflareDNS)
  2. PVE 9.1: Just-In-Time login target
  3. Cloudflared (for exposing Authentik’s ACME client)
  4. Authentik: OpenID login broker
  5. Google Cloud - Google Auth Platform Client
  6. A Google account
  7. Chatbot of your liking

Pre-Requisites

Proxmox VE with HTTPS

For authentication to work, services being exposed should have secured subdomains. This short blog by Ikiesow covers most of the process. Create API key from Cloudflare dashboard to be used by Proxmox VE under Datacenter/ACME for DNS-01 or HTTP-01 challanges.

Cloudflared Tunnel into LAN

Add a new cloudflared tunnel under Dashboard/Zero Trust/Networks/Connectors. Thereon, you can expose CIDR through that tunnel given that your client devices have WARP installed.

Having installed a tunnel, 3 free reedirects can be set up at Dashboard/Domains/your domain name/Rules/Page Rules for the free tier. These can be used for ACME HTTP-01 challanges if desired.

User management is beyond this post’s scope but One Time Password emails for logging in is fairly easy to set up.

Authentik instance with HTTPS

Authentik is deployed within docker compose. ACME is configured through webui at System/Certificates. A page rule is setup as mentioned above for simple HTTP-01 challange.

compose.yml can be found at the end of this post.

1
2
3
4
5
6
7
# .env - Generated by Gemini
AUTHENTIK_SECRET_KEY=yJRPaoeFOHY3B/klctBh0rQsSJjZx9rX1l0hAiNmaseoisb+
AUTHENTIK_POSTGRES_PASSWORD=PBE6rgEyiim+0IcALDgrpg==

AUTHENTIK_ERROR_REPORTING__ENABLED=true
# Set this to your external URL
AUTHENTIK_HOST=https://idm.bug.tr

Note that this exposes host device to the web.

Steps

Authentik Source

  1. Log into Google Cloud Platform, and create a new web application authentication under your project. This will give Client ID and Client Key. These will be used by Authentik to confirm a user via federation and retrieve their e-mail address from the provider (Google in this case).

  2. Create a new source at Directory/Federation and Social Login with credentials generated at the step above:

  • Provider Type: Google
  • User matching mode: Link to a user with identical email address
  • Callback URL: https://idm.bug.tr:8443/source/oauth/callback/google/

Authentik Provider

  1. Create a new mapping at Customization/Property Mappings for setting the same group for all future users:
  • Scope name: groups
  • Expression: return {"groups": ["auditers"]}
  1. Create a new Authentik OAuth2/OpenID Provider with following data:
  • Protocol Settings:
    • Client ID and Client Key are auto-generated.
    • Strict Redirect URIs:
      • https://pve1.bug.tr:8006/api2/json/access/openid/auth-code
      • https://pve1.bug.tr:8006
    • Signing key (use default)
    • Encryption key (leave empty as per Kelly Mansua’s notes)
    • Under __Advanced Protocol Settings:
  1. Create a new Authentik Application with following data:
  • Slug: ‘pve1’ (arbitrary, yet relevant)
  • Provider: select provider created above

Proxmox Pool and Role

  1. Create a new pool Audit at Datacenter/Permissions/Pools.

  2. Create a new role PoolAuditor with all the .Audit permissions: [ Sys.Audit, VM.Audit, SDN.Audit, VM.GuestAgent.Audit, Pool.Audit, Datastore.Audit, Mapping.Audit ]

  3. Create new OpenID Connect Server Realm authentik at Datacenter/Realms with:

  • Issuer URL: https://idm.bug.tr/application/o/pve1/, notice that pve1 is the slug above.
  • Client ID and Client Key credentials from provider creation
  • Scopes: openid email profile groups, notice that groups is scope name of property mapping above.
  • Default: yes
  • Autocreate Users: yes
  • Username Claim: email
  • Autocreate Groups: no
  • Groups Claim: groups just like scopes
  • Overwrite Groups:: yes
  1. Create a new group auditors-authentik. Naming is of the form <GroupName>-<RealmName>, where realm is defined on Proxmox VE and group is defined on property mapping above.

  2. Give permission PoolAuditor to group auditors-authentik to path /pool/Audit under Datacenter/Permissions.

  3. Add members to the pool at Resource Pool/Audit/Members/Edit to allow certain VMs and storages to be audited.

If all goes well, Proxmox login screen should redirect you to Authentik and there on to Google account selection. This specific setup requires changing Google accounts by oneself prior to logging in with another account (between photos 4 and 5 below).

  • Privileged resource pool visible by root accout. 01-root-user.png
  • Login page after logout (switched Realm) 02-login-page.png
  • Authentik’s admin account, switching account with “Not you?” button. Mind that internal accounts, as long as they have email addresses set, work as well. 03-change-authentik-user.png
  • Click on Google, then select a logged-in account there. 04-authentik-select-google.png
  • This will ask you of a username and then error out as shown. No problem head back to PVE. Also username is arbitrary information at this point. 05-authentik-logged-into-google.png
  • Logged in as a Just-In-Time / On-The-Fly user with automatically assigned group. Voilà! 06-newly-created-user.png

Honorable Mentions

  • This DevTo article by Miklos Halasz has gotton me on my feet. There he uses LLDAP and Keycloak. I have not yet concluded on how to integrate LDAP neatly, If it werent for next honorary mention, I could settle for his suggestion.

  • I have come across recent video on kanidm by SUSE after hearing about it from Gemini. I tried utilizing it, and it is promising. However, lack of a WebUI and Authentik having better support by Gemini has eliminated that application for this late-night experiment. Still, as a 4-year-old project it has some jaw-dropping encryption support, 2025 demo is a must watch!

Long Awaited Compose YAML

 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
# compose.yml for Authentik - Generated by Gemini
services:
  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: ${AUTHENTIK_POSTGRES_PASSWORD}
      POSTGRES_USER: ${AUTHENTIK_POSTGRES_USER:-authentik}
      POSTGRES_DB: ${AUTHENTIK_POSTGRES_DB:-authentik}
    env_file:
      - .env

  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:/data

  server:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.12.3}
    restart: unless-stopped
    command: server
    dns:
    - 1.1.1.1
    environment:
      AUTHENTIK_REDIS__HOST: redis
      AUTHENTIK_LISTEN__HTTPS: 0.0.0.0:443
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRES_USER:-authentik}
      AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRES_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD}
    volumes:
      - ./media:/media
      - ./custom-templates:/templates
    env_file:
      - .env
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      postgresql:
        condition: service_healthy
      redis:
        condition: service_healthy

  worker:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.12.3}
    restart: unless-stopped
    command: worker
    dns:
    - 1.1.1.1
    environment:
      AUTHENTIK_REDIS__HOST: redis
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRES_USER:-authentik}
      AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRES_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD}
    user: root
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./media:/media
      - ./certs:/certs
      - ./custom-templates:/templates
    env_file:
      - .env
    depends_on:
      postgresql:
        condition: service_healthy
      redis:
        condition: service_healthy

Bibliography

  1. Configure ACME via Cloudflare DNS in Proxmox by Ikiesow
  2. Using Authentik for Proxmox PVE 8 user and group mapping by Kelly Mansua
  3. Authentik: Proxmox VE Integration
  4. A Big Live Demo of Kanidm - William Brown (Everything Open 2025)
  5. Proxmox Certificate Management Docs
  6. How to configure OpenID authentication in Proxmox VE by Miklos Halasz