feat(grafana): Gitea OAuth SSO via bootstrap_sso.py
This commit is contained in:
14
compose.yml
14
compose.yml
@@ -746,6 +746,9 @@ services:
|
||||
networks:
|
||||
- gateway
|
||||
- observability
|
||||
env_file:
|
||||
- path: .state/gitea/grafana.env
|
||||
required: false
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_USER=admin
|
||||
- GF_SECURITY_ADMIN_PASSWORD=${GF_ADMIN_PASSWORD:-admin}
|
||||
@@ -753,6 +756,17 @@ services:
|
||||
- GF_AUTH_ANONYMOUS_ENABLED=true
|
||||
- GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
|
||||
- GF_SERVER_ROOT_URL=https://grafana.${DOMAIN:-fhirworx.io}
|
||||
- GF_AUTH_GENERIC_OAUTH_ENABLED=true
|
||||
- GF_AUTH_GENERIC_OAUTH_NAME=Gitea
|
||||
- GF_AUTH_GENERIC_OAUTH_SCOPES=openid profile email
|
||||
- GF_AUTH_GENERIC_OAUTH_AUTH_URL=https://git.${DOMAIN:-fhirworx.io}/login/oauth/authorize
|
||||
- GF_AUTH_GENERIC_OAUTH_TOKEN_URL=http://git:3000/login/oauth/access_token
|
||||
- GF_AUTH_GENERIC_OAUTH_API_URL=http://git:3000/api/v1/user
|
||||
- GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP=true
|
||||
- GF_AUTH_GENERIC_OAUTH_AUTO_LOGIN=false
|
||||
- GF_AUTH_OAUTH_ALLOW_INSECURE_EMAIL_LOOKUP=true
|
||||
- GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH=is_admin && 'GrafanaAdmin'
|
||||
- GF_AUTH_GENERIC_OAUTH_ALLOW_ASSIGN_GRAFANA_ADMIN=true
|
||||
volumes:
|
||||
- ./infra/grafana/provisioning:/etc/grafana/provisioning:ro
|
||||
- ./infra/grafana/dashboards:/var/lib/grafana/dashboards:ro
|
||||
|
||||
@@ -23,6 +23,7 @@ ROOT = Path(__file__).resolve().parents[2]
|
||||
STATE = ROOT / ".state" / "gitea"
|
||||
OAUTH_STATE = STATE / "oauth.json"
|
||||
OAUTH2_PROXY_ENV = STATE / "oauth2-proxy.env"
|
||||
GRAFANA_ENV = STATE / "grafana.env"
|
||||
|
||||
DOMAIN = os.environ.get("DOMAIN", "fhirworx.io")
|
||||
GITEA_API = os.environ.get("GITEA_API", "http://git:3000/api/v1")
|
||||
@@ -238,6 +239,16 @@ def _write_oauth2_proxy_env(client_id: str, client_secret: str) -> bool:
|
||||
)
|
||||
|
||||
|
||||
def _write_grafana_env(client_id: str, client_secret: str) -> bool:
|
||||
return _write_env_file(
|
||||
GRAFANA_ENV,
|
||||
(
|
||||
f"GF_AUTH_GENERIC_OAUTH_CLIENT_ID={client_id}\n"
|
||||
f"GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET={client_secret}\n"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tunnel DNS (Cloudflare API via wrangler OAuth token)
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -382,6 +393,15 @@ def main() -> None:
|
||||
else:
|
||||
print(" ok: oauth2-proxy env unchanged")
|
||||
|
||||
grafana_creds = _ensure_oauth_app(
|
||||
client,
|
||||
token,
|
||||
name="grafana",
|
||||
redirect_uri=f"https://grafana.{DOMAIN}/login/generic_oauth",
|
||||
)
|
||||
if grafana_creds:
|
||||
_write_grafana_env(*grafana_creds)
|
||||
|
||||
print("==> Clearing Cloudflare Access apps")
|
||||
_clear_access_apps(client)
|
||||
|
||||
|
||||
@@ -227,3 +227,27 @@ class TestPromtailLabels:
|
||||
assert "--accesslog" in flat or any(
|
||||
"TRAEFIK_ACCESSLOG" in str(e) for e in traefik.get("environment", [])
|
||||
)
|
||||
|
||||
|
||||
class TestGrafanaOAuth:
|
||||
def test_grafana_loads_state_env_file(self):
|
||||
env_files = _services()["grafana"].get("env_file", [])
|
||||
# accepts either a list of dicts or a list of strings
|
||||
joined = yaml.safe_dump(env_files)
|
||||
assert ".state/gitea/grafana.env" in joined
|
||||
|
||||
def test_grafana_oauth_env_vars(self):
|
||||
envs = _services()["grafana"].get("environment", [])
|
||||
text = "\n".join(envs)
|
||||
assert "GF_AUTH_GENERIC_OAUTH_ENABLED=true" in text
|
||||
assert "GF_AUTH_GENERIC_OAUTH_NAME=Gitea" in text
|
||||
assert (
|
||||
"GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH=is_admin && 'GrafanaAdmin'"
|
||||
in text
|
||||
)
|
||||
|
||||
def test_bootstrap_sso_provisions_grafana(self):
|
||||
src = (ROOT / "dev/scripts/bootstrap_sso.py").read_text()
|
||||
assert "GRAFANA_ENV" in src
|
||||
assert 'name="grafana"' in src
|
||||
assert "/login/generic_oauth" in src
|
||||
|
||||
Reference in New Issue
Block a user