====== Реализация SSO с помощью Authentik ====== {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/banner.png?nolink&}} ===== Введение ===== [[https://goauthentik.io/|Authentik]] - это провайдер аутентификации с [[https://github.com/goauthentik/authentik?tab=readme-ov-file|открытым исходным кодом]], который отличается гибкостью и универсальностью, поддерживая широкий набор протоколов. При развертывании приложений в домашней лаборатории вы можете столкнуться с тем, что некоторые из них вовсе не поддерживают аутентификацию либо поддерживают базовую в которой могут иметься уязвимости. Так же малое количество сервисов из коробки поддерживает 2FA (двухфакторная аутентификация). Помимо этого для каждого сервиса вам приходится придумывать отдельно логин и пароль, что может запутать когда этих сервисов у вас много. Выход из всего этого есть и это - **Authentik**. Технология единого входа (Single sign-on SSO) — метод аутентификации, который позволяет пользователям безопасно аутентифицироваться сразу в нескольких приложениях и сайтах, используя один набор учетных данных. ===== Развертывание Authentik ===== Развертывать Authentik будем при помощи Docker Compose и использовать в связке с обратным прокси сервером [[https://doc.traefik.io/traefik/user-guides/docker-compose/basic-example/|Traefik]]. Для этого переходим на [[https://docs.goauthentik.io/docs/install-config/install/docker-compose|страницу документации]] Authentik с использованием Docker Compose и внимательно изучаем ее. Нам предлагается сразу загрузить готовый ''docker-compose'' файл при помощи команды: wget https://goauthentik.io/docker-compose.yml \\ Так как Authentik не поддерживает тег latest после каждого обновления на сайте публикуется новый docker-compose файл с изменения версий docker образов.\\ \\ \\ Возьмем за основу шаблон с сайта актуальной на момент написания заметки 2025 года. ''docker-compose.yaml'' 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: ${PG_PASS:?database password required} POSTGRES_USER: ${PG_USER:-authentik} POSTGRES_DB: ${PG_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:-2025.6.1} restart: unless-stopped command: server environment: AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required} AUTHENTIK_REDIS__HOST: redis AUTHENTIK_POSTGRESQL__HOST: postgresql AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} volumes: - ./media:/media - ./custom-templates:/templates env_file: - .env ports: - "${COMPOSE_PORT_HTTP:-9000}:9000" - "${COMPOSE_PORT_HTTPS:-9443}:9443" depends_on: postgresql: condition: service_healthy redis: condition: service_healthy worker: image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1} restart: unless-stopped command: worker environment: AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required} AUTHENTIK_REDIS__HOST: redis AUTHENTIK_POSTGRESQL__HOST: 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 - ./media:/media - ./certs:/certs - ./custom-templates:/templates env_file: - .env depends_on: postgresql: condition: service_healthy redis: condition: service_healthy volumes: database: driver: local redis: driver: local Далее согласно документации нужно сгенерировать пароль и секретный ключ в файл с переменными ''.env'' echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')">> .env echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')">> .env Так же можно настроить порты, т.к. по умолчанию authentik прослушивает внутренний порт 9000 для HTTP и 9443 для HTTPS. Поэтому чтобы пробросить порты 80 и 443, вы можете задать переменные ''COMPOSE_PORT''. Но нам это не нужно так как на этих портах уже работает Traefik. ''.env'' PG_PASS= AUTHENTIK_SECRET_KEY= #COMPOSE_PORT_HTTPS=80 #COMPOSE_PORT_HTTP=433 # SMTP Host Emails are sent to AUTHENTIK_EMAIL__HOST=localhost AUTHENTIK_EMAIL__PORT=25 # Optionally authenticate (don't add quotation marks to your password) AUTHENTIK_EMAIL__USERNAME= AUTHENTIK_EMAIL__PASSWORD= # Use StartTLS AUTHENTIK_EMAIL__USE_TLS=false # Use SSL AUTHENTIK_EMAIL__USE_SSL=false AUTHENTIK_EMAIL__TIMEOUT=10 # Email address authentik will send from, should have a correct @domain AUTHENTIK_EMAIL__FROM=authentik@localhost Перед запуском контейнера обязательно проверьте локальное время на сервере, чтобы избежать проблем с аутентификацией. timedatectl Local time: Sat 2024-10-19 23:59:41 MSK Universal time: Sat 2024-10-19 20:59:41 UTC RTC time: Sat 2024-10-19 20:59:41 '' Time zone: Europe/Moscow (MSK, +0300) System clock synchronized: yes NTP service: active RTC in local TZ: no Если время не совпадает то найдите и установите ваш часовой пояс: timedatectl list-timezones sudo timedatectl set-timezone Europe/Moscow Запускаем контейнер: docker compose pull docker compose up -d После запуска переходим по адресу [[http://:9000/if/flow/initial-setup/]] для первоначальной настройки. Там вам будет предложено установить пароль для пользователя по умолчанию ''akadmin''. После того как создали пароль и авторизовались создайте субдомен для Authentik, например ''authentik.domain.ru'' ===== Конфигурирование Traefik ===== Создаем файл динамической конфигурации для Authentik: ''ext_authentik.yml'' http: routers: authentik: rule: "Host(`authentik.domain.ru`)" entrypoints: - http middlewares: - authentik-https-redirect service: authentik authentik-secure: rule: "Host(`authentik.domain.ru`)" entrypoints: - https middlewares: tls: true service: authentik middlewares: authentik-https-redirect: redirectScheme: scheme: https services: authentik: loadBalancer: servers: - url: "http://192.168.78.110:9000" И сразу создадим промежуточный слой, который будет использоваться для включения авторизации в наших сервисах. ''authentik.yml'' http: middlewares: authentik: forwardAuth: address: "http://192.168.78.110:9000/outpost.goauthentik.io/auth/traefik" trustForwardHeader: true authResponseHeaders: - X-authentik-username - X-authentik-groups - 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 И еще один промежуточный слой для arr-стека, если вы планируете использовать Sonarr, Radarr, Prowlarr и т.д. ''media-authentik.yml'' http: middlewares: authentik-media: forwardAuth: address: "http://192.168.78.110:9000/outpost.goauthentik.io/auth/traefik" trustForwardHeader: true authResponseHeaders: - X-authentik-username - X-authentik-groups - 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 - Authorization Теперь переходим по вашему адресу ''authentik.domain.ru'' и логинимся. ===== Настройка Authentik ===== ==== Создание пользователя ==== Переходим в интерфейс администратора. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/1.jpg?nolink&}} Затем в левом меню переходим в ''Каталог > Пользователи'' и нажимаем **Создать**. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/2.jpg?nolink&}} Указываем username, отображаемое имя и почту. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/3.jpg?nolink&}} Теперь нам нужно установить пароль, для этого переходим в созданного пользователя и нажимаем **Установить пароль** {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/4.jpg?nolink&}} Затем переходим в группы, выбираем ''authentik Admins'', переходим на вкладку пользователи и нажимаем **Добавить существующего пользователя**, выбираем нашего пользователя **User** из списка и нажимаем добавить. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/5.jpg?nolink&}} Наш пользователь добавлен в группу суперпользователей. Теперь разлогинимся из аккаунта ''akadmin'' и авторизуемся под новым пользователем. После чего снова перейдем в раздел Пользователи, проваливаемся в пользователя ''akadmin'' и отключаем его нажав кнопку **Деактивировать** ==== Подключаем двухфакторную аутентификацию (2FA) ==== Нажимаем шестеренку в правом верхнем углу экрана или на иконку пользователя в нижнем левом если вы находитесь в панели администратора. Выбираем MFA-устройства и зарегистрировать **TOTP Device** {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/6.jpg?nolink&}} После этого вас перекинет на страницу привязки устройства. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/7.jpg?nolink&}} После этого перелогиниваемся и проверяем что после ввода пароля у вас запросят еще и OTP-код. ==== Создание провайдера и подключение приложения ==== Переходим в раздел провайдеры и создаем провайдера: {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/8.jpg?nolink&}} Выбираем тип провайдера Proxy Provider: {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/9.jpg?nolink&}} Поток провайдера выбираем ''explicit'' и Прямая аутентификация (уровень домена): {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/10.jpg?nolink&}} Прописываем наш субдомен на котором работает Authentik и домен для cookie: {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/11.jpg?nolink&}} После создания провайдера видим предупреждение что к нему не привязано ни одно приложение {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/12.jpg?nolink&}} Переходим в раздел приложения и приступаем к созданию, обязательно выбираем ранее созданный провайдер. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/13.jpg?nolink&}} После создания приложения, предупреждение должно исчезнуть. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/14.jpg?nolink&}} Теперь переходим в раздел внешние компоненты и перемещаем наше приложение из **Доступные приложения** в **Выбранные приложения**: {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/15.jpg?nolink&}} В конфигурации обязательно проверяем что имя домена для ''authentik_host'' указано верно. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/16.jpg?nolink&}} На этом конфигурация окончена. ==== Подключаем Authentik к Traefik и проксируемым через него приложениям ==== Теперь перейдем к файлу динамической конфигурации самого Traefik и подключим аутентификацию, добавив промежуточный слой ''authentik'' ''ext_traefik.yml'' http: routers: traefik: rule: "Host(`traefik.domain.ru`)" entrypoints: - http middlewares: - traefik-https-redirect - authentik service: api@internal traefik-secure: rule: "Host(`traefik.domain.ru`)" entrypoints: - https middlewares: - authentik tls: true service: api@internal middlewares: traefik-https-redirect: redirectScheme: scheme: https Теперь при входе в дашборд Traefik необходимо будет авторизоваться. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/17.jpg?nolink&}} После этого можно подключить аутентификацию на любом вашем сервисе, просто добавив промежуточный слой. Но при подключении к другим приложениям, экран входа меняться не будет. Всегда будет написано ''Войдите чтобы перейти на traefik''. Чтобы этого избежать нужно как и ранее создать еще одного Proxy-провайдера но выбрать **Переадресация аутентификации (одно приложение)** и указать домен на котором развернуто приложение. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/18.jpg?nolink&}} ==== Подключение OIDC-аутентификации ==== OpenID Connect (OIDC) — протокол аутентификации и получения информации о пользователе из внешней системы. Протокол обратно совместим с OAuth, разница заключается в том, что OpenID Connect используется для аутентификации, а OAuth для авторизации. На [[https://docs.goauthentik.io/integrations/|странице документации]] есть множество примеров интеграции со многими популярными приложениями, но некоторых в этом списке нет. Например разберем пример включения OIDC аутентификации на примере дашборда [[https://homarr.dev/|Homarr]]. Из документации - [[https://homarr.dev/docs/advanced/sso/|Single Sign On | Homarr documentation]] мы видим что само приложение это поддерживает, но нужно изменить ''docker-compose'' файл добавив туда некоторые переменные. ''docker-compose.yaml'' version: "3" services: homarr: container_name: homarr image: ghcr.io/ajnart/homarr:fix-oidc-wrong-redirect restart: unless-stopped volumes: # - /var/run/docker.sock:/var/run/docker.sock # Optional, only if you want docker integration - ./homarr/configs:/app/data/configs - ./homarr/icons:/app/public/icons - ./homarr/data:/data environment: AUTH_PROVIDER: oidc AUTH_OIDC_URI: https://authentik.domain.ru/application/o/homarr AUTH_LOGOUT_REDIRECT_URL: https://authentik.domain.ru/application/o/homarr/end-session/ AUTH_OIDC_CLIENT_SECRET: ${AUTH_OIDC_CLIENT_SECRET} AUTH_OIDC_CLIENT_ID: ${AUTH_OIDC_CLIENT_ID} AUTH_OIDC_CLIENT_NAME: Authentik AUTH_OIDC_ADMIN_GROUP: authentik Admins AUTH_OIDC_OWNER_GROUP: admin AUTH_OIDC_TIMEOUT: 3500 AUTH_OIDC_AUTO_LOGIN: false ports: - 7575:7575 networks: {} Создаем файл для хранения переменных ''.env'': nano .env Вместо **your_client_secret** и **your_client_id** вставляем соответствующие данные полученные из **Authentik**: ''.env'' AUTH_OIDC_CLIENT_SECRET='your_client_secret' AUTH_OIDC_CLIENT_ID='your_client_id' \\ NOTE На момент написания заметки, в образе latest были проблемы с редиректом после включения OIDC, поэтому использовался тег fix-oidc-wrong-redirect.\\ После этого нужно перейти в Authentik и создать новое приложение и провайдера. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/19.jpg?nolink&}} В **Перенаправляющие URI/Источники (RegEx)** указываем имя домена Homarr, например [[https://homarr.domain.ru|https://homarr.domain.ru]] {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/20.jpg?nolink&}} Копируем ID Клиента и Секрет клиента, вставляем в соответствующие переменные ''docker-compose'' файла. Создаем приложение и подключаем к нему ранее созданного провайдера. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/21.jpg?nolink&}} Разворачиваем настройки пользовательского интерфейса и указываем имя домена на котором развернут Homarr. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/22.jpg?nolink&}} После этого переходим в раздел Провайдеры, нажимаем на наш провайдер и справа вы увидите ссылки для редиректа. Нам понадобится **Эмитент конфигурации OpenID** для переменной ''AUTH_OIDC_URI'' и **URL-адрес выхода из системы** для ''AUTH_LOGOUT_REDIRECT_URL'' {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/23.jpg?nolink&}} После этого запускаем контейнер и видим что теперь мы можем войти с помощью Authentik {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/24.jpg?nolink&}} Возьмем еще один пример - [[https://www.portainer.io/|Portainer]]. Здесь все немного проще, во первых есть [[https://docs.goauthentik.io/integrations/services/portainer/|документация по интеграции]] а во вторых все переменные можно задать прям в панели управления. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/25.jpg?nolink&}} Cохраните настройки выйдите из аккаунта и убедитесь что теперь доступна аутентификация через OAuth. {{https://fatalex.cifro.net/lib/plugins/ckgedit/fckeditor/userfiles/image/devops/26.jpg?nolink&}}