Add platform infrastructure configuration

This commit is contained in:
donghyeon-ka
2026-08-28 17:35:41 +09:00
parent fa76531e5b
commit 16c337bcc9
302 changed files with 83259 additions and 1 deletions
+19
View File
@@ -0,0 +1,19 @@
# pgAdmin
PostgreSQL 관리 화면을 platform-admin 네임스페이스에 배포합니다.
- 주소: db-admin.learn.hyeonworks.com
- 실제 접근 범위: 호스트 Nginx에서 LAN·Tailscale만 허용
- 차트: dpage/pgadmin4-helm:9.16.0
- 이미지: dpage/pgadmin4:9.16의 amd64 digest 고정
- 저장소: 2Gi SSD Local PV, Retain
- 배포 전략: 단일 replica, Recreate
Keycloak 그룹 /platform-db-admins가 있는 사용자만 OIDC 로그인이
가능합니다. 내부 관리자는 비상용으로 유지합니다. 공유 서버 정의에는
비밀번호가 없으며, DB 비밀번호 저장도 비활성화합니다.
필요한 Secret은 다음 두 개뿐이며 Git에 저장하지 않습니다.
- pgadmin-keycloak-oidc: client-id, client-secret
- pgadmin-bootstrap: password
+42
View File
@@ -0,0 +1,42 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: pgadmin-config
namespace: platform-admin
labels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/instance: pgadmin
app.kubernetes.io/part-of: platform
data:
config_local.py: |
import os
AUTHENTICATION_SOURCES = ['oauth2', 'internal']
OAUTH2_AUTO_CREATE_USER = True
OAUTH2_CONFIG = [{
'OAUTH2_NAME': 'keycloak',
'OAUTH2_DISPLAY_NAME': 'Hyeonworks ID',
'OAUTH2_CLIENT_ID': os.environ['PGADMIN_OIDC_CLIENT_ID'],
'OAUTH2_CLIENT_SECRET': os.environ['PGADMIN_OIDC_CLIENT_SECRET'],
'OAUTH2_SERVER_METADATA_URL': (
'https://id.learn.hyeonworks.com/realms/hyeonworks/'
'.well-known/openid-configuration'
),
'OAUTH2_SCOPE': 'openid email profile',
'OAUTH2_USERNAME_CLAIM': 'preferred_username',
'OAUTH2_ADDITIONAL_CLAIMS': {
'groups': ['/platform-db-admins'],
},
}]
ALLOW_SAVE_PASSWORD = False
ENHANCED_COOKIE_PROTECTION = False
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
ALLOWED_HOSTS = ['db-admin.learn.hyeonworks.com']
UPGRADE_CHECK_ENABLED = False
SHOW_GRAVATAR_IMAGE = False
LLM_ENABLED = False
ENABLE_PSQL = False
ENABLE_SERVER_PASS_EXEC_CMD = False
@@ -0,0 +1,5 @@
- op: remove
path: /metadata/annotations/kubernetes.io~1ingress.class
- op: add
path: /spec/ingressClassName
value: traefik
+38
View File
@@ -0,0 +1,38 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
helmGlobals:
chartHome: .helm/charts
helmCharts:
- name: pgadmin4-helm
repo: oci://docker.io/dpage
version: 9.16.0
releaseName: pgadmin
namespace: platform-admin
valuesFile: values/home.yaml
includeCRDs: false
skipTests: true
resources:
- config.yaml
- network-policies
patches:
- patch: |-
- op: add
path: /metadata/namespace
value: platform-admin
target:
labelSelector: app.kubernetes.io/instance=pgadmin
- path: ingress-class-patch.yaml
target:
group: networking.k8s.io
version: v1
kind: Ingress
name: pgadmin
images:
- name: docker.io/dpage/pgadmin4
newName: docker.io/dpage/pgadmin4
digest: sha256:66a300a7ecdcc1f325af0c430315329bca46cd4a7067227d6899802238167c6e
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- pgadmin.yaml
- platform-postgres.yaml
@@ -0,0 +1,150 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pgadmin-default-deny
namespace: platform-admin
labels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/part-of: platform
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/instance: pgadmin
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pgadmin-allow-traefik
namespace: platform-admin
labels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/part-of: platform
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/instance: pgadmin
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
app.kubernetes.io/name: traefik
ports:
- protocol: TCP
port: 5050
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pgadmin-allow-dns
namespace: platform-admin
labels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/part-of: platform
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/instance: pgadmin
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pgadmin-allow-keycloak
namespace: platform-admin
labels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/part-of: platform
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/instance: pgadmin
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 192.168.0.107/32
ports:
- protocol: TCP
port: 443
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pgadmin-allow-platform-postgres
namespace: platform-admin
labels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/part-of: platform
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/instance: pgadmin
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: platform-data
podSelector:
matchLabels:
cnpg.io/cluster: platform-postgres
ports:
- protocol: TCP
port: 5432
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pgadmin-allow-blackbox-health
namespace: platform-admin
labels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/part-of: platform
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/instance: pgadmin
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: observability
podSelector:
matchLabels:
app.kubernetes.io/name: prometheus-blackbox-exporter
app.kubernetes.io/instance: blackbox-exporter
ports:
- protocol: TCP
port: 5050
@@ -0,0 +1,27 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: platform-postgres-allow-pgadmin
namespace: platform-data
labels:
app.kubernetes.io/name: platform-postgres
app.kubernetes.io/component: database-network-policy
app.kubernetes.io/part-of: platform
spec:
podSelector:
matchLabels:
cnpg.io/cluster: platform-postgres
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: platform-admin
podSelector:
matchLabels:
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/instance: pgadmin
ports:
- protocol: TCP
port: 5432
+175
View File
@@ -0,0 +1,175 @@
fullname: pgadmin
image:
registry: docker.io
repository: dpage/pgadmin4
tag: "9.16"
pullPolicy: IfNotPresent
commonLabels:
app: pgadmin4
app.kubernetes.io/name: pgadmin4
app.kubernetes.io/instance: pgadmin
app.kubernetes.io/component: database-admin
app.kubernetes.io/part-of: platform
replicas: 1
strategy:
type: Recreate
containerPort: 5050
disablePostfix: true
enableServiceLinks: false
auth:
email: platform-admin@hyeonworks.com
existingSecret: pgadmin-bootstrap
passwordKey: password
extraEnvVars:
- name: PGADMIN_OIDC_CLIENT_ID
valueFrom:
secretKeyRef:
name: pgadmin-keycloak-oidc
key: client-id
- name: PGADMIN_OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: pgadmin-keycloak-oidc
key: client-secret
- name: PGADMIN_REPLACE_SERVERS_ON_STARTUP
value: "True"
config_local:
enabled: false
extraVolumes:
- name: config-local
configMap:
name: pgadmin-config
defaultMode: 292
items:
- key: config_local.py
path: config_local.py
extraVolumeMounts:
- name: config-local
mountPath: /pgadmin4/config_local.py
subPath: config_local.py
readOnly: true
serverDefinitions:
enabled: true
data:
"1":
Name: Hyeonworks Gitea
Group: Platform
Host: platform-postgres-rw.platform-data.svc.cluster.local
Port: 5432
MaintenanceDB: gitea
Username: gitea
Shared: true
SharedUsername: gitea
ConnectionParameters:
sslmode: require
connect_timeout: 10
"2":
Name: Hyeonworks Keycloak
Group: Platform
Host: platform-postgres-rw.platform-data.svc.cluster.local
Port: 5432
MaintenanceDB: keycloak
Username: keycloak
Shared: true
SharedUsername: keycloak
ConnectionParameters:
sslmode: require
connect_timeout: 10
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
persistence:
enabled: true
size: 2Gi
storageClass: ssd-local-pgadmin-retain
accessModes:
- ReadWriteOnce
service:
type: ClusterIP
port: 80
serviceAccount:
create: true
automountServiceAccountToken: false
ingress:
enabled: true
hostname: db-admin.learn.hyeonworks.com
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/router.entrypoints: web
tlsSecret: ""
startupProbe:
enabled: true
httpGet:
path: /misc/ping
port: http
httpHeaders:
- name: Host
value: db-admin.learn.hyeonworks.com
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 30
readinessProbe:
enabled: true
httpGet:
path: /misc/ping
port: http
httpHeaders:
- name: Host
value: db-admin.learn.hyeonworks.com
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 6
livenessProbe:
enabled: true
httpGet:
path: /misc/ping
port: http
httpHeaders:
- name: Host
value: db-admin.learn.hyeonworks.com
periodSeconds: 20
timeoutSeconds: 3
failureThreshold: 6
podSecurityContext:
enabled: true
fsGroupChangePolicy: OnRootMismatch
fsGroup: 1001
containerSecurityContext:
enabled: true
runAsUser: 1001
runAsGroup: 1001
runAsNonRoot: true
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
appArmorProfile:
type: RuntimeDefault