Skip to content

Commit e73ff53

Browse files
baijumclaude
andcommitted
docs: add security hardening details to server-contract and archive plans
Document fail2ban, SSH hardening, security headers, and Trivy scanning in the Server Hardening section. Update Caddyfile examples to show the security_headers snippet. Add scan-images.sh to infrastructure scripts table. Mark ci-cd-improvements and monitoring-alerting plans as archived. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 393a069 commit e73ff53

3 files changed

Lines changed: 27 additions & 1 deletion

File tree

docs/server-contract.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ All scripts live in the platform repo under `infrastructure/` and are copied to
104104
| `check-alerts.sh` | Check container health, disk, memory; create GitHub Issues | Cron: every 5 minutes |
105105
| `update-images.sh` | Pull latest Docker images and recreate containers | Cron: weekly Sunday at 03:00 |
106106
| `usage-report.sh` | Generate 6-section resource usage report | Manual (`bash`) |
107+
| `scan-images.sh` | Scan running container images for vulnerabilities (Trivy) | Cron: weekly Sunday at 04:00 |
107108

108109
## Server Hardening
109110

@@ -119,6 +120,14 @@ The bootstrap script applies several security measures automatically. Self-hoste
119120

120121
**Container resource limits** — Every platform service and every app container has explicit CPU and memory limits in its Docker Compose file. This prevents any single container from exhausting server resources. The 7 core services use ~2.66G / 3.25 CPU. The 3 optional metrics services add 448M / 1.00 CPU when enabled.
121122

123+
**Brute-force protection** — fail2ban is installed with an SSH jail (systemd backend, since Debian 12 uses journald). Configuration: maxretry=5, bantime=3600s. IPs that exceed the retry limit are banned for one hour.
124+
125+
**SSH hardening** — A drop-in config at `/etc/ssh/sshd_config.d/99-towlion-hardening.conf` enforces: `PermitRootLogin no`, `PasswordAuthentication no`, `MaxAuthTries 3`, `X11Forwarding no`. Only key-based authentication as the `deploy` user is permitted.
126+
127+
**Security headers** — The platform Caddyfile includes a `(security_headers)` snippet that sets: `Strict-Transport-Security` (HSTS, max-age=31536000, includeSubDomains), `X-Content-Type-Options nosniff`, `X-Frame-Options DENY`, `Referrer-Policy strict-origin-when-cross-origin`, `Permissions-Policy` (camera, microphone, and geolocation denied), and strips the `Server` header. All app and ops Caddy routes import this snippet.
128+
129+
**Image vulnerability scanning** — Trivy is installed via the Aqua Security apt repository. Every deploy runs a non-blocking `trivy image` scan of the newly built app image (HIGH/CRITICAL severity). A weekly cron job (`scan-images.sh`, Sunday 04:00) scans all running container images.
130+
122131
**Mandatory Access Control (AppArmor)** — Debian 12 ships with AppArmor enabled by default. Docker automatically applies the `docker-default` AppArmor profile to all containers, which restricts capabilities like writing to `/proc` and `/sys`, mounting filesystems, and accessing raw sockets. No configuration is needed — this works out of the box.
123132

124133
SELinux is **not** used. While SELinux is the standard MAC system on RHEL/Fedora, it is not well-suited for Debian:
@@ -132,13 +141,24 @@ Since AppArmor is already active and Docker integrates with it automatically, th
132141

133142
## Caddyfile Generation
134143

135-
The platform Caddyfile at `/opt/platform/Caddyfile` contains a single import directive:
144+
The platform Caddyfile at `/opt/platform/Caddyfile` contains a security headers snippet and an import directive:
136145

137146
```
138147
{
139148
email {$ACME_EMAIL:admin@localhost}
140149
}
141150
151+
(security_headers) {
152+
header {
153+
Strict-Transport-Security "max-age=31536000; includeSubDomains"
154+
X-Content-Type-Options "nosniff"
155+
X-Frame-Options "DENY"
156+
Referrer-Policy "strict-origin-when-cross-origin"
157+
Permissions-Policy "camera=(), microphone=(), geolocation=()"
158+
-Server
159+
}
160+
}
161+
142162
import /etc/caddy/apps/*.caddy
143163
```
144164

@@ -148,6 +168,7 @@ The `caddy-apps/` directory is bind-mounted into the Caddy container at `/etc/ca
148168

149169
```
150170
app.example.com {
171+
import security_headers
151172
reverse_proxy <name>-app-1:8000
152173
}
153174
```
@@ -156,6 +177,7 @@ app.example.com {
156177

157178
```
158179
pr-<N>.preview.example.com {
180+
import security_headers
159181
reverse_proxy <name>-pr-<N>-app-1:8000
160182
}
161183
```

plans/ci-cd-improvements.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# CI/CD Improvements — Implementation Record
22

3+
> **Archived** — This plan has been fully implemented and verified. Kept for reference.
4+
35
**Status**: Implemented (2026-03-16)
46

57
## Changes Made

plans/monitoring-alerting.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Plan: Expand Alert Checks in check-alerts.sh
22

3+
> **Archived** — This plan has been fully implemented and verified. Kept for reference.
4+
35
**Status**: Done (2026-03-16)
46

57
## What was done

0 commit comments

Comments
 (0)