Skip to content

Security hardening: DB credential separation & Kubernetes SecurityContext#10

Merged
vladiant merged 6 commits intomainfrom
add_security_fixes
Mar 31, 2026
Merged

Security hardening: DB credential separation & Kubernetes SecurityContext#10
vladiant merged 6 commits intomainfrom
add_security_fixes

Conversation

@vladiant
Copy link
Copy Markdown
Collaborator

Summary

Eliminates hardcoded database credentials from source code, configuration defaults, and Kubernetes ConfigMaps. Adds pod-level security hardening across all Kubernetes deployments.

This is a breaking changeIMG_DATABASE_URL is removed and replaced by individual IMG_DB_* variables. Existing deployments must set IMG_DB_USER and IMG_DB_PASSWORD environment variables before upgrading.

Breaking Changes

  • IMG_DATABASE_URL environment variable is removed
  • IMG_DB_USER and IMG_DB_PASSWORD are now required — no defaults are provided to prevent accidental credential leakage
  • Docker Compose requires POSTGRES_PASSWORD to be set in the host environment (or a .env file)

What Changed

Credential separation (config.py)

  • Replaced single database_url field (with hardcoded postgres:postgres default) with individual typed fields: db_user, db_password, db_host, db_port, db_name
  • database_url is now a @computed_field property that assembles the connection string with proper password URL-encoding via urllib.parse.quote_plus

Docker Compose (docker-compose.yml)

  • App and DB credentials are read from host environment variables (${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD})
  • Added .env.example as a template for local development

Kubernetes Secrets (secret.yaml, 01a-secret.yaml)

  • Created Secret resources for IMG_DB_USER / IMG_DB_PASSWORD
  • Removed IMG_DATABASE_URL (with embedded credentials) from both ConfigMaps
  • Deployments mount both ConfigMap and Secret via envFrom
  • Minikube PostgreSQL pod reads credentials from the Secret via secretKeyRef

SecurityContext (k8s + minikube deployments)

  • image-service: runAsNonRoot: true, runAsUser: 999, runAsGroup: 999, allowPrivilegeEscalation: false, readOnlyRootFilesystem: true
  • postgres: runAsNonRoot: true, runAsUser: 70, fsGroup: 70, allowPrivilegeEscalation: false, readOnlyRootFilesystem: true
  • Added emptyDir volumes for tmp (both pods) and /var/run/postgresql (postgres) to support read-only root filesystem

Dockerfile fix

  • Added COPY pyproject.toml and pip install --no-deps . so importlib.metadata.version() works at runtime (pre-existing bug)

Documentation updates

  • README.md, PROJECT_DESCRIPTION.md, AGENTS.md, REQUIREMENTS.md, README.md updated to reflect new config variables, Secret resources, and SecurityContext

Files Changed

Area Files
Config config.py, dependencies.py
Docker Dockerfile, docker-compose.yml, .env.example
K8s (prod) configmap.yaml, deployment.yaml, secret.yaml
K8s (minikube) 01-configmap.yaml, 01a-secret.yaml, 02-postgres.yaml, 04-deployment.yaml, setup.sh
Tests test_api.py, test_correlation.py
Docs README.md, PROJECT_DESCRIPTION.md, AGENTS.md, REQUIREMENTS.md, README.md, CHANGELOG.md
Version pyproject.toml (1.3.02.0.0)

Testing

  • ruff check — all passed
  • mypy src/ — clean
  • pytest — 101 tests passed
  • Minikube end-to-end — full demo.sh (11 steps) passed with SecurityContext active and credentials sourced from Kubernetes Secret

Version Bump

MAJOR (1.3.02.0.0) — removal of IMG_DATABASE_URL and required IMG_DB_USER/IMG_DB_PASSWORD with no defaults is a breaking configuration change.

@vladiant vladiant merged commit 22e62cf into main Mar 31, 2026
4 checks passed
@vladiant vladiant deleted the add_security_fixes branch March 31, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant