Files
ermnvldmr.com/services/docs/content/en/apex/concepts/security-model.md
T
deytenit b3638f4d63 fix: cyrillic fonts, dev certs, page head, and ru-text typography (#67)
🤖 PR generated for branch `fix/cyrillic-fonts-dev-certs-and-page-head`.

### Changes Summary
- **Fonts**: Add Cyrillic glyph subsets for Lato, EB Garamond, and Fira
Code.
- **Dev**: Support remote Root CA and encrypted dev CA key in
`.env.dev`.
- **UI & Kits**: Add size variant to `Breadcrumbs` component and enlarge
`PageHead` breadcrumbs with tuned collapse scroll threshold.
- **ESLint**: Add `no-hanging-particles` i18n & markdown typography rule
with auto-fixer.
- **Content & i18n**: Apply `ru-text` editorial and typography polish
(em dashes, number ranges, «ё» restoration, non-breaking spaces) across
`services/www` and `services/docs`.
2026-10-25 15:21:09 +03:00

4.8 KiB

title, description, weight
title description weight
Security model Privilege isolation, firewall management, intrusion detection, and secret handling. 18

apex hardens a node in independent layers: filesystem privilege isolation, a managed host firewall, intrusion detection, container-level containment, and a strict secrets boundary. Each layer is applied by an action and is therefore reproducible and re-runnable.

Privilege isolation

Every project runs as its own locked noroot-<project> system user; shared storage is group-writable with the sticky bit so projects can exchange files without being able to delete each other's. The full mechanism — users, groups, and the ownership matrix — is described in Concept: Tiered storage.

Host firewall

apex configure/ufw applies the node's firewall from the configs/ufw/ pillar in three parts:

  • Host rules (configs/ufw/host/host.rules) — plain ufw commands, one per line, applied in order.
  • Kernel-level rule blocks (configs/ufw/host/before.rules, after.rules) — injected into /etc/ufw/before.rules and /etc/ufw/after.rules as managed marker blocks. Injection is self-healing: every previous managed block — including blocks left by predecessor tooling — is removed before the fresh block is inserted after ufw's # End required lines anchor, and a timestamped .bak of the target is kept beside it.
  • Container rules (configs/ufw/docker/*.rules) — applied through ufw-docker, which translates them into rules that survive Docker's own iptables manipulation. configure/base installs the helper to ~/.local/bin/ufw-docker.

Missing configuration is an error, not a silent skip: an absent docker/ or host/ directory exits 66 when its counterpart exists, and a missing /etc/ufw target file aborts the run. The action finishes with a reminder that ufw must be restarted to take effect — and that the SSH port must be allowed first.

Intrusion detection

apex configure/crowdsec installs CrowdSec through its official installer when cscli is absent, renders everything under configs/crowdsec/ into /etc/crowdsec/ (acquisition sources, parsers, bouncer configuration), and installs the crowdsecurity/linux and crowdsecurity/traefik collections. When the node's configs include a firewall-bouncer configuration, the matching bouncer package is installed as well, closing the loop from detection to blocking.

Container containment

The core composition encodes container-level hardening:

  • The edge proxy never touches the Docker socket: it discovers backends through a filtered socket proxy that exposes read-only container/service state on an isolated network.
  • enclave and socket are internal: true networks — no egress, no host port exposure.
  • Core services set no-new-privileges and run under the project's noroot identity wherever the workload allows; capabilities are granted per service, not globally.

Observability

Observability is an outbound push, not an exposed route. The optional alloy core service (Grafana Alloy, one agent per node) collects host metrics (a node_exporter-equivalent), container metrics (cadvisor), the systemd journal, and docker container logs, and pushes them to a central Prometheus and Loki that live on a designated node — the metrics via prometheus.remote_write to APEX_PROM_PUSH_URL, the logs via loki.write to APEX_LOKI_PUSH_URL. Both targets are authenticated with HTTP basic auth using APEX_OBS_BASIC_AUTH_USER / APEX_OBS_BASIC_AUTH_PASS. Because the push is outbound, Alloy attaches to the direct network (which has egress) rather than the internal enclave; there is no node-local log store and no /loki route to protect.

Secrets boundary

  • Secrets live only in per-project .env files, which are symlinks into tier-1 storage — outside the repository working tree and covered by .gitignore (**/.env).
  • Each node repository documents its expected keys in SECRETS.md; the file documents names, never values.
  • Committed configuration (apex.env) is restricted to non-secret scalars.
  • The shared composition marks critical secrets with ?error, so a missing value fails fast at compose-config time.
  • Capture-up commits are safe by construction: the ignored .env links and tier data never enter the git index.

See also: