Skip to content

YourBOX Security Controls

This page consolidates the security posture of YourBOX across source, build, container, runtime and network controls. The application is one workload in the homelab portfolio and inherits the workspace baseline. The page calls out the controls specific to YourBOX and the evidence trail each control produces.

The threats considered in the application design:

  • Untrusted user input through registration, login, upload, comment and vote endpoints.
  • Untrusted legacy code in YourBOX/ during the strangler migration. The fallback bundle executes 2020 PHP without modern security guarantees.
  • Compromised CI runner that could exfiltrate the build pipeline.
  • Public network reachability of the VPS smoke test, which is the only externally addressable production-like surface.
  • Supply chain attacks on container images, PHP packages and CI dependencies.

The threat model excludes a fully compromised homelab platform: a successful breach of OpenBao or the Argo CD control plane is treated as a platform incident with its own response path.

Control Tool Stage
Static analysis PHPStan level 8 Lint
Style PHP-CS-Fixer (PSR-12) Lint
Dependency vulnerability composer audit Lint
Secret detection gitleaks Pre commit + CI
YAML lint yamllint Lint
Ansible lint ansible-lint production Lint
Dockerfile lint hadolint Lint
License scan license-checker SAST
Architecture rules PHPStan custom rules Lint

The PHPStan custom rules forbid Symfony imports under Domain/ and Application/ per ADR-0006. They also forbid require and require_once inside app/src/.

Control Tool Evidence artifact
Multi stage minimal image Dockerfile image digest
Vulnerability scan Trivy (HIGH+CRITICAL) trivy.json
SBOM generation syft (CycloneDX) sbom.cdx.json
Image signature cosign cosign attestation
SBOM attestation cosign attest cosign attestation
Digest pinning Plumber control plumber-report.json
Source registry allowlist Plumber control plumber-report.json
Forbidden tag rejection Plumber control plumber-report.json

The CI/CD page describes the exact jobs. Each evidence artifact is kept as a GitLab artifact and attached to the deployment record.

Control Where it lives
Non root container UID Dockerfile USER 10001:10001
Read only root filesystem Helm values containerSecurityContext
Drop all Linux capabilities Helm values capabilities.drop: ["ALL"]
Seccomp profile RuntimeDefault
No host network or host PID Helm values defaults
Resource requests and limits Helm values
Liveness and readiness probes Helm values
Pod Disruption Budget Helm template poddisruptionbudget.yaml
Kyverno admission policies homelab-platform Kyverno cluster policies
Sigstore image signature verify homelab-platform policy-controller

The Kyverno cluster policies reject images without digests, with a root user, without dropped capabilities, or from a non allowed registry.

The NetworkPolicy template described on the Kubernetes GitOps page applies the default deny model. Egress is whitelisted to PostgreSQL, Meilisearch, MinIO, Redis cache, Authentik (OIDC token exchange), the SMTP provider and the messaging bus selected in ADR-0011. Ingress is whitelisted to Traefik and Prometheus.

On the VPS, Traefik enforces a security headers middleware (HSTS, frame deny, content type sniff, referrer policy, permissions policy) and a token bucket rate limit. The VPS firewall keeps the inbound ports to 80 and 443 and a Wireguard or SSH management port restricted to the admin source addresses.

ADR-0004 sets the OIDC plus form firewall layout. The specific defenses applied on top of the Symfony Security firewall are:

  • CSRF tokens on every state changing endpoint.
  • Symfony Forms enforce token rotation.
  • Session cookies are Secure, HttpOnly, SameSite=Lax.
  • Session id rotates on login and on privilege elevation.
  • The remember me cookie is the Symfony built in cookie signed with APP_SECRET. The broken 2020 cookie format is gone.
  • Rate limit of 5 failed form logins per minute per IP through the Symfony rate limiter.
  • Authentik enforces the equivalent rate limit in production.
  • Account recovery is delegated to Authentik in production. The 2020 reset flow is deleted.

ADR-0008 sets the secret management model. The defenses specific to YourBOX:

  • The container image carries no secret values. Trivy and image inspection cannot leak credentials.
  • The OpenBao policy kv/data/yourbox/<env>/* is read only and scoped per environment.
  • The GitLab runner authenticates to OpenBao through JWT and only sees the staging path. The production runner is gated by manual approval.
  • The age private key on the VPS lives on a tmpfs and is materialized from Ansible Vault at boot.
  • The cosign signing key lives in OpenBao under kv/yourbox/cosign-key and is fetched at job time only.

A ZAP baseline scan runs against the VPS smoke test after the deploy job. The scan targets the public homepage, the login page, the registration page and the catalog. Findings above MEDIUM block the promotion to Azure or to the homelab cluster.

A Nikto scan runs on a weekly schedule against the same surface and surfaces server header and default file findings.

The fallback bundle serves the 2020 PHP code unchanged. The defenses applied during the transition:

  • The Symfony front controller validates the URL path against the legacy root directory with realpath. A path traversal returns 404 instead of leaking files outside the bundle.
  • The static asset MIME guard refuses to stream a .env, .env.php, composer.lock, composer.json or any non allowlisted file extension.
  • The Authentik OIDC firewall protects every legacy URL that lives behind /app/*. The legacy public pages (/, /index.php) inherit the same CSP and security headers from Traefik.
  • The WAF (ModSecurity through Traefik plugin or Coraza for Kubernetes) is enabled on the public surface and runs the OWASP CRS. The 2020 SQL injection surface is mitigated by the WAF rules until the migration covers the route.

The artifacts produced by each control are:

Evidence Source Retention
trivy.json CI scan stage 90 days as GitLab artifact
sbom.cdx.json CI sign stage 365 days as GitLab artifact
cosign signature CI sign stage with the image, immutable
plumber-report.json CI lint stage 30 days as GitLab artifact
gitleaks.json CI lint stage 30 days as GitLab artifact
zap-baseline.json CI DAST stage 90 days as GitLab artifact
Audit log records Application 90 days hot in Postgres, 365 cold in OpenSearch

Every deployment Merge Request references the matching pipeline run, so the evidence trail is reachable from the deployment record.

YourBOX does not target a specific compliance framework. The controls above map cleanly to the categories of NIST SSDF, OWASP ASVS L2 and CIS Kubernetes Benchmark Level 1 for the relevant container and admission controls. The mapping is documented as a checklist on the workspace level Security Model page.