Expose local services securely using authentik
This post will walk through my thoughts process to expose a service that runs on my local network
Premise
I already did expose service, which I have posted a bit from my previous blogs, quick recap on that:
while I can expose services with well-known good authentication (for example grafana or adguard-home) I can't expose services with no authentication (for example: dashy) and services with too basic authentication that it's insecure & easy to brute force (for example sonarr, radar, and qbittorrent)
The goal here is to have some authentication methods for all of my services so that we need authentication services
The Authentication Services
yes, I know the title already said that I use authentik, but the options for me are:
- Setup Google login and protect anything insecure with Google auth proxy
- Same as before, but instead of Google auth proxy, we use Pomerium
- explore auth services like keycloak, authelia or authentik
Setup Google login + auth proxy may be the easiest way to do, I'm familiar with it, but the last time I check, I must provide every Google auth proxy for every service that I have, and I have many services to expose.. this option is something that easy in the beginning but don't scale very well
Another similar option is Pomerium, I've also pretty familiar with Pomerium, and I still can google login proxy with the better value from previous options with just one deployment for all services that I have
Then I find authentik, something that I haven't used before. From the documentation, I can have one login method for all services that I have, for example, if I have logged on to https://grafana.wibenson.cloud, I can open https://homepage.wibenson.cloud without login, authentik also have other security protocol that I'd like to explore in the future. Authentik also seems preferred on this Reddit thread
hot damn, I'm in
Authentik
The setup itself is quite simple, and the guide from the official docs is quite good, I won't rewrite that here because I believe it's subject of changes (or I'm lazy), here is the new diagram after we have Authentik
There are only one cloudflare and Caddy service, I split it up to 3 just to understand the flow of each services, authentik itself has a lot of documented integration with services on their documentation, but in short, authentik proxy provider will work with a lot of services, for some that already have "solid" authentication like grafana, we will just add antoher layer of authentication, so that the user will login twice, once for authentik and another for the app itself, so that's why services like grafana that support external OAuth, it's better to use Authentik Oauth Provider to simplify authentication
Epilogue
some noteworthy thing to mention is:
- Authentik needs a lot of memory, the docs state the minimum requirement is 2 core and 2 GB of memory, I use around 900++ mb of memory
➜ authentik docker stats | grep authentik
04e80aafca1c authentik-worker-1 2.04% 240.6MiB / 7.506GiB 3.13% 332MB / 222MB 1.01MB / 0B 7
786fada5d82f authentik-server-1 1.68% 570.7MiB / 7.506GiB 7.42% 120MB / 177MB 21.4MB / 0B 48
277d8712366d authentik-postgresql-1 0.43% 78.05MiB / 7.506GiB 1.02% 93.4MB / 89.7MB 80.7MB / 326MB 10
9048807a0646 authentik-redis-1 0.38% 9.305MiB / 7.506GiB 0.12% 285MB / 347MB 3.99MB / 3.13GB 5
2. There's an integration with google login, and it does work. But to the point where this blog is written, I still have issue with how can I allow specific email to signup (or disable signup altogether).
3. Authentik does support authorization! it's really a nice feature that can be implemented in an organization, not really useful for self-hosted private projects because usually there's only one person accessing all this stuff.
4. There's a point where suddenly I can't login into authentik without error message, there's authentik log ERROR: invalid input syntax for type inet: "172.70.142.146:56164" at character 491
which.. don't really tell anything, except that it seems like this wasn't the correct format for IP address, hardcoding remove caddy's x-forwarded-for
solve the issue for me (Cloudflare already provide correct x-forwarded-for
), it was my mistake to overwrite it with remote_addr
Update 2023-07-28: Fix some wordings