myśli (16)
Jak zalogować się do Grafany przez Authelię jako admin?
Ostatnio hobbystycznie wracam do zabawy w selfhosting — jeden z tych okresowych nawrotów, gdzie na nowo można rozwiązać stare problemy, testując różne podejścia do rzeczy, które kiedyś już “rozwiązałem”1. Tym razem przyszła kolej na monitoring.
Zdziwiło mnie, że zaraz po skonfigurowaniu OIDC nie mogłem dodać żadnego dashboardu w Grafanie — logowanie działało, a mimo to brakowało uprawnień.
Setup
Grafana stała już za Authelią (self-hosted SSO, jeden użytkownik, w grupie admins) przez natywne OIDC2 (auth.generic_oauth). Zadanie wydawało się trywialne: każdy z grupy admins ma dostawać rolę GrafanaAdmin w Grafanie automatycznie przy logowaniu, zamiast nadać ręcznie w UI — i tak zostałoby nadpisane przy każdym logowaniu, bo allow_sign_up: true re-provisionuje usera za każdym razem.
Grafana
Standardowa, udokumentowana ścieżka: scope groups na kliencie OIDC + role_attribute_path (wyrażenie JMESPath3) po stronie Grafany.
Grafanę stawiam przez Ansible, rolą grafana.grafana.grafana. Najważniejszy fragment configu to zmienna grafana_ini_oauth:
grafana_ini_oauth:
"auth.generic_oauth":
enabled: true
name: Authelia
client_id: grafana
client_secret: "{{ grafana_authelia_oidc_secret | default('') }}"
scopes: "openid profile email groups"
auth_url: "https://authelia.example.com/api/oidc/authorization"
token_url: "https://authelia.example.com/api/oidc/token"
api_url: "https://authelia.example.com/api/oidc/userinfo"
use_pkce: true
allow_sign_up: true
role_attribute_path: "contains(groups[*], 'admins') && 'GrafanaAdmin' || 'Viewer'"
Admin user jest jedynym członkiem grupy admins w Authelii — stąd contains(groups[*], 'admins') w wyrażeniu wyżej. Warunek konieczny, żeby to zadziałało: scope groups musi być dodany do klienta OIDC Grafany, tak jak w configu powyżej.
Co miało się wydarzyć
Dokumentacja role_attribute_path w Grafanie opisuje trójstopniowy fallback: najpierw id_token, jeśli nic nie znajdzie — userinfo (api_url), jeśli nadal nic — access_token. Brzmi jak solidna redundancja.
Co się wydarzyło w praktyce
W Grafanie 13.2.1 fallback do userinfo jest zepsuty — potwierdzone przez grafana/grafana#106686. Jeśli claima nie ma w id_token, Grafana nie sprawdza userinfo tak, jak deklaruje dokumentacja.
Tymczasem Authelia od wersji 4.39 przestała domyślnie wrzucać claimy ze scope’ów (np. groups) do id_token — trafiają tylko do userinfo. To sensowne zaostrzenie bezpieczeństwa samo w sobie (mniej PII w tokenie, który trafia do różnych stron), ale w zderzeniu ze zepsutym fallbackiem Grafany daje cichy blackout: dokładnie ten claim, który ma znaczenie dla roli, nigdzie nie dociera.4
Fix po stronie Authelii
identity_providers.oidc.claims_policies po stronie Authelii — jawnie wymusza konkretne claimy z powrotem do id_token per-klient, referencjonowane z klienta przez claims_policy: <nazwa>.
identity_providers:
oidc:
# ...
claims_policies:
grafana: # nazwa polityki, dowolna, referencjonowana niżej
id_token:
- 'groups' # wymuś ten claim do id_tokenu
clients:
- client_id: 'inny'
# brak claims_policy — nie dostaje tego traktowania
- client_id: 'grafana'
client_secret: '...'
claims_policy: 'grafana' # podłączenie polityki do klienta
redirect_uris:
- 'https://grafana.example.com/login/generic_oauth'
scopes:
- 'openid'
- 'profile'
- 'email'
- 'groups' # musi być zażądany, inaczej nic do wymuszenia
Z tymi ustawieniami ponownie można logować się do Grafany jako admin — kolejny stary problem odhaczony, na nowo i inaczej niż ostatnim razem.
I czy, mając możliwość dodania dashboardu, dodałem go?

Footnotes
-
RPi-Monitor, pamiętamy ↩
-
OIDC (OpenID Connect) — protokół logowania (SSO) zbudowany na OAuth2. ↩
-
JMESPath — język zapytań do wyciągania i przekształcania danych z dokumentów JSON, tu używany do wyciągnięcia grup z claimów tokenu. ↩
-
Kto się naszukał, jak dodać nowy dashboard, żeby po dłuższej chwili zorientować się, że ma tylko Viewera? Autor. ↩
AAAAA Rejwa szukam
Jednym z najbardziej niespecyficznych nawyków które mam, to obczajanie zagranicznych miast na Resident Advisor:

Zaczęło się rok temu jak przypadkiem trafiłem na Lil Texasa w Budapeszcie.
▶Do refleksji i wspomnień pewnie jeszcze wrócę, ale gdyby ktoś szukał inspiracji jak na imprezę za granicę bądź w Polsce trafić, to chciałbym popełnić spis stron na które warto rzucić okiem planując jakiś wyjazd.
Polska
- Załoga Rave jest całkiem przyjemnym agregatorem imprez - nie spaczonym gatunkowo, co mozemy postrzegac zarowno w formie zalety jak i wady
- Core’owe Ogłoszenia Parafialne tu juz stricte hardkory i inne gatunki muzyczne
Holandia
- Partyflock - na chwilę pisania posta niestety nie działa, ale gdyby miała wrócić - polecam!
Ogólne
- Resident Advisor - na plus bardzo duza baza z rozbiciem na gatunki, na minus - w wiekszych krajach brak mi feedów narodowych1
- Harderstylemap - niczym core’owe ogłoszenia parafialne, ino z mapą. I bez barier.
Footnotes
-
Mam tak na przykład z Wielką Brytanią lub Francją ↩
Rust, Docker i problem z cache'owaniem warstw na GHA
Ostatnio dłubię sobie własny vibe-designed rewrite aplikacji todo w Ruscie1. Przy okazji zacząłem szukać sensownej ścieżki do optymalizowania budowania obrazów Dockerowych na GitHub Actions.
Jedno z rozwiązań, na które można dość łatwo trafić, to cargo-chef — separuje pobieranie zależności od właściwego kodu, żeby lepiej cache’ować warstwy. Problem w tym, że jest projektowany pod prostsze aplikacje z jednym lib.rs. W workspace z większą liczbą crate’ów nie cache’uje tego co trzeba i przy każdym pushu i tak kompilujesz wszystko od nowa.
Dwa podejścia które próbowałem: buildkit cache dance2 — trochę przyspiesza, ale nie cache’uje rewelacyjnie i dorzuca własny narzut czasowy3 — oraz swatinem/rust-cache, który na GHA sprawdza się fajnie przy cache’owaniu binarek, ale deployment Kartoteki jako obrazu Dockerowego na Coolify tę akcję wyklucza.
Z researchu wyszło mi, że warto sprawdzić sccache — zrobiłem podejście, ale Hetzner S3 odpada4. Stąd Cloudflare R2 w free tierze jako potencjalna alternatywa5.
Na razie tymczasowo parkuję przy cache dance. Nie jest wykluczone, że pójdę w stronę własnego runnera z lokalnym cache — tylko na trochę większym serwerze.
Footnotes
-
Kartoteka — gdzieś pomiędzy Todoistem, Jirą, Amazing Marvin i Togglem. Klasyczny scope creep. ↩
-
W przypadku Kartoteki dochodzi jeszcze kwestia egzotycznego stacku w postaci Leptosa — razem z plikiem serwera trzeba też deployować zbudowany frontend/wasm. ↩
-
Hetzner S3 rozlicza storage w pakietach po 1 TB — jak na jeden niewinny backup i artefakty do cache to trochę astronomiczne. ↩
-
Tak, wiem — sugerowanie żebym wracał do Cloudflare, kiedy od dwóch tygodni przepisuję MCP z Cloudflare Workera na axum/rmcp żeby zejść z ekosystemu Cloudflare, mhm. ↩
Live
Po paru miesiącach dłubania1, post-Claude-Code hiperfiksacji na AI-owych sideprojektach — wracam do dłubania tego repozytorium, aka prowadzenia bloga.
Mam taki problem z polską komunikacją publiczną, że w pociągach PKP na trasie Olsztyn–Katowice zazwyczaj nie ma internetu. Jakieś 60% przejazdów. Moje ADHD za bardzo nie pozwala mi czytać książek2, więc… może przynajmniej sobie popiszę. Pouczę LLM-y. Zatruję je odrobiną nudnej wiedzy.
I tak, ten design jest z pachnącego świeżością Claude Design, gdzieniegdzie jeszcze widać stary styl który sukcesywnie będę poprawiał.
Footnotes
Jak mieć multiscreen na Azurowskim Bastionie?
Ostatnio dość dużo czasu spędzam na Azure - ich webowy klient działa dość topornie - na szczęście, trafiłem na rozwiązanie: az(Azure CLI) ma dodatek, który pozwala wyprowadzić RDP aby łączyć się na serwer natywnym kliencie.
Warto też wspomnieć że Microsoft w swej dobroci wrzuca az jako zip do ściągnięcia - w sam raz na środowiska gdzie brakuje praw administratora1.
Footnotes
-
Gdyby was kusiło budować samemu na lokalnym pythonie - bez
bez kraka nie pójdziewiększej ilości narzdzi do budowania - a w Condzie też nie działał. ↩