feat(apps): Add pgweb

This commit is contained in:
2026-10-10 12:23:13 +05:30
parent 1a104cb0c5
commit 390c2e332d
20 changed files with 347 additions and 0 deletions
+6
View File
@@ -14,6 +14,11 @@ data:
identifiers: identifiers:
path: mounted/cm-blueprint-garage-ui/garage-ui.yaml path: mounted/cm-blueprint-garage-ui/garage-ui.yaml
required: true required: true
- model: authentik_blueprints.metaapplyblueprint
attrs:
identifiers:
path: mounted/cm-blueprint-pgweb/pgweb.yaml
required: true
- model: authentik_blueprints.metaapplyblueprint - model: authentik_blueprints.metaapplyblueprint
attrs: attrs:
identifiers: identifiers:
@@ -26,4 +31,5 @@ data:
attrs: attrs:
providers: providers:
- !Find [authentik_providers_proxy.proxyprovider, [name, garage-ui]] - !Find [authentik_providers_proxy.proxyprovider, [name, garage-ui]]
- !Find [authentik_providers_proxy.proxyprovider, [name, pgweb]]
- !Find [authentik_providers_proxy.proxyprovider, [name, qbittorrent]] - !Find [authentik_providers_proxy.proxyprovider, [name, qbittorrent]]
+33
View File
@@ -0,0 +1,33 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: blueprint-pgweb
namespace: authentik
data:
pgweb.yaml: |
version: 1
metadata:
name: pgweb
entries:
- model: authentik_providers_proxy.proxyprovider
id: pgweb-provider
identifiers:
name: pgweb
attrs:
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
mode: forward_single
external_host: https://pgweb.whyredfire.dev
- model: authentik_core.application
id: pgweb
identifiers:
slug: pgweb
attrs:
name: pgweb
provider: !KeyOf pgweb-provider
- model: authentik_policies.policybinding
identifiers:
order: 0
target: !KeyOf pgweb
attrs:
group: !Find [authentik_core.group, [name, admins]]
+1
View File
@@ -7,6 +7,7 @@ resources:
- blueprint-google-login.yaml - blueprint-google-login.yaml
- blueprint-grafana.yaml - blueprint-grafana.yaml
- blueprint-outpost.yaml - blueprint-outpost.yaml
- blueprint-pgweb.yaml
- blueprint-qbittorrent.yaml - blueprint-qbittorrent.yaml
- blueprint-wireguard-admin.yaml - blueprint-wireguard-admin.yaml
- httproute.yaml - httproute.yaml
+3
View File
@@ -8,6 +8,9 @@ spec:
- group: gateway.networking.k8s.io - group: gateway.networking.k8s.io
kind: HTTPRoute kind: HTTPRoute
namespace: garage namespace: garage
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: pgweb
- group: gateway.networking.k8s.io - group: gateway.networking.k8s.io
kind: HTTPRoute kind: HTTPRoute
namespace: qbit namespace: qbit
+11
View File
@@ -24,6 +24,13 @@ spec:
name: legislative name: legislative
passwordSecret: passwordSecret:
name: legislative-db name: legislative-db
- ensure: present
inRoles:
- pg_read_all_data
login: true
name: pgweb
passwordSecret:
name: pgweb-db
- ensure: present - ensure: present
login: true login: true
name: redoost name: redoost
@@ -31,8 +38,12 @@ spec:
name: redoost-db name: redoost-db
postgresql: postgresql:
# Each app role may only connect to the database of the same name. # Each app role may only connect to the database of the same name.
# pgweb is read-only and may browse every database except authentik's,
# which holds credentials and session tokens.
pg_hba: pg_hba:
- host sameuser all all scram-sha-256 - host sameuser all all scram-sha-256
- host authentik pgweb all reject
- host all pgweb all scram-sha-256
- host all all all reject - host all all all reject
resources: resources:
limits: limits:
+1
View File
@@ -8,5 +8,6 @@ resources:
- grafana-database.yaml - grafana-database.yaml
- legislative-db-sealedsecret.yaml - legislative-db-sealedsecret.yaml
- legislative-database.yaml - legislative-database.yaml
- pgweb-db-sealedsecret.yaml
- redoost-db-sealedsecret.yaml - redoost-db-sealedsecret.yaml
- redoost-database.yaml - redoost-database.yaml
@@ -0,0 +1,17 @@
---
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: pgweb-db
namespace: postgres
spec:
encryptedData:
password: AgBOEIc6OuRugdd6OZGVRCFItD5XUaHxrRSfh4VDc5JION8/p+5KBlXd8wtHzNyGXCxHIFnenkGxWEZKWiaMAQS9v/At6tMJFRQYYwRHzFPx1u16H3lzmnE5+GgUhmoIayiRkhLA4Qs9aub/+mSzIW3sPo5RykLzhGZbnVbF0y7jQ39X01Sb6UFVJBGBXFjHuBkM9B5Iep01EgCM4a7SpWVgn0+kPzopfABbjJKAQM1ah0DMaXTFMCkKm2N0/e5KyGw1FNWC+Aor8mVkm6irCz9O2rFBJ3b/jY44cEoJ7zVIAfGN8y1HxTGOrVuBb7LkfrYTxIVVAT2CrxUaEdutAlGXgWyXmJ+wMgiQ4qds5rD5+T5ePdErCAiY74Jb8LWuyuZXG0uI/lGL0QTECcNiXJ/dvX8PNuq+L+Y6IZTK+WgxBvJXIgsfs2a3QyT7vIaB/k8QTQ7uF2KBBV1ol/cXhW45Dewu8yWz9Sjhb2roK1yNHvCiZaS79sUo9VPjEhGKZ3TcyWvi+eqWMFsLLxmXCz4wefU1XO83aLg8oPqZkfbo1IhcUC6oonv1dLX/jTy8RKudCPbkrytrlffKoVZ4aLhi+3ehkPY1d2J1oa1Nmmu2Vr5wDEXxtvQwtBJavB80ep5/esv89EYqjYYJglzUm4UBMv18v50E0dpGymem6mx/5yG5Ym+RI1hvE37x2Ed5GO9rX29BAjqob3H69Jd44OVlAuF6/Gz4fwVstPexi9gEbp2m2Mpiz+WOtrww2ofktENCKi211Qr+woc9h4Tq4DGI
username: AgAAdKsgTKEFmQTw0VxAdiocOEaT9WbTurBlaQVpdvneGMry2A6iAmKvrszFT1RaG+Iy0nRtxu1XM8bkpn5QDML0H6AB3O25QDrEOkhBd0feBBKjgaFCAwrcp64Wu3o8q+yEXTZcDJ5Ah3cXwvXDpc3PPMyvkDnIcGTqDKXEplJQY533NrE0iw3hPsBFztavb4QiH6Txlnq+JpPu/F2G++nRCcNh1kuaMG1kQ61IImj4xSdOoYDO7RLbIxA/cRcQYju4UkSliU2uMHTw4pDT7mDqP1GjSN/tvoezk9FjNHIgaBUg2WFk6cBzdLIFY/zafwchkUAeM0AX+kFpeAIhzRmI0uknyH8fuZWHkYxU07PuanE3kNJkhSbCQWQ0TtKTXCtccxgUYHaucskVk3ZC66cVJj+NCRQbV1lvUGaNHEuoF/lGueosdM5saCIChuidbJbJsmDIztf6OBBJM0nyOoQjV6cMwirXxO2Ap+vxb/tI5eLsoUkVORe/nxoiGF7P+529mv2S1KE7PWwd0A82s6A30RoovTmTyxFOTT2p9TmxYIzzzymiz52hRiGI4YBSDirajfGleOmxILDxWwLdiXpBhUNwgjaZ39taumgsZ+wyxxIaD6OxdHKGGI/u+fRyJMdvIITPn3CMbl16+MTwQkrvx/Qw7+52Pm5mp/gW5AQQqJHBSKdSGGosNYMV1Tx9UHHZ12GDnw==
template:
metadata:
labels:
cnpg.io/reload: "true"
name: pgweb-db
namespace: postgres
type: kubernetes.io/basic-auth
+13
View File
@@ -0,0 +1,13 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: pgweb-bookmark-grafana
namespace: pgweb
data:
grafana.toml: |
host = "postgres-rw.postgres.svc.cluster.local"
user = "pgweb"
passwordvar = "DATABASE_PASSWORD"
database = "grafana"
sslmode = "require"
readonly = true
+13
View File
@@ -0,0 +1,13 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: pgweb-bookmark-legislative
namespace: pgweb
data:
legislative.toml: |
host = "postgres-rw.postgres.svc.cluster.local"
user = "pgweb"
passwordvar = "DATABASE_PASSWORD"
database = "legislative"
sslmode = "require"
readonly = true
+13
View File
@@ -0,0 +1,13 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: pgweb-bookmark-redoost
namespace: pgweb
data:
redoost.toml: |
host = "postgres-rw.postgres.svc.cluster.local"
user = "pgweb"
passwordvar = "DATABASE_PASSWORD"
database = "redoost"
sslmode = "require"
readonly = true
+77
View File
@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: pgweb
namespace: pgweb
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: pgweb
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/name: pgweb
spec:
containers:
# Only bookmarked databases can be connected to, picked on the
# connect screen; there is one bookmark per app database.
- args:
- --bookmarks-dir=/bookmarks
- --bookmarks-only
- --no-ssh
- --readonly
- --skip-open
env:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: pgweb
image: docker.io/sosedoff/pgweb:0.17.0
livenessProbe:
httpGet:
path: /
port: http
name: pgweb
ports:
- containerPort: 8081
name: http
readinessProbe:
httpGet:
path: /
port: http
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 10m
memory: 32Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
volumeMounts:
- mountPath: /bookmarks
name: bookmarks
readOnly: true
securityContext:
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
volumes:
- name: bookmarks
projected:
sources:
- configMap:
name: pgweb-bookmark-grafana
- configMap:
name: pgweb-bookmark-legislative
- configMap:
name: pgweb-bookmark-redoost
+37
View File
@@ -0,0 +1,37 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
annotations:
argocd.argoproj.io/sync-wave: "2"
name: pgweb
namespace: pgweb
spec:
hostnames:
- pgweb.whyredfire.dev
parentRefs:
- kind: Gateway
name: traefik-gateway
namespace: traefik
sectionName: websecure
rules:
- backendRefs:
- name: authentik-server
namespace: authentik
port: 80
matches:
- path:
type: PathPrefix
value: /outpost.goauthentik.io
- backendRefs:
- name: pgweb
port: 8081
filters:
- extensionRef:
group: traefik.io
kind: Middleware
name: authentik
type: ExtensionRef
matches:
- path:
type: PathPrefix
value: /
+12
View File
@@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- sealed-secret.yaml
- bookmark-grafana.yaml
- bookmark-legislative.yaml
- bookmark-redoost.yaml
- deployment.yaml
- service.yaml
- networkpolicy.yaml
- middleware.yaml
- httproute.yaml
+17
View File
@@ -0,0 +1,17 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1"
name: authentik
namespace: pgweb
spec:
forwardAuth:
address: http://authentik-server.authentik.svc.cluster.local/outpost.goauthentik.io/auth/traefik
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
trustForwardHeader: true
+45
View File
@@ -0,0 +1,45 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pgweb
namespace: pgweb
spec:
# Only traefik may reach pgweb, so authentik can't be bypassed from inside
# the cluster, and pgweb may only reach postgres.
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
- ports:
- port: 5432
protocol: TCP
to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: postgres
podSelector:
matchLabels:
cnpg.io/cluster: postgres
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik
ports:
- port: 8081
protocol: TCP
podSelector:
matchLabels:
app.kubernetes.io/name: pgweb
policyTypes:
- Ingress
- Egress
+12
View File
@@ -0,0 +1,12 @@
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: pgweb
namespace: pgweb
spec:
encryptedData:
password: AgAZE1EB8YzFvC/qgXm8Mvb9Cy2eRubqST3Hxc42LB6/xGW6ZGj9fVYIw4WcVGTOYKXGfEB4JyP+hidluf20kynufYynHXJZw9zBR15ZHIEDVPnbtW1Z+iMua9Hd8gRwug75IeM9wFHMI6dcXQk164GsJQa77vB1EBts8bN78iSuQwuk4YcIUsMfhbx9NI+SGvV+Ih3B5XrUonhDnEIW2d4D46P/1SYXxqd2HhJPOdyTEWws0pSV191RltpKpEJAb/iJNHP6w1++O2Ld6eRTTgmHBAtJf8NtlRxpeZQ1SixAhpsspaPx1FbDrvq17a8JtY60Zyn4a4JnSY/rgErNadR0C82NkYsokePGZ8KMT1QI+jvz7M1NKQLee4GG9+khBAILmlstuXoZPMACB/HAt+nxJAOA8fAYJYxwCP7AsOEpCR/osK1zX2jlaIB2pvBOx7k3/aqamCWt8QUNOiDfqd5G7SH1PI5bAjOA4YjOVxm89t01MzTE9tIdSlDGMoAfodZDwyjA+zenBKe/ha4lddKUGMtucHlyL2e+CPHhfWSWSRw/aimcRkTZf4fVf+17tF6lm5byp9kRbAOW4ymMtfZLikQqTWJ6Aec1bMCLYD2SagrXMkVgnpuu6Z6W1U0p2f3ZHU8tuOZ4avCz53EjmLw+8gdcD2MXZGlJVtq1kxXGpK9sKRcyD4i05VbtESgZ2XmOiUNrbVAzmu2QhSn/k5NGZpDKg0uWMT3X7igQWSz8Af9S53mPDv6aJ2z/q65D7+BBAMwuE+gO2V7cyK37G2ze
template:
metadata:
name: pgweb
namespace: pgweb
+12
View File
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: pgweb
namespace: pgweb
spec:
ports:
- name: http
port: 8081
targetPort: http
selector:
app.kubernetes.io/name: pgweb
+1
View File
@@ -32,6 +32,7 @@ spec:
- blueprint-google-login - blueprint-google-login
- blueprint-grafana - blueprint-grafana
- blueprint-outpost - blueprint-outpost
- blueprint-pgweb
- blueprint-qbittorrent - blueprint-qbittorrent
- blueprint-wireguard-admin - blueprint-wireguard-admin
server: server:
+1
View File
@@ -7,6 +7,7 @@ resources:
- garage-ui.yaml - garage-ui.yaml
- jellyfin.yaml - jellyfin.yaml
- legislative-summarization.yaml - legislative-summarization.yaml
- pgweb.yaml
- qbit.yaml - qbit.yaml
- redoost.yaml - redoost.yaml
- rustbin.yaml - rustbin.yaml
+22
View File
@@ -0,0 +1,22 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
annotations:
argocd.argoproj.io/sync-wave: "3"
name: pgweb
namespace: argocd
spec:
destination:
namespace: pgweb
server: https://kubernetes.default.svc
project: default
source:
path: apps/pgweb
repoURL: https://gitea.whyredfire.dev/whyredfire/gitops.git
targetRevision: main
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true