Merge pull request #107 from trails-cool/grafana-postgres-datasource

Add PostgreSQL datasource to Grafana with read-only user
This commit is contained in:
Ullrich Schäfer 2026-03-27 20:08:28 +01:00 committed by GitHub
commit 2a5615dfdf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 64 additions and 7 deletions

View file

@ -68,6 +68,13 @@ jobs:
GHCR_TOKEN=$(grep DEPLOY_GHCR_TOKEN .env | cut -d= -f2-)
echo "$GHCR_TOKEN" | docker login ghcr.io -u stigi --password-stdin 2>/dev/null || true
# Setup Grafana read-only DB user (idempotent)
docker compose exec -T postgres psql -U trails -d trails -f /docker-entrypoint-initdb.d/init-grafana-user.sql 2>/dev/null || true
GRAFANA_DB_PW=$(grep GRAFANA_DB_PASSWORD .env | cut -d= -f2-)
if [ -n "$GRAFANA_DB_PW" ]; then
docker compose exec -T postgres psql -U trails -d trails -c "ALTER ROLE grafana_reader PASSWORD '$GRAFANA_DB_PW'" 2>/dev/null || true
fi
# Full restart: gh workflow run cd-infra.yml -f restart_all=true
if [ "${{ github.event.inputs.restart_all }}" = "true" ]; then
docker compose --env-file .env up -d --remove-orphans

View file

@ -78,6 +78,7 @@ services:
POSTGRES_DB: trails
volumes:
- pgdata:/var/lib/postgresql/data
- ./postgres/init-grafana-user.sql:/docker-entrypoint-initdb.d/init-grafana-user.sql:ro
command:
- "postgres"
- "-c"
@ -154,6 +155,7 @@ services:
GF_AUTH_GITHUB_ALLOWED_ORGANIZATIONS: trails-cool
GF_AUTH_GITHUB_SCOPES: user:email,read:org
GF_AUTH_DISABLE_LOGIN_FORM: "true"
GRAFANA_DB_PASSWORD: ${GRAFANA_DB_PASSWORD:-}
volumes:
- ./grafana/provisioning:/etc/grafana/provisioning:ro
- ./grafana/dashboards:/var/lib/grafana/dashboards:ro

View file

@ -15,3 +15,18 @@ datasources:
access: proxy
url: http://loki:3100
editable: false
- name: PostgreSQL
uid: postgres
type: postgres
access: proxy
url: postgres:5432
user: grafana_reader
editable: false
jsonData:
database: trails
sslmode: disable
maxOpenConns: 2
maxIdleConns: 1
secureJsonData:
password: $__env{GRAFANA_DB_PASSWORD}

View file

@ -0,0 +1,32 @@
-- Read-only user for Grafana dashboards
-- Password is set via: ALTER ROLE grafana_reader PASSWORD '<from SOPS>'
-- Run by cd-infra deploy script after container start
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'grafana_reader') THEN
CREATE ROLE grafana_reader WITH LOGIN;
END IF;
END
$$;
GRANT CONNECT ON DATABASE trails TO grafana_reader;
GRANT USAGE ON SCHEMA public TO grafana_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO grafana_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO grafana_reader;
-- Also grant on planner/journal schemas if they exist
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.schemata WHERE schema_name = 'planner') THEN
GRANT USAGE ON SCHEMA planner TO grafana_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA planner TO grafana_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA planner GRANT SELECT ON TABLES TO grafana_reader;
END IF;
IF EXISTS (SELECT 1 FROM information_schema.schemata WHERE schema_name = 'journal') THEN
GRANT USAGE ON SCHEMA journal TO grafana_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA journal TO grafana_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA journal GRANT SELECT ON TABLES TO grafana_reader;
END IF;
END
$$;

View file

@ -1,10 +1,11 @@
#ENC[AES256_GCM,data:IbWmlFr0kUJNYnRkD9Rt6tPAgtE+8TrECPY3MstykO8EPIZOvkg0T1hjGsDLca5NA8cdWqWWEmSF4o7ewvk=,iv:UD1YxHEH9PxnSrkVI/Nm9WVazGk9Kh+B8uzfNqjmf3I=,tag:+mWHdGvo+OeQFa4Ak/S3Pg==,type:comment]
#ENC[AES256_GCM,data:BDOEQHz+QsQcQCzrD8XWcxREuNWELctcjsZahTmwEAYolct7EaW4G9bGI1K8BL8V5OejHvqtxgd34LHBAzTrTL66ATW/pWGY2lF/G69J4Q==,iv:4RyNDeZUZOgibkI7+aIyCJDxd/7jZMMaBIepQCbbHFA=,tag:v/mPe5ILLVS2bLUKFpOoJg==,type:comment]
GF_AUTH_GITHUB_CLIENT_ID=ENC[AES256_GCM,data:4a1+g2U6a+XlfwSLLoJFWruvOLg=,iv:h1yDpE21XPxqOGBsE+E1Xunr0eAC2ALLP9x11XMPd6Q=,tag:zKWMUrCi1b2Ir8g1BcsAcA==,type:str]
GF_AUTH_GITHUB_CLIENT_SECRET=ENC[AES256_GCM,data:LGbZHhQeLcS01UJXtZefsGUi0P8lscZRrho0HGq+hKRuoy5RO1HssA==,iv:NATDvm3fKe4zjJ36PWb/iJLVA2lJsognRLg0TZY5yw4=,tag:JYatVnyvrc0dYue2aTh55Q==,type:str]
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4UiszMUJMYzFlWE5Qc3Zk\nUDF2V1BIYmIwbjVydHI5OTJoRVJXdFhDZDEwCmlEQTFKRUZwYVlQbVRJMEpHL2Vj\nd21pS3BwZHc3QklCMVl4ZHFzZUJYRWMKLS0tIEtQeFQvNGxRUGhqNnBzQ0ZvaXRY\nMFZjQlhobXBKT08yc0dLVGNwd0pHbmcKEAS/YRu2NhGCZLX+nkVjo7PEu7ZV4iCW\nyO9GIsaIQcN6FWmp5IkjdeM6jkHxSk+qHCL5bKx78EgPMgzKobjgzQ==\n-----END AGE ENCRYPTED FILE-----\n
#ENC[AES256_GCM,data:0mZOnEJyXdCzF0HYzuVFkOmGOpfsTzfHbrwmCwU7NyeaDKFpoTvH1fQW/XCcflGaWPRrKRyCEYOa4sdPnag=,iv:iiEYiIqvmvOFQTEDPFeu7fkluWf0z/v+tvDmY7L0cFE=,tag:Ds/EHF6XSGfnv8ZCa5OU6w==,type:comment]
#ENC[AES256_GCM,data:+au0EOdh5q7IY7qcP4Jko5dJz4AdDCF8ilBqKUCHb9hB8xlM2FHiyLrcf3Q0eYbAyg28xaTm+wewKDivvuoOv4grGohqezJ4Ypffm1Yg6g==,iv:zXrneKQUu+bL5oRFmz5nVdUcUolH0HDFuOSK460rmpc=,tag:WDybda6Q9WBEp+SuzfKQqw==,type:comment]
GF_AUTH_GITHUB_CLIENT_ID=ENC[AES256_GCM,data:mik8yBpOAkJXHQ8vEeMZV2Y+KY4=,iv:DNZLDWxnichM9E4fitJSQdf0lxNsneYJxleIs6CPJgs=,tag:aXCt7Ff5PggBWaXvRYv9tw==,type:str]
GF_AUTH_GITHUB_CLIENT_SECRET=ENC[AES256_GCM,data:jcGhMeBwOLZotvfExZWqyMtql1C7AC0hlus7Vl/RLvEjshPmNtO9yg==,iv:20HLImbrFMkWLQ+chInq0Ig9j2Q4NSLXFN+72jXxM/M=,tag:INKt4Icg9QI1PTD+KEfCHg==,type:str]
GRAFANA_DB_PASSWORD=ENC[AES256_GCM,data:o1G5rDo1G4RiOGBbd7KDcqEIKG7UuwTlVx7BI7eVHWI=,iv:Fd1wA+4uB7Ypix8n4aTGKJo6V+uiCkr4yZ3wkGZ5rQA=,tag:c0qpH/v7lgmU5yXZo7n+RA==,type:str]
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBbnY1VndkeE9hYnByK3RU\nRDFUYU5DcWhCRXYrdStoallzU0ZnWkJJeEY4CnBUYUlIK2ZhcUV2aWhqSDFSYnhD\nb1hkOGdkSGFyajRXNVg5a1FZcE9mQzQKLS0tIEVKZThiV1RMdkhhaWlvM05vY1g4\nYTNYUkFaYUJzbVUvMi83eHg1NXhXcGMKShBIdPKho4WmWiykqFXdmQ/NRAKoUpUw\ntUQKcGlrhHRhpgaFTyeKj+UVD1y52cXWZX9xhFdJ7TFxEO1opNc9LQ==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age1vukt8py0s2mm47fx6qh6vykckfkdqslf9w68ekytfzvc8xp7e3rqn6p64n
sops_lastmodified=2026-03-27T15:40:55Z
sops_mac=ENC[AES256_GCM,data:pkYMdGTyjc6/ig/hdBD4GGeyiOkJBp/z9+w3vlT/bfHeje4FBZxjdmgykfCmNFJqov1MoysEsP0z8VZpdcSa+cjcJXVIhXcSpl4Uo/NXZuYRIuPkQztSGna+tStrpus4Zxk2SLe8IF5AFgPtuCwZvS7R7JE4KKbkKG/kfcTMrR8=,iv:SXzctdK5QEV6RZuSSxDor7MYPgEJGvSih4l3G2+lwYI=,tag:umAgJ94DM7DKVPPniCdRvw==,type:str]
sops_lastmodified=2026-03-27T19:07:05Z
sops_mac=ENC[AES256_GCM,data:hKi5AD4+FFL5/bDHnBfNvWipsUA0GOLVF0/l5o2I6bh5aD4l/ZJbL1hOdxq/2MO7eJPjej5AFqREEDbMKHwY7s9nvKJhNAjtg8ejRK/y1x8r8Skm790cjcT04hIbpIgc2yaM131eyOuz39q9HODAmCoLqrVBpkStEQYhId5gQcY=,iv:fFSYntpfurMfD5vzRgaVONMZe3NyxuJPw0w2lqqCyQs=,tag:8gPfB9sJpwUaG8cc43kesQ==,type:str]
sops_unencrypted_suffix=_unencrypted
sops_version=3.9.4