Skip to content

Security

Security Standards

Aligned to ISO/IEC 27001:2022. This document defines the operational controls in use for the Level147 internal operations dashboard. A full ISMS gap assessment should be conducted before any formal certification pursuit.


Information Security Policy

Level147 is committed to protecting the confidentiality, integrity, and availability of information assets belonging to the business and its clients. All personnel (including contractors and AI-assisted tooling) operate under these controls.

Owner: Principal Consultant
Review: Annual minimum, or after any security incident


Asset Classification

ClassExamplesControls
ConfidentialClient credentials, API keys, OIDC client secrets, financial recordsEncrypted at rest and in transit; access logged; never in version control
InternalArchitecture docs, infrastructure configs, internal comms, dashboard dataAccess limited to authorised personnel via Cloudflare Access + Authentik SSO
PublicOpen-source code, public documentationNo restrictions

Access Control (ISO 27001 A.5.15–A.5.18)

Principle of Least Privilege

Every user, service account, and agent is granted only the minimum permissions required for its function. Admin access is never used for routine tasks.

Authentication

The dashboard uses a two-layer authentication model:

  1. Cloudflare Access (network perimeter) — all requests pass through a zero-trust Cloudflare Access policy before reaching the application. Unauthenticated requests are blocked at the network edge.
  2. NextAuth v5 + Authentik OIDC (application layer) — provides user identity (session.user) and role claims. Enforced at two points:
    • src/middleware.ts gates all /api/* routes (except /api/auth/* and /api/health) as the framework-level choke point so new routes are protected by default.
    • Each route handler also calls requireSession() (src/lib/require-session.ts) for defence-in-depth.

No other identity providers are used. There is no email/password auth, no Google/GitHub login, and no guest access.

  • All production systems require MFA (enforced via Authentik)
  • SSH key authentication only — password auth disabled on all servers
  • SSH keys: Ed25519 minimum; RSA keys ≥ 4096-bit if required for compatibility
  • SSH keys rotated on personnel change or suspected compromise

Service Accounts

  • Each service has its own credential — no shared passwords between services
  • Authentik OIDC client secret: server-side only (NextAuth config), never in frontend bundles
  • Woodpecker secrets injected at pipeline runtime; never logged

Access Review

Quarterly review of:

  • Authentik users and group memberships
  • Gitea organisation members
  • Woodpecker admin access
  • Portainer access
  • Cloudflare account members

Secrets Management (ISO 27001 A.5.17)

Rules

  1. Never commit secrets. No API keys, passwords, tokens, or private keys in version control — ever.
  2. .env files are always gitignored. .env.example with placeholder values is committed.
  3. CI/CD secrets live in Woodpecker repo or organisation secrets, scoped to the minimum required pipelines.
  4. Secrets referenced in pipelines use the from_secret: directive — never inline plaintext.
  5. Long-lived tokens (Gitea PATs, OIDC client secrets) are documented in the secrets inventory below.

Secrets Inventory

Maintain a private off-system record (e.g. Bitwarden) of:

SecretScopeRotation trigger
Gitea PAT (GITEA_TOKEN)Registry push/pullAnnual or on personnel change
Authentik OIDC client secretNextAuth provider configAnnual or on breach
Woodpecker agent shared secretAgent ↔ server authOn agent re-enrolment or breach
Cloudflare API tokensDNS, tunnelAnnual
SSH private keysServer accessOn device loss or personnel change

Network Security (ISO 27001 A.8.20–A.8.22)

Perimeter

  • All access to the dashboard is routed through a cloudflared tunnel → Cloudflare Access (zero-trust). There is no direct public ingress to the origin server.
  • The dashboard is not public-facing; it is an internal tool accessible only to authorised users.
  • Internal services (Woodpecker gRPC port 9000, Portainer, Gitea) are not publicly exposed.
  • Internal access via Tailscale overlay VPN only.

Firewall Rules

  • Default deny inbound on all hosts
  • Explicit allow: 22 (SSH, key-auth only), Tailscale interface; cloudflared outbound tunnel (no inbound 80/443 required)
  • Docker-published ports on internal hosts: bound to 127.0.0.1 or Tailscale interface, not 0.0.0.0

TLS

  • Minimum TLS 1.2; TLS 1.3 preferred
  • Cloudflare Full (Strict) mode — origin certificates must be valid
  • Internal service-to-service traffic on private networks may use HTTP if on Tailscale

Container Security (ISO 27001 A.8.9)

  • Container images pinned to explicit semver tags — never :latest in production
  • Images pulled from trusted registries only (gitea.level147.net, official Docker Hub images)
  • Resource limits set on all containers: CPU quota and memory limits in compose
  • Containers run as non-root where the image supports it
  • Docker socket mounts (/var/run/docker.sock) granted only to trusted infra agents (Woodpecker deploy agent, Portainer) — the dashboard app mounts the socket without :ro because it performs write operations (container restart/stop)

Vulnerability Management (ISO 27001 A.8.8)

  • Dependency updates reviewed monthly via npm audit / equivalent
  • OS patches applied to all servers within 30 days of release; critical patches within 72 hours
  • Docker base images rebuilt on significant upstream releases
  • Known CVEs in dependencies escalated: High/Critical → address within sprint; Medium → next planned cycle

Logging and Monitoring (ISO 27001 A.8.15–A.8.16)

  • Container logs: Target 14-day retention. Note: Docker log rotation must be explicitly configured (max-size/max-file in the log driver) to enforce this — confirm it is set in production before relying on this figure.
  • NextAuth session events logged server-side (sign-in, sign-out, token refresh failures)
  • Woodpecker pipeline logs: Target 90-day retention (Woodpecker default; verify current server configuration).
  • Cloudflare Analytics reviewed monthly for anomalies
  • Failed auth attempts and unusual API call volumes trigger manual investigation

Incident Response (ISO 27001 A.5.24–A.5.28)

Severity Classification

SeverityDefinitionResponse time
P1 — CriticalActive breach, data exfiltration, system unavailableImmediate
P2 — HighSuspected compromise, significant data exposure riskWithin 4 hours
P3 — MediumVulnerability identified, no active exploitWithin 48 hours
P4 — LowMinor issue, no immediate riskNext business day

Response Steps

  1. Contain — isolate affected system (revoke credentials, block IPs, take service offline if needed)
  2. Assess — determine scope: what was accessed, what data was exposed, time window
  3. Notify — if personal data is involved, assess Australian notifiable data breach obligations (see /governance/data-privacy)
  4. Remediate — patch, rotate credentials, rebuild from clean state if warranted
  5. Post-incident review — document root cause, update controls, review this standard

Credential Compromise Response

  1. Immediately revoke/rotate all affected credentials
  2. Audit logs for usage of compromised credential
  3. Redeploy affected services with new credentials
  4. Review how credential was exposed; update secrets management controls

Business Continuity (ISO 27001 A.5.29–A.5.30)

Backup Schedule

DataBackup frequencyRetentionLocation
IPAM data (data/ipam.json)Target: DailyTarget: 7 daysOff-site
Gitea repositoriesTarget: WeeklyTarget: 30 daysOff-site
Server configurationOn change (git)IndefiniteGitea
Docker volumes (stateful)Target: DailyTarget: 7 daysOff-site

Recovery Objectives

ObjectiveTarget
Recovery Time Objective (RTO)4 hours for production services
Recovery Point Objective (RPO)24 hours maximum data loss

Third-Party and Supply Chain (ISO 27001 A.5.19–A.5.22)

Key third-party dependencies and their security posture:

ProviderRoleNotes
CloudflareCDN, DNS, WAF, zero-trust Access, tunnelSOC 2 Type II
TailscaleVPN overlaySOC 2 Type II; WireGuard-based
Authentik (self-hosted)Identity provider (OIDC)Self-managed; security is owner’s responsibility
Gitea (self-hosted)Source control, container registrySelf-managed; security is owner’s responsibility
Woodpecker CI (self-hosted)CI/CDSelf-managed; no external data sharing

v0.1.0 · d0d7a20 · 2026-06-26