Harden deployment and fix PEN-01
- Fix Bearer token extraction to validate prefix (PEN-01) - Add TestExtractBearerFromRequest covering PEN-01 edge cases - Fix flaky TestRenewToken timing (2s → 4s lifetime) - Move default config/install paths to /srv/mcias - Add RUNBOOK.md for operational procedures - Update AUDIT.md with penetration test round 4 Security: extractBearerFromRequest now uses case-insensitive prefix validation instead of fixed-offset slicing, rejecting non-Bearer Authorization schemes that were previously accepted. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
51
dist/install.sh
vendored
51
dist/install.sh
vendored
@@ -6,7 +6,7 @@
|
||||
# This script must be run as root. It:
|
||||
# 1. Creates the mcias system user and group (idempotent).
|
||||
# 2. Copies binaries to /usr/local/bin/.
|
||||
# 3. Creates /etc/mcias/ and /var/lib/mcias/ with correct permissions.
|
||||
# 3. Creates /srv/mcias/ with correct permissions.
|
||||
# 4. Installs the systemd service unit.
|
||||
# 5. Prints post-install instructions.
|
||||
#
|
||||
@@ -25,8 +25,7 @@ set -eu
|
||||
# Configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
BIN_DIR="/usr/local/bin"
|
||||
CONF_DIR="/etc/mcias"
|
||||
DATA_DIR="/var/lib/mcias"
|
||||
SRV_DIR="/srv/mcias"
|
||||
MAN_DIR="/usr/share/man/man1"
|
||||
SYSTEMD_DIR="/etc/systemd/system"
|
||||
SERVICE_USER="mcias"
|
||||
@@ -114,23 +113,19 @@ for bin in mciassrv mciasctl mciasdb mciasgrpcctl; do
|
||||
install -m 0755 -o root -g root "$src" "$BIN_DIR/$bin"
|
||||
done
|
||||
|
||||
# Step 3: Create configuration directory.
|
||||
info "Creating $CONF_DIR"
|
||||
install -d -m 0750 -o root -g "$SERVICE_GROUP" "$CONF_DIR"
|
||||
# Step 3: Create service directory.
|
||||
info "Creating $SRV_DIR"
|
||||
install -d -m 0750 -o "$SERVICE_USER" -g "$SERVICE_GROUP" "$SRV_DIR"
|
||||
|
||||
# Install example config files; never overwrite existing configs.
|
||||
for f in mcias.conf.example mcias.env.example; do
|
||||
src="$SCRIPT_DIR/$f"
|
||||
dst="$CONF_DIR/$f"
|
||||
dst="$SRV_DIR/$f"
|
||||
if [ -f "$src" ]; then
|
||||
install -m 0640 -o root -g "$SERVICE_GROUP" "$src" "$dst" 2>/dev/null || true
|
||||
install -m 0640 -o "$SERVICE_USER" -g "$SERVICE_GROUP" "$src" "$dst" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Step 4: Create data directory.
|
||||
info "Creating $DATA_DIR"
|
||||
install -d -m 0750 -o "$SERVICE_USER" -g "$SERVICE_GROUP" "$DATA_DIR"
|
||||
|
||||
# Step 5: Install systemd service unit.
|
||||
if [ -d "$SYSTEMD_DIR" ]; then
|
||||
info "Installing systemd service unit to $SYSTEMD_DIR"
|
||||
@@ -175,26 +170,26 @@ Next steps:
|
||||
|
||||
# Self-signed (development / personal use):
|
||||
openssl req -x509 -newkey ed25519 -days 3650 \\
|
||||
-keyout /etc/mcias/server.key \\
|
||||
-out /etc/mcias/server.crt \\
|
||||
-keyout /srv/mcias/server.key \\
|
||||
-out /srv/mcias/server.crt \\
|
||||
-subj "/CN=auth.example.com" \\
|
||||
-nodes
|
||||
chmod 0640 /etc/mcias/server.key
|
||||
chown root:mcias /etc/mcias/server.key
|
||||
chmod 0640 /srv/mcias/server.key
|
||||
chown mcias:mcias /srv/mcias/server.key /srv/mcias/server.crt
|
||||
|
||||
2. Copy and edit the configuration file:
|
||||
|
||||
cp /etc/mcias/mcias.conf.example /etc/mcias/mcias.conf
|
||||
\$EDITOR /etc/mcias/mcias.conf
|
||||
chmod 0640 /etc/mcias/mcias.conf
|
||||
chown root:mcias /etc/mcias/mcias.conf
|
||||
cp /srv/mcias/mcias.conf.example /srv/mcias/mcias.toml
|
||||
\$EDITOR /srv/mcias/mcias.toml
|
||||
chmod 0640 /srv/mcias/mcias.toml
|
||||
chown mcias:mcias /srv/mcias/mcias.toml
|
||||
|
||||
3. Set the master key passphrase:
|
||||
|
||||
cp /etc/mcias/mcias.env.example /etc/mcias/env
|
||||
\$EDITOR /etc/mcias/env # replace the placeholder passphrase
|
||||
chmod 0640 /etc/mcias/env
|
||||
chown root:mcias /etc/mcias/env
|
||||
cp /srv/mcias/mcias.env.example /srv/mcias/env
|
||||
\$EDITOR /srv/mcias/env # replace the placeholder passphrase
|
||||
chmod 0640 /srv/mcias/env
|
||||
chown mcias:mcias /srv/mcias/env
|
||||
|
||||
IMPORTANT: Back up the passphrase to a secure offline location.
|
||||
Losing it means losing access to all encrypted data in the database.
|
||||
@@ -208,16 +203,16 @@ Next steps:
|
||||
5. Create the first admin account using mciasdb (while the server is
|
||||
running, or before first start):
|
||||
|
||||
MCIAS_MASTER_PASSPHRASE=\$(grep MCIAS_MASTER_PASSPHRASE /etc/mcias/env | cut -d= -f2) \\
|
||||
mciasdb --config /etc/mcias/mcias.conf account create \\
|
||||
MCIAS_MASTER_PASSPHRASE=\$(grep MCIAS_MASTER_PASSPHRASE /srv/mcias/env | cut -d= -f2) \\
|
||||
mciasdb --config /srv/mcias/mcias.toml account create \\
|
||||
--username admin --type human
|
||||
|
||||
Then set a password:
|
||||
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /etc/mcias/mcias.conf \\
|
||||
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /srv/mcias/mcias.toml \\
|
||||
account set-password --id <UUID>
|
||||
|
||||
And grant the admin role:
|
||||
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /etc/mcias/mcias.conf \\
|
||||
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /srv/mcias/mcias.toml \\
|
||||
role grant --id <UUID> --role admin
|
||||
|
||||
For full documentation, see: man mciassrv
|
||||
|
||||
2
dist/mcias-dev.conf.example
vendored
2
dist/mcias-dev.conf.example
vendored
@@ -15,7 +15,7 @@
|
||||
# export MCIAS_MASTER_PASSPHRASE=devpassphrase
|
||||
#
|
||||
# Start the server:
|
||||
# mciassrv -config /path/to/mcias-dev.conf
|
||||
# mciassrv -config /path/to/mcias-dev.toml
|
||||
|
||||
[server]
|
||||
listen_addr = "127.0.0.1:8443"
|
||||
|
||||
18
dist/mcias.conf.docker.example
vendored
18
dist/mcias.conf.docker.example
vendored
@@ -1,38 +1,36 @@
|
||||
# mcias.conf.docker.example — Config template for container deployment
|
||||
#
|
||||
# Mount this file into the container at /etc/mcias/mcias.conf:
|
||||
# Mount this file into the container at /srv/mcias/mcias.toml:
|
||||
#
|
||||
# docker run -d \
|
||||
# --name mcias \
|
||||
# -v /path/to/mcias.conf:/etc/mcias/mcias.conf:ro \
|
||||
# -v /path/to/certs:/etc/mcias:ro \
|
||||
# -v mcias-data:/data \
|
||||
# -v /srv/mcias:/srv/mcias \
|
||||
# -e MCIAS_MASTER_PASSPHRASE=your-passphrase \
|
||||
# -p 8443:8443 \
|
||||
# -p 9443:9443 \
|
||||
# mcias:latest
|
||||
#
|
||||
# The container runs as uid 10001 (mcias). Ensure that:
|
||||
# - /data volume is writable by uid 10001
|
||||
# - /srv/mcias is writable by uid 10001
|
||||
# - TLS cert and key are readable by uid 10001
|
||||
#
|
||||
# TLS: The server performs TLS termination inside the container; there is no
|
||||
# plain-text mode. Mount your certificate and key under /etc/mcias/.
|
||||
# plain-text mode. Place your certificate and key under /srv/mcias/.
|
||||
# For Let's Encrypt certificates, mount the live/ directory read-only.
|
||||
|
||||
[server]
|
||||
listen_addr = "0.0.0.0:8443"
|
||||
grpc_addr = "0.0.0.0:9443"
|
||||
tls_cert = "/etc/mcias/server.crt"
|
||||
tls_key = "/etc/mcias/server.key"
|
||||
tls_cert = "/srv/mcias/server.crt"
|
||||
tls_key = "/srv/mcias/server.key"
|
||||
# If a reverse proxy (nginx, Caddy, Traefik) sits in front of this container,
|
||||
# set trusted_proxy to its container IP so real client IPs are used for rate
|
||||
# limiting and audit logging. Leave commented out for direct exposure.
|
||||
# trusted_proxy = "172.17.0.1"
|
||||
|
||||
[database]
|
||||
# VOLUME /data is declared in the Dockerfile; map a named volume here.
|
||||
path = "/data/mcias.db"
|
||||
# All data lives under /srv/mcias for a single-volume deployment.
|
||||
path = "/srv/mcias/mcias.db"
|
||||
|
||||
[tokens]
|
||||
issuer = "https://auth.example.com"
|
||||
|
||||
18
dist/mcias.conf.example
vendored
18
dist/mcias.conf.example
vendored
@@ -1,12 +1,12 @@
|
||||
# mcias.conf — Reference configuration for mciassrv
|
||||
#
|
||||
# Copy this file to /etc/mcias/mcias.conf and adjust the values for your
|
||||
# Copy this file to /srv/mcias/mcias.toml and adjust the values for your
|
||||
# deployment. All fields marked REQUIRED must be set before the server will
|
||||
# start. Fields marked OPTIONAL can be omitted to use defaults.
|
||||
#
|
||||
# File permissions: mode 0640, owner root:mcias.
|
||||
# chmod 0640 /etc/mcias/mcias.conf
|
||||
# chown root:mcias /etc/mcias/mcias.conf
|
||||
# chmod 0640 /srv/mcias/mcias.toml
|
||||
# chown root:mcias /srv/mcias/mcias.toml
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [server] — Network listener configuration
|
||||
@@ -26,11 +26,11 @@ listen_addr = "0.0.0.0:8443"
|
||||
# REQUIRED. Path to the TLS certificate (PEM format).
|
||||
# Self-signed certificates work fine for personal deployments; for
|
||||
# public-facing deployments consider a certificate from Let's Encrypt.
|
||||
tls_cert = "/etc/mcias/server.crt"
|
||||
tls_cert = "/srv/mcias/server.crt"
|
||||
|
||||
# REQUIRED. Path to the TLS private key (PEM format).
|
||||
# Permissions: mode 0640, owner root:mcias.
|
||||
tls_key = "/etc/mcias/server.key"
|
||||
tls_key = "/srv/mcias/server.key"
|
||||
|
||||
# OPTIONAL. IP address of a trusted reverse proxy (e.g. nginx, Caddy, HAProxy).
|
||||
# When set, the rate limiter and audit log extract the real client IP from the
|
||||
@@ -55,7 +55,7 @@ tls_key = "/etc/mcias/server.key"
|
||||
# REQUIRED. Path to the SQLite database file.
|
||||
# The directory must be writable by the mcias user. WAL mode is enabled
|
||||
# automatically; expect three files: mcias.db, mcias.db-wal, mcias.db-shm.
|
||||
path = "/var/lib/mcias/mcias.db"
|
||||
path = "/srv/mcias/mcias.db"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [tokens] — JWT issuance policy
|
||||
@@ -113,13 +113,13 @@ threads = 4
|
||||
# database on first run and reused on subsequent runs so the same passphrase
|
||||
# always produces the same master key.
|
||||
#
|
||||
# Set the passphrase in /etc/mcias/env (loaded by the systemd EnvironmentFile
|
||||
# Set the passphrase in /srv/mcias/env (loaded by the systemd EnvironmentFile
|
||||
# directive). See dist/mcias.env.example for the template.
|
||||
passphrase_env = "MCIAS_MASTER_PASSPHRASE"
|
||||
|
||||
# Option B: Key file mode. The file must contain exactly 32 bytes of raw key
|
||||
# material (AES-256). Generate with: openssl rand -out /etc/mcias/master.key 32
|
||||
# material (AES-256). Generate with: openssl rand -out /srv/mcias/master.key 32
|
||||
# Permissions: mode 0640, owner root:mcias.
|
||||
#
|
||||
# Uncomment and comment out passphrase_env to switch modes.
|
||||
# keyfile = "/etc/mcias/master.key"
|
||||
# keyfile = "/srv/mcias/master.key"
|
||||
|
||||
6
dist/mcias.env.example
vendored
6
dist/mcias.env.example
vendored
@@ -1,10 +1,10 @@
|
||||
# /etc/mcias/env — Environment file for mciassrv (systemd EnvironmentFile).
|
||||
# /srv/mcias/env — Environment file for mciassrv (systemd EnvironmentFile).
|
||||
#
|
||||
# This file is loaded by the mcias.service unit before the server starts.
|
||||
# It must be readable only by root and the mcias service account:
|
||||
#
|
||||
# chmod 0640 /etc/mcias/env
|
||||
# chown root:mcias /etc/mcias/env
|
||||
# chmod 0640 /srv/mcias/env
|
||||
# chown root:mcias /srv/mcias/env
|
||||
#
|
||||
# SECURITY: This file contains the master key passphrase. Treat it with
|
||||
# the same care as a private key. Do not commit it to version control.
|
||||
|
||||
10
dist/mcias.service
vendored
10
dist/mcias.service
vendored
@@ -11,11 +11,11 @@ User=mcias
|
||||
Group=mcias
|
||||
|
||||
# Configuration and secrets.
|
||||
# /etc/mcias/env must contain MCIAS_MASTER_PASSPHRASE=<passphrase>
|
||||
# /srv/mcias/env must contain MCIAS_MASTER_PASSPHRASE=<passphrase>
|
||||
# See dist/mcias.env.example for the template.
|
||||
EnvironmentFile=/etc/mcias/env
|
||||
EnvironmentFile=/srv/mcias/env
|
||||
|
||||
ExecStart=/usr/local/bin/mciassrv -config /etc/mcias/mcias.conf
|
||||
ExecStart=/usr/local/bin/mciassrv -config /srv/mcias/mcias.toml
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
@@ -30,11 +30,11 @@ LimitNOFILE=65536
|
||||
CapabilityBoundingSet=
|
||||
|
||||
# Filesystem restrictions.
|
||||
# mciassrv reads /etc/mcias (config, TLS cert/key) and writes /var/lib/mcias (DB).
|
||||
# mciassrv reads and writes /srv/mcias (config, TLS cert/key, database).
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
ReadWritePaths=/var/lib/mcias
|
||||
ReadWritePaths=/srv/mcias
|
||||
|
||||
# Additional hardening.
|
||||
NoNewPrivileges=true
|
||||
|
||||
Reference in New Issue
Block a user