Repository: goauthentik/authentik

Issue:
Redis (Unix) Socket?
**Describe your question/**
Is it possible to run an authentik docker container (server and worker) with a redis unix socket rather than tcp?
Directly overwriting redis variables via user_settings.py doesn't appear to modify anything despite @BeryJu suggesting in [pull request #4036](https://github.com/goauthentik/authentik/pull/4036) it should be viable.

**Relevant infos**
Docker compose:
version: '3.4'

services:
  server:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:latest
    restart: unless-stopped
    command: server
    environment:
      AUTHENTIK_POSTGRESQL__HOST: ${PG_HOST}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER}
      AUTHENTIK_POSTGRESQL__NAME: ${PG_NAME}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_REDIS__HOST: ${REDIS_HOST}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
      AUTHENTIK_LISTEN__HTTP: ${AUTHENTIK_LISTEN__HTTP}
      AUTHENTIK_LISTEN__HTTPS: ${AUTHENTIK_LISTEN__HTTPS}
    volumes:
      - ./media:/media
      - ./custom-templates:/templates
      - /run/redis/redis-server.sock:/run/redis/redis-server.sock
      - /var/run/postgresql/.s.PGSQL.5432:/var/run/postgresql/.s.PGSQL.5432
      - ./user_settings.py:/data/user_settings.py
    ports:
      - "${AUTHENTIK_PORT_HTTP}:${AUTHENTIK_PORT_HTTP}"
      - "${AUTHENTIK_PORT_HTTPS}:${AUTHENTIK_PORT_HTTPS}"
  worker:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:latest
    restart: unless-stopped
    command: worker
    environment:
      AUTHENTIK_POSTGRESQL__HOST: ${PG_HOST}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER}
      AUTHENTIK_POSTGRESQL__NAME: ${PG_NAME}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_REDIS__HOST: ${REDIS_HOST}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
    user: authentik
    volumes:
      - ./media:/media
      - ./certs:/certs
      - ./custom-templates:/templates
      - /run/docker.sock:/var/run/docker.sock
      - /run/redis/redis-server.sock:/run/redis/redis-server.sock
      - /var/run/postgresql/.s.PGSQL.5432:/var/run/postgresql/.s.PGSQL.5432
      - ./user_settings.py:/data/user_settings.py

I didn't include the definition for ${REDIS_HOST} as sockets cannot be passed via environmental variables per [pull 4036](https://github.com/goauthentik/authentik/pull/4036).

**Logs**
DBG undefined | event=Loaded config logger=authentik.lib.config timestamp=1679734632.5913134 file=/authentik/lib/default.yml 
DBG undefined | event=Loaded environment variables logger=authentik.lib.config timestamp=1679734632.5915806 count=7 
INF undefined | event=Starting authentik bootstrap logger=authentik.lib.config timestamp=1679734632.59165 
INF undefined | event=PostgreSQL connection successful logger=authentik.lib.config timestamp=1679734632.5988 
INF undefined | event=Redis Connection failed, retrying... (Error 99 connecting to localhost:6379. Cannot assign requested address.) logger=authentik.lib.config timestamp=1679734633.600902 redis_url=redis://:@localhost:6379/0 

**Version and Deployment (please complete the following information):**
 - authentik version: 2023.3
 - Deployment: docker-compose

**Additional context**
docker exec -it authentik-stack-server-1 bash
authentik@283a42f97c09:/$ cd /data
authentik@283a42f97c09:/data$ ls -la
total 27
drwxr-xr-x  2 root root           3 Mar 25 08:24 .
drwxr-xr-x 33 root root          39 Mar 25 08:24 ..
-rw-rw-r--  1 1022 _runit-log 16463 Mar 25 08:45 user_settings.py
authentik@283a42f97c09:/data$ cat user_settings.py | grep redis
REDIS_PROTOCOL_PREFIX = "redis://"
if CONFIG.y_bool("redis.tls", False):
    REDIS_PROTOCOL_PREFIX = "rediss://"
    REDIS_CELERY_TLS_REQUIREMENTS = f"?ssl_cert_reqs={CONFIG.y('redis.tls_reqs')}"
_redis_url = (
    f"{quote_plus(CONFIG.y('redis.password'))}@{quote_plus(CONFIG.y('redis.host'))}:"
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": 'unix://run/redis/redis-server.sock',
        "TIMEOUT": int(CONFIG.y("redis.cache_timeout", 300)),
        "OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": 'unix://run/redis/redis-server.sock',
CELERY_BROKER_URL = 'redis+socket:///run/redis/redis-server.sock'
CELERY_RESULT_BACKEND = 'redis+socket:///run/redis/redis-server.sock'
    "redis": "WARNING",
authentik@283a42f97c09:/data$ 


Discussion:
According to the [redis-py docs](https://redis-py.readthedocs.io/en/stable/connections.html#generic-client) using the redis protocol prefix of `unix://` would allow defining the socket file. Unfortunately as you can see in the [wait_for_db.py#L44](https://github.com/goauthentik/authentik/blob/e542783fec5fea709c1d03554513a56fc5ba6622/lifecycle/wait_for_db.py#L44) and [settings.py#L186](https://github.com/goauthentik/authentik/blob/e542783fec5fea709c1d03554513a56fc5ba6622/authentik/root/settings.py#L186)the REDIS_PROTOCOL_PREFIX is currently hard coded and can't be overridden via environment variable. Also I believe the socket path would need to be constructed differently to the url based off of [this](https://docs.celeryq.dev/en/stable/getting-started/backends-and-brokers/redis.html).

@BeryJu Is this a environment variable you would consider adding? I'm currently switching all my containers to using unix sockets where possible and seeing quite a boost to performance where I have done so.
this is mostly doable with https://github.com/goauthentik/authentik/pull/9335 without having use the `user_settings.py` file, we need to make some more small adjustments in the startup to make it fully supported
@BeryJu Nice! Hopefully I can find time one of these days to redo my earlier PR based on that.

Resolving patch:
diff --git a/lifecycle/wait_for_db.py b/lifecycle/wait_for_db.py
--- a/lifecycle/wait_for_db.py
+++ b/lifecycle/wait_for_db.py
@@ -3,7 +3,6 @@
 import authentik. This is done by the dockerfile."""
 from sys import exit as sysexit
 from time import sleep
-from urllib.parse import quote_plus
 
 from psycopg import OperationalError, connect
 from redis import Redis
@@ -35,7 +34,7 @@ def check_postgres():
 
 
 def check_redis():
-    url = redis_url(CONFIG.get("redis.db"))
+    url = CONFIG.get("cache.url") or redis_url(CONFIG.get("redis.db"))
     while True:
         try:
             redis = Redis.from_url(url)
@@ -43,10 +42,7 @@ def check_redis():
             break
         except RedisError as exc:
             sleep(1)
-            sanitized_url = url.replace(quote_plus(CONFIG.get("redis.password")), "******")
-            CONFIG.log(
-                "info", f"Redis Connection failed, retrying... ({exc})", redis_url=sanitized_url
-            )
+            CONFIG.log("info", f"Redis Connection failed, retrying... ({exc})")
     CONFIG.log("info", "Redis Connection successful")
 
 


Test patch: