Align with engineering standards (steps 1-5)
- Rename dist/ -> deploy/ with subdirs examples/, scripts/, systemd/ per standard repository layout - Update .gitignore: gitignore all of dist/ (build output only) - Makefile: all target is now vet->lint->test->build; add vet, proto-lint, devserver targets; CGO_ENABLED=0 for builds (modernc.org/sqlite is pure-Go, no C toolchain needed); CGO_ENABLED=1 retained for tests (race detector) - Dockerfile: builder -> golang:1.26-alpine, runtime -> alpine:3.21; drop libc6 dep; add /srv/mcias/certs and /srv/mcias/backups to image - deploy/systemd/mcias.service: add RestrictSUIDSGID=true - deploy/systemd/mcias-backup.service: new oneshot backup unit - deploy/systemd/mcias-backup.timer: daily 02:00 UTC, 5m jitter - deploy/scripts/install.sh: install backup units and enable timer; create certs/ and backups/ subdirs in /srv/mcias - buf.yaml: add proto linting config for proto-lint target - internal/db: add Snapshot and SnapshotDir methods (VACUUM INTO) - cmd/mciasdb: add snapshot subcommand; no master key required
This commit is contained in:
50
deploy/examples/mcias-dev.conf.example
Normal file
50
deploy/examples/mcias-dev.conf.example
Normal file
@@ -0,0 +1,50 @@
|
||||
# mcias-dev.conf — Local development configuration for mciassrv
|
||||
#
|
||||
# Suitable for running mciassrv on a developer workstation.
|
||||
# DO NOT use this configuration in production:
|
||||
# - Tokens expire quickly (for rapid test iteration).
|
||||
# - The master key passphrase is trivial.
|
||||
# - TLS paths point to local self-signed certificates.
|
||||
#
|
||||
# Generate a self-signed certificate for local development:
|
||||
# openssl req -x509 -newkey ed25519 -days 365 \
|
||||
# -keyout /tmp/mcias-dev.key -out /tmp/mcias-dev.crt \
|
||||
# -subj "/CN=localhost" -nodes
|
||||
#
|
||||
# Set the master passphrase:
|
||||
# export MCIAS_MASTER_PASSPHRASE=devpassphrase
|
||||
#
|
||||
# Start the server:
|
||||
# mciassrv -config /path/to/mcias-dev.toml
|
||||
|
||||
[server]
|
||||
listen_addr = "127.0.0.1:8443"
|
||||
grpc_addr = "127.0.0.1:9443"
|
||||
tls_cert = "/tmp/mcias-dev.crt"
|
||||
tls_key = "/tmp/mcias-dev.key"
|
||||
# trusted_proxy not set — direct local development, no reverse proxy.
|
||||
|
||||
[database]
|
||||
path = "/tmp/mcias-dev.db"
|
||||
|
||||
[tokens]
|
||||
issuer = "https://localhost:8443"
|
||||
default_expiry = "1h"
|
||||
admin_expiry = "30m"
|
||||
service_expiry = "24h"
|
||||
|
||||
[argon2]
|
||||
# OWASP minimums maintained even in dev; do not reduce further.
|
||||
time = 2
|
||||
memory = 65536
|
||||
threads = 4
|
||||
|
||||
[master_key]
|
||||
passphrase_env = "MCIAS_MASTER_PASSPHRASE"
|
||||
|
||||
# WebAuthn — passkey authentication for local development.
|
||||
# rp_origin includes the non-standard port since we're not behind a proxy.
|
||||
[webauthn]
|
||||
rp_id = "localhost"
|
||||
rp_origin = "https://localhost:8443"
|
||||
display_name = "MCIAS (dev)"
|
||||
61
deploy/examples/mcias.conf.docker.example
Normal file
61
deploy/examples/mcias.conf.docker.example
Normal file
@@ -0,0 +1,61 @@
|
||||
# mcias.conf.docker.example — Config template for container deployment
|
||||
#
|
||||
# Mount this file into the container at /srv/mcias/mcias.toml:
|
||||
#
|
||||
# docker run -d \
|
||||
# --name mcias \
|
||||
# -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:
|
||||
# - /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. 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 = "/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]
|
||||
# All data lives under /srv/mcias for a single-volume deployment.
|
||||
path = "/srv/mcias/mcias.db"
|
||||
|
||||
[tokens]
|
||||
issuer = "https://auth.example.com"
|
||||
default_expiry = "168h"
|
||||
admin_expiry = "8h"
|
||||
service_expiry = "8760h"
|
||||
|
||||
[argon2]
|
||||
time = 3
|
||||
memory = 65536
|
||||
threads = 4
|
||||
|
||||
[master_key]
|
||||
# Pass the passphrase via the MCIAS_MASTER_PASSPHRASE environment variable.
|
||||
# Set it with: docker run -e MCIAS_MASTER_PASSPHRASE=your-passphrase ...
|
||||
# or with a Docker secret / Kubernetes secret.
|
||||
passphrase_env = "MCIAS_MASTER_PASSPHRASE"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [webauthn] — FIDO2/WebAuthn passkey authentication (OPTIONAL)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Uncomment to enable passwordless passkey login. Set rp_id to your domain
|
||||
# and rp_origin to the full HTTPS origin users access in their browser.
|
||||
#
|
||||
# [webauthn]
|
||||
# rp_id = "auth.example.com"
|
||||
# rp_origin = "https://auth.example.com"
|
||||
# display_name = "MCIAS"
|
||||
146
deploy/examples/mcias.conf.example
Normal file
146
deploy/examples/mcias.conf.example
Normal file
@@ -0,0 +1,146 @@
|
||||
# mcias.conf — Reference configuration for mciassrv
|
||||
#
|
||||
# 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 /srv/mcias/mcias.toml
|
||||
# chown root:mcias /srv/mcias/mcias.toml
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [server] — Network listener configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
[server]
|
||||
|
||||
# REQUIRED. Address and port for the HTTPS REST listener.
|
||||
# Format: "host:port". Use "0.0.0.0" to listen on all interfaces.
|
||||
# Ports > 1024 do not require elevated privileges.
|
||||
listen_addr = "0.0.0.0:8443"
|
||||
|
||||
# OPTIONAL. Address and port for the gRPC/TLS listener.
|
||||
# If omitted, the gRPC listener is disabled and only REST is served.
|
||||
# Format: "host:port".
|
||||
# grpc_addr = "0.0.0.0:9443"
|
||||
|
||||
# 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 = "/srv/mcias/server.crt"
|
||||
|
||||
# REQUIRED. Path to the TLS private key (PEM format).
|
||||
# Permissions: mode 0640, owner root:mcias.
|
||||
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
|
||||
# X-Real-IP or X-Forwarded-For header, but ONLY for requests whose TCP source
|
||||
# address matches this exact IP. All other requests use RemoteAddr directly,
|
||||
# preventing IP spoofing by external clients.
|
||||
#
|
||||
# Must be an IP address, not a hostname or CIDR range.
|
||||
# Omit when running without a reverse proxy (direct Internet exposure).
|
||||
#
|
||||
# Example — local nginx proxy:
|
||||
# trusted_proxy = "127.0.0.1"
|
||||
#
|
||||
# Example — Docker network gateway:
|
||||
# trusted_proxy = "172.17.0.1"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [database] — SQLite database
|
||||
# ---------------------------------------------------------------------------
|
||||
[database]
|
||||
|
||||
# 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 = "/srv/mcias/mcias.db"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [tokens] — JWT issuance policy
|
||||
# ---------------------------------------------------------------------------
|
||||
[tokens]
|
||||
|
||||
# REQUIRED. Issuer claim embedded in every JWT. Relying parties should
|
||||
# validate this claim matches the expected value.
|
||||
# Use the base URL of your MCIAS server (without trailing slash).
|
||||
issuer = "https://auth.example.com"
|
||||
|
||||
# OPTIONAL. Default token expiry for interactive (human) logins.
|
||||
# Go duration string: "h" hours, "m" minutes, "s" seconds.
|
||||
# Default: 168h (7 days). The maximum allowed value is 720h (30 days).
|
||||
default_expiry = "168h"
|
||||
|
||||
# OPTIONAL. Expiry for admin tokens (tokens with the "admin" role).
|
||||
# Should be shorter than default_expiry to limit the blast radius of
|
||||
# a leaked admin credential.
|
||||
# Default: 8h.
|
||||
admin_expiry = "8h"
|
||||
|
||||
# OPTIONAL. Expiry for system account tokens (machine-to-machine).
|
||||
# System accounts have no interactive login; their tokens are long-lived.
|
||||
# Default: 8760h (365 days).
|
||||
service_expiry = "8760h"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [argon2] — Password hashing parameters (Argon2id)
|
||||
# ---------------------------------------------------------------------------
|
||||
[argon2]
|
||||
|
||||
# OWASP 2023 minimums: time >= 2, memory >= 65536 KiB (64 MB).
|
||||
# Increasing these values improves resistance to brute-force attacks but
|
||||
# increases CPU and memory usage at login time.
|
||||
|
||||
# OPTIONAL. Time cost (number of passes over memory). Default: 3.
|
||||
time = 3
|
||||
|
||||
# OPTIONAL. Memory cost in KiB. Default: 65536 (64 MB).
|
||||
memory = 65536
|
||||
|
||||
# OPTIONAL. Parallelism (number of threads). Default: 4.
|
||||
threads = 4
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [master_key] — AES-256 master key derivation
|
||||
# ---------------------------------------------------------------------------
|
||||
[master_key]
|
||||
|
||||
# REQUIRED. Exactly ONE of passphrase_env or keyfile must be set.
|
||||
|
||||
# Option A: Passphrase mode. The passphrase is read from the named environment
|
||||
# variable at startup, then cleared. The Argon2id KDF salt is stored in the
|
||||
# database on first run and reused on subsequent runs so the same passphrase
|
||||
# always produces the same master key.
|
||||
#
|
||||
# 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 /srv/mcias/master.key 32
|
||||
# Permissions: mode 0640, owner root:mcias.
|
||||
#
|
||||
# Uncomment and comment out passphrase_env to switch modes.
|
||||
# keyfile = "/srv/mcias/master.key"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# [webauthn] — FIDO2/WebAuthn passkey authentication (OPTIONAL)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Enables passwordless passkey login and hardware security key 2FA.
|
||||
# If this section is omitted or rp_id/rp_origin are empty, WebAuthn is
|
||||
# disabled and passkey options will not appear in the UI.
|
||||
#
|
||||
# [webauthn]
|
||||
#
|
||||
# REQUIRED (if enabling). The Relying Party ID — typically the domain name
|
||||
# (without port or scheme). Must match the domain users see in their browser.
|
||||
# rp_id = "auth.example.com"
|
||||
#
|
||||
# REQUIRED (if enabling). The Relying Party Origin — the full origin URL
|
||||
# including scheme. Must be HTTPS. Include the port if non-standard (not 443).
|
||||
# rp_origin = "https://auth.example.com"
|
||||
#
|
||||
# OPTIONAL. Display name shown to users during passkey registration prompts.
|
||||
# Default: "MCIAS".
|
||||
# display_name = "MCIAS"
|
||||
17
deploy/examples/mcias.env.example
Normal file
17
deploy/examples/mcias.env.example
Normal file
@@ -0,0 +1,17 @@
|
||||
# /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 /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.
|
||||
# Back it up to a secure offline location — losing this passphrase means
|
||||
# losing access to all encrypted data in the database.
|
||||
|
||||
# Master key passphrase. Used to derive the AES-256 master key via Argon2id.
|
||||
# Choose a long, random passphrase (e.g., generated by `openssl rand -base64 32`).
|
||||
# This must match the passphrase_env setting in mcias.conf.
|
||||
MCIAS_MASTER_PASSPHRASE=change-me-to-a-long-random-passphrase
|
||||
230
deploy/scripts/install.sh
Normal file
230
deploy/scripts/install.sh
Normal file
@@ -0,0 +1,230 @@
|
||||
#!/bin/sh
|
||||
# install.sh — MCIAS first-time and upgrade installer
|
||||
#
|
||||
# Usage: sh deploy/scripts/install.sh
|
||||
#
|
||||
# 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 /srv/mcias/ with correct permissions.
|
||||
# 4. Installs the systemd service and backup units.
|
||||
# 5. Prints post-install instructions.
|
||||
#
|
||||
# The script does NOT start or enable the service automatically. Review the
|
||||
# configuration files and set the master key passphrase before starting.
|
||||
#
|
||||
# Idempotent: safe to re-run after upgrades. Existing config files are not
|
||||
# overwritten; new example files are placed alongside them with a .new suffix
|
||||
# so you can review and merge changes.
|
||||
#
|
||||
# POSIX sh compatible — no bash-isms.
|
||||
|
||||
set -eu
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
BIN_DIR="/usr/local/bin"
|
||||
SRV_DIR="/srv/mcias"
|
||||
MAN_DIR="/usr/share/man/man1"
|
||||
SYSTEMD_DIR="/etc/systemd/system"
|
||||
SERVICE_USER="mcias"
|
||||
SERVICE_GROUP="mcias"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
DEPLOY_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
REPO_ROOT="$(dirname "$DEPLOY_DIR")"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
info() {
|
||||
printf '==> %s\n' "$*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
printf 'WARNING: %s\n' "$*" >&2
|
||||
}
|
||||
|
||||
die() {
|
||||
printf 'ERROR: %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
die "This script must be run as root."
|
||||
fi
|
||||
}
|
||||
|
||||
# install_file SRC DST MODE OWNER
|
||||
# Installs SRC to DST. If DST already exists, installs SRC as DST.new
|
||||
# so the operator can review changes.
|
||||
install_file() {
|
||||
src="$1"
|
||||
dst="$2"
|
||||
mode="$3"
|
||||
owner="$4"
|
||||
|
||||
if [ -e "$dst" ]; then
|
||||
info "Existing file found: $dst (installing as $dst.new)"
|
||||
install -m "$mode" -o "$owner" "$src" "$dst.new"
|
||||
else
|
||||
install -m "$mode" -o "$owner" "$src" "$dst"
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Main
|
||||
# ---------------------------------------------------------------------------
|
||||
require_root
|
||||
|
||||
# Step 1: Create system user and group.
|
||||
info "Creating system user and group: $SERVICE_USER"
|
||||
if getent group "$SERVICE_GROUP" > /dev/null 2>&1; then
|
||||
info "Group $SERVICE_GROUP already exists — skipping."
|
||||
else
|
||||
groupadd --system "$SERVICE_GROUP"
|
||||
fi
|
||||
|
||||
if getent passwd "$SERVICE_USER" > /dev/null 2>&1; then
|
||||
info "User $SERVICE_USER already exists — skipping."
|
||||
else
|
||||
useradd \
|
||||
--system \
|
||||
--gid "$SERVICE_GROUP" \
|
||||
--no-create-home \
|
||||
--shell /usr/sbin/nologin \
|
||||
--comment "MCIAS authentication server" \
|
||||
"$SERVICE_USER"
|
||||
fi
|
||||
|
||||
# Step 2: Install binaries.
|
||||
info "Installing binaries to $BIN_DIR"
|
||||
for bin in mciassrv mciasctl mciasdb mciasgrpcctl; do
|
||||
src="$REPO_ROOT/bin/$bin"
|
||||
if [ ! -f "$src" ]; then
|
||||
warn "Binary not found: $bin — skipping. Run 'make build' first."
|
||||
continue
|
||||
fi
|
||||
info " Installing $bin"
|
||||
install -m 0755 -o root -g root "$src" "$BIN_DIR/$bin"
|
||||
done
|
||||
|
||||
# Step 3: Create service directory structure.
|
||||
info "Creating $SRV_DIR"
|
||||
install -d -m 0750 -o "$SERVICE_USER" -g "$SERVICE_GROUP" "$SRV_DIR"
|
||||
install -d -m 0750 -o "$SERVICE_USER" -g "$SERVICE_GROUP" "$SRV_DIR/certs"
|
||||
install -d -m 0750 -o "$SERVICE_USER" -g "$SERVICE_GROUP" "$SRV_DIR/backups"
|
||||
|
||||
# Install example config files; never overwrite existing configs.
|
||||
for f in mcias.conf.example mcias.env.example; do
|
||||
src="$DEPLOY_DIR/examples/$f"
|
||||
dst="$SRV_DIR/$f"
|
||||
if [ -f "$src" ]; then
|
||||
install -m 0640 -o "$SERVICE_USER" -g "$SERVICE_GROUP" "$src" "$dst" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Step 4: Install systemd units.
|
||||
if [ -d "$SYSTEMD_DIR" ]; then
|
||||
info "Installing systemd units to $SYSTEMD_DIR"
|
||||
for unit in mcias.service mcias-backup.service mcias-backup.timer; do
|
||||
src="$DEPLOY_DIR/systemd/$unit"
|
||||
if [ -f "$src" ]; then
|
||||
install -m 0644 -o root -g root "$src" "$SYSTEMD_DIR/$unit"
|
||||
info " Installed $unit"
|
||||
fi
|
||||
done
|
||||
info "Reloading systemd daemon"
|
||||
systemctl daemon-reload 2>/dev/null || warn "systemctl not available; reload manually."
|
||||
info "Enabling backup timer"
|
||||
systemctl enable mcias-backup.timer 2>/dev/null || warn "Could not enable timer; enable manually with: systemctl enable mcias-backup.timer"
|
||||
else
|
||||
warn "systemd not found at $SYSTEMD_DIR; skipping service unit installation."
|
||||
fi
|
||||
|
||||
# Step 5: Install man pages.
|
||||
if [ -d "$REPO_ROOT/man/man1" ]; then
|
||||
install -d -m 0755 -o root -g root "$MAN_DIR"
|
||||
info "Installing man pages to $MAN_DIR"
|
||||
for page in "$REPO_ROOT/man/man1"/*.1.gz; do
|
||||
[ -f "$page" ] || continue
|
||||
install -m 0644 -o root -g root "$page" "$MAN_DIR/"
|
||||
done
|
||||
# Also install uncompressed pages if no gz versions exist.
|
||||
for page in "$REPO_ROOT/man/man1"/*.1; do
|
||||
[ -f "$page" ] || continue
|
||||
gzname="${MAN_DIR}/$(basename "$page").gz"
|
||||
if [ ! -f "$gzname" ]; then
|
||||
gzip -c "$page" > "$gzname"
|
||||
chmod 0644 "$gzname"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Post-install instructions
|
||||
# ---------------------------------------------------------------------------
|
||||
cat <<EOF
|
||||
|
||||
==========================================================================
|
||||
MCIAS installed successfully.
|
||||
==========================================================================
|
||||
|
||||
Next steps:
|
||||
|
||||
1. Generate a TLS certificate and key:
|
||||
|
||||
# Self-signed (development / personal use):
|
||||
openssl req -x509 -newkey ed25519 -days 3650 \\
|
||||
-keyout /srv/mcias/certs/server.key \\
|
||||
-out /srv/mcias/certs/server.crt \\
|
||||
-subj "/CN=auth.example.com" \\
|
||||
-nodes
|
||||
chmod 0640 /srv/mcias/certs/server.key
|
||||
chown mcias:mcias /srv/mcias/certs/server.key /srv/mcias/certs/server.crt
|
||||
|
||||
2. Copy and edit the configuration file:
|
||||
|
||||
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 /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.
|
||||
|
||||
4. Enable and start the service:
|
||||
|
||||
systemctl enable mcias
|
||||
systemctl start mcias
|
||||
systemctl status mcias
|
||||
|
||||
The backup timer was enabled automatically. Verify with:
|
||||
systemctl status mcias-backup.timer
|
||||
|
||||
5. Create the first admin account using mciasdb (while the server is
|
||||
running, or before first start):
|
||||
|
||||
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 /srv/mcias/mcias.toml \\
|
||||
account set-password --id <UUID>
|
||||
|
||||
And grant the admin role:
|
||||
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /srv/mcias/mcias.toml \\
|
||||
role grant --id <UUID> --role admin
|
||||
|
||||
For full documentation, see: man mciassrv
|
||||
==========================================================================
|
||||
EOF
|
||||
32
deploy/systemd/mcias-backup.service
Normal file
32
deploy/systemd/mcias-backup.service
Normal file
@@ -0,0 +1,32 @@
|
||||
[Unit]
|
||||
Description=MCIAS Database Backup
|
||||
Documentation=man:mciasdb(1)
|
||||
After=mcias.service
|
||||
# Backup runs against the live database using VACUUM INTO, which is safe
|
||||
# while mciassrv is running (WAL mode allows concurrent readers).
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=mcias
|
||||
Group=mcias
|
||||
|
||||
EnvironmentFile=/srv/mcias/env
|
||||
|
||||
ExecStart=/usr/local/bin/mciasdb -config /srv/mcias/mcias.toml snapshot
|
||||
|
||||
# Filesystem restrictions (read-write to /srv/mcias for the backup output).
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
ReadWritePaths=/srv/mcias
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
CapabilityBoundingSet=
|
||||
RestrictSUIDSGID=true
|
||||
RestrictNamespaces=true
|
||||
RestrictRealtime=true
|
||||
LockPersonality=true
|
||||
MemoryDenyWriteExecute=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
15
deploy/systemd/mcias-backup.timer
Normal file
15
deploy/systemd/mcias-backup.timer
Normal file
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=Daily MCIAS Database Backup
|
||||
Documentation=man:mciasdb(1)
|
||||
|
||||
[Timer]
|
||||
# Run daily at 02:00 UTC with up to 5-minute random jitter to avoid
|
||||
# thundering-herd on systems with many services.
|
||||
OnCalendar=*-*-* 02:00:00 UTC
|
||||
RandomizedDelaySec=5min
|
||||
# Run immediately on boot if the last scheduled run was missed
|
||||
# (e.g. host was offline at 02:00).
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
52
deploy/systemd/mcias.service
Normal file
52
deploy/systemd/mcias.service
Normal file
@@ -0,0 +1,52 @@
|
||||
[Unit]
|
||||
Description=MCIAS Authentication Server
|
||||
Documentation=man:mciassrv(1)
|
||||
After=network.target
|
||||
# Require network to be available before starting.
|
||||
# Remove if you bind only to loopback.
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=mcias
|
||||
Group=mcias
|
||||
|
||||
# Configuration and secrets.
|
||||
# /srv/mcias/env must contain MCIAS_MASTER_PASSPHRASE=<passphrase>
|
||||
# See deploy/examples/mcias.env.example for the template.
|
||||
EnvironmentFile=/srv/mcias/env
|
||||
|
||||
ExecStart=/usr/local/bin/mciassrv -config /srv/mcias/mcias.toml
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# File descriptor limit. mciassrv keeps one fd per open connection plus
|
||||
# the SQLite WAL files; 65536 is generous headroom for a personal server.
|
||||
LimitNOFILE=65536
|
||||
|
||||
# Sandboxing. mcias does not need capabilities; it listens on ports > 1024.
|
||||
# If you need port 443 or 8443 on a privileged port (< 1024), either:
|
||||
# a) use a reverse proxy (recommended), or
|
||||
# b) grant CAP_NET_BIND_SERVICE with: AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=
|
||||
|
||||
# Filesystem restrictions.
|
||||
# mciassrv reads and writes /srv/mcias (config, TLS cert/key, database).
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
ReadWritePaths=/srv/mcias
|
||||
|
||||
# Additional hardening.
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
RestrictSUIDSGID=true
|
||||
RestrictNamespaces=true
|
||||
RestrictRealtime=true
|
||||
LockPersonality=true
|
||||
MemoryDenyWriteExecute=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user