# MCIAS Runbook Operational procedures for running and maintaining the MCIAS authentication server. All required files live under `/srv/mcias`. --- ## Directory Layout ``` /srv/mcias/ mcias.toml — server configuration (TOML) server.crt — TLS certificate (PEM) server.key — TLS private key (PEM, mode 0640) mcias.db — SQLite database (WAL mode creates .db-wal and .db-shm) env — environment file: MCIAS_MASTER_PASSPHRASE (mode 0640) master.key — optional raw AES-256 key file (mode 0640, alternative to env) ``` All files are owned by the `mcias` system user and group (`mcias:mcias`). The directory itself is mode `0750`. --- ## Installation Run as root from the repository root after `make build`: ```sh sh dist/install.sh ``` This script is idempotent. It: 1. Creates the `mcias` system user and group if they do not exist. 2. Installs binaries to `/usr/local/bin/`. 3. Creates `/srv/mcias/` with correct ownership and permissions. 4. Installs the systemd service unit to `/etc/systemd/system/mcias.service`. 5. Installs example config files to `/srv/mcias/` (will not overwrite existing files). After installation, complete the steps below before starting the service. --- ## First-Run Setup ### 1. Generate a TLS certificate **Self-signed (personal/development use):** ```sh openssl req -x509 -newkey ed25519 -days 3650 \ -keyout /srv/mcias/server.key \ -out /srv/mcias/server.crt \ -subj "/CN=auth.example.com" \ -nodes chmod 0640 /srv/mcias/server.key chown mcias:mcias /srv/mcias/server.key /srv/mcias/server.crt ``` **Using the `cert` tool:** ```sh go install github.com/kisom/cert@latest cat > /tmp/request.yaml < /srv/mcias/server.key cert selfsign -p /srv/mcias/server.key -f /tmp/request.yaml > /srv/mcias/server.crt chmod 0640 /srv/mcias/server.key chown mcias:mcias /srv/mcias/server.key /srv/mcias/server.crt rm /tmp/request.yaml ``` ### 2. Write the configuration file ```sh 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 ``` Minimum required settings: ```toml [server] listen_addr = "0.0.0.0:8443" tls_cert = "/srv/mcias/server.crt" tls_key = "/srv/mcias/server.key" [database] path = "/srv/mcias/mcias.db" [tokens] issuer = "https://auth.example.com" [master_key] passphrase_env = "MCIAS_MASTER_PASSPHRASE" ``` See `dist/mcias.conf.example` for the full annotated reference. ### 3. Set the master key passphrase ```sh cp /srv/mcias/mcias.env.example /srv/mcias/env $EDITOR /srv/mcias/env # set MCIAS_MASTER_PASSPHRASE to a long random value chmod 0640 /srv/mcias/env chown mcias:mcias /srv/mcias/env ``` Generate a strong passphrase: ```sh openssl rand -base64 32 ``` > **IMPORTANT:** Back up the passphrase to a secure offline location. > Losing it permanently destroys access to all encrypted data in the database. ### 4. Create the first admin account ```sh export MCIAS_MASTER_PASSPHRASE=your-passphrase mciasdb --config /srv/mcias/mcias.toml account create \ --username admin --type human # note the UUID printed mciasdb --config /srv/mcias/mcias.toml account set-password --id mciasdb --config /srv/mcias/mcias.toml role grant --id --role admin ``` ### 5. Enable and start the service ```sh systemctl enable mcias systemctl start mcias systemctl status mcias ``` ### 6. Verify ```sh curl -k https://auth.example.com:8443/v1/health # {"status":"ok"} ``` --- ## Routine Operations ### Start / stop / restart ```sh systemctl start mcias systemctl stop mcias systemctl restart mcias ``` ### View logs ```sh journalctl -u mcias -f journalctl -u mcias --since "1 hour ago" ``` ### Check service status ```sh systemctl status mcias ``` ### Reload configuration The server reads its configuration at startup only. To apply config changes: ```sh systemctl restart mcias ``` --- ## Account Management All account management can be done via `mciasctl` (REST API) when the server is running, or `mciasdb` for offline/break-glass operations. ```sh # Set env for offline tool export MCIAS_MASTER_PASSPHRASE=your-passphrase CONF="--config /srv/mcias/mcias.toml" # List accounts mciasdb $CONF account list # Create account mciasdb $CONF account create --username alice --type human # Set password (prompts interactively) mciasdb $CONF account set-password --id # Grant or revoke a role mciasdb $CONF role grant --id --role admin mciasdb $CONF role revoke --id --role admin # Disable account mciasdb $CONF account set-status --id --status inactive # Delete account mciasdb $CONF account set-status --id --status deleted ``` --- ## Token Management ```sh CONF="--config /srv/mcias/mcias.toml" # List active tokens for an account mciasdb $CONF token list --id # Revoke a specific token by JTI mciasdb $CONF token revoke --jti # Revoke all tokens for an account (e.g., suspected compromise) mciasdb $CONF token revoke-all --id # Prune expired tokens from the database mciasdb $CONF prune tokens ``` --- ## Database Maintenance ### Verify schema ```sh mciasdb --config /srv/mcias/mcias.toml schema verify ``` ### Run pending migrations ```sh mciasdb --config /srv/mcias/mcias.toml schema migrate ``` ### Force schema version (break-glass) ```sh mciasdb --config /srv/mcias/mcias.toml schema force --version N ``` Use only when `schema migrate` reports a dirty version after a failed migration. ### Backup the database SQLite WAL mode creates three files. Back up all three atomically using the SQLite backup API or by stopping the server first: ```sh # Online backup (preferred — no downtime): sqlite3 /srv/mcias/mcias.db ".backup /path/to/backup/mcias-$(date +%F).db" # Offline backup: systemctl stop mcias cp /srv/mcias/mcias.db /path/to/backup/mcias-$(date +%F).db systemctl start mcias ``` Store backups alongside a copy of the master key passphrase in a secure offline location. A database backup without the passphrase is unrecoverable. --- ## Audit Log ```sh CONF="--config /srv/mcias/mcias.toml" # Show last 50 audit events mciasdb $CONF audit tail --n 50 # Query by account mciasdb $CONF audit query --account # Query by event type since a given time mciasdb $CONF audit query --type login_failure --since 2026-01-01T00:00:00Z # Output as JSON (for log shipping) mciasdb $CONF audit query --json ``` --- ## Upgrading 1. Build the new binaries: `make build` 2. Stop the service: `systemctl stop mcias` 3. Install new binaries: `sh dist/install.sh` - The script will not overwrite existing config files. - New example files are placed with a `.new` suffix for review. 4. Review any `.new` config files in `/srv/mcias/` and merge changes manually. 5. Run schema migrations if required: ```sh mciasdb --config /srv/mcias/mcias.toml schema migrate ``` 6. Start the service: `systemctl start mcias` 7. Verify: `curl -k https://auth.example.com:8443/v1/health` --- ## WebAuthn / Passkey Configuration WebAuthn enables passwordless passkey login and hardware security key 2FA. It is **disabled by default** — to enable it, add a `[webauthn]` section to `mcias.toml` with the relying party ID and origin. ### Enable WebAuthn Add to `/srv/mcias/mcias.toml`: ```toml [webauthn] rp_id = "auth.example.com" rp_origin = "https://auth.example.com" display_name = "MCIAS" ``` - **`rp_id`** — The domain name (no scheme or port). Must match the domain users see in their browser address bar. - **`rp_origin`** — The full HTTPS origin. Include the port if non-standard (e.g., `https://localhost:8443` for development). - **`display_name`** — Shown to users during browser passkey prompts. Defaults to "MCIAS" if omitted. Restart the server after changing the config: ```sh systemctl restart mcias ``` Once enabled, the **Passkeys** section appears on the user's Profile page (self-service enrollment) and on the admin Account Detail page (credential management). ### Passkey enrollment Passkey enrollment is self-service only. Users add passkeys from their **Profile → Passkeys** section. Admins can view and remove passkeys from the Account Detail page but cannot enroll on behalf of users (passkey registration requires the authenticator device to be present). ### Disable WebAuthn Remove or comment out the `[webauthn]` section and restart. Existing credentials remain in the database but are unused. Passkey UI sections will be hidden. ### Remove all passkeys for an account (break-glass) ```sh mciasdb --config /srv/mcias/mcias.toml account reset-webauthn --id ``` --- ## TOTP Two-Factor Authentication TOTP enrollment is self-service via the **Profile → Two-Factor Authentication** section. Users enter their current password to begin enrollment, scan the QR code with an authenticator app, and confirm with a 6-digit code. ### Admin: Remove TOTP for an account From the web UI: navigate to the account's detail page and click **Remove** next to the TOTP status. From the CLI: ```sh mciasdb --config /srv/mcias/mcias.toml account reset-totp --id ``` This clears the TOTP secret and disables the 2FA requirement. The user can re-enroll from their Profile page. --- ## Master Key Rotation > This operation is not yet automated. Until a rotation command is > implemented, rotation requires a full re-encryption of the database. > Contact the project maintainer for the current procedure. --- ## TLS Certificate Renewal Replace the certificate and key files, then restart the server: ```sh # Generate or obtain new cert/key, then: cp new-server.crt /srv/mcias/server.crt cp new-server.key /srv/mcias/server.key chmod 0640 /srv/mcias/server.key chown mcias:mcias /srv/mcias/server.crt /srv/mcias/server.key systemctl restart mcias ``` For Let's Encrypt with Certbot, add a deploy hook: ```sh # /etc/letsencrypt/renewal-hooks/deploy/mcias.sh #!/bin/sh cp /etc/letsencrypt/live/auth.example.com/fullchain.pem /srv/mcias/server.crt cp /etc/letsencrypt/live/auth.example.com/privkey.pem /srv/mcias/server.key chmod 0640 /srv/mcias/server.key chown mcias:mcias /srv/mcias/server.crt /srv/mcias/server.key systemctl restart mcias ``` --- ## Docker Deployment ```sh make docker mkdir -p /srv/mcias cp dist/mcias.conf.docker.example /srv/mcias/mcias.toml $EDITOR /srv/mcias/mcias.toml # Place TLS cert and key under /srv/mcias/ # Set ownership so uid 10001 (container mcias user) can read them. chown -R 10001:10001 /srv/mcias docker run -d \ --name mcias \ -v /srv/mcias:/srv/mcias \ -e MCIAS_MASTER_PASSPHRASE=your-passphrase \ -p 8443:8443 \ -p 9443:9443 \ --restart unless-stopped \ mcias:latest ``` See `dist/mcias.conf.docker.example` for the full annotated Docker config. --- ## Troubleshooting ### Server fails to start: "open database" Check that `/srv/mcias/` is writable by the `mcias` user: ```sh ls -la /srv/mcias/ stat /srv/mcias/mcias.db # if it already exists ``` Fix: `chown mcias:mcias /srv/mcias` ### Server fails to start: "environment variable ... is not set" The `MCIAS_MASTER_PASSPHRASE` env var is missing. Ensure `/srv/mcias/env` exists, is readable by the mcias user, and contains the correct variable: ```sh grep MCIAS_MASTER_PASSPHRASE /srv/mcias/env ``` Also confirm the systemd unit loads it: ```sh systemctl cat mcias | grep EnvironmentFile ``` ### Server fails to start: "decrypt signing key" The master key passphrase has changed or is wrong. The passphrase must match the one used when the database was first initialized (the KDF salt is stored in the database). Restore the correct passphrase from your offline backup. ### TLS errors in client connections Verify the certificate is valid and covers the correct hostname: ```sh openssl x509 -in /srv/mcias/server.crt -noout -text | grep -E "Subject|DNS" openssl x509 -in /srv/mcias/server.crt -noout -dates ``` ### Database locked / WAL not cleaning up Check for lingering `mcias.db-wal` and `mcias.db-shm` files after an unclean shutdown. These are safe to leave in place — SQLite will recover on next open. Do not delete them while the server is running. ### Schema dirty after failed migration ```sh mciasdb --config /srv/mcias/mcias.toml schema verify mciasdb --config /srv/mcias/mcias.toml schema force --version N mciasdb --config /srv/mcias/mcias.toml schema migrate ``` Replace `N` with the last successfully applied version number. --- ## File Permissions Reference | Path | Mode | Owner | |------|------|-------| | `/srv/mcias/` | `0750` | `mcias:mcias` | | `/srv/mcias/mcias.toml` | `0640` | `mcias:mcias` | | `/srv/mcias/server.crt` | `0644` | `mcias:mcias` | | `/srv/mcias/server.key` | `0640` | `mcias:mcias` | | `/srv/mcias/mcias.db` | `0640` | `mcias:mcias` | | `/srv/mcias/env` | `0640` | `mcias:mcias` | | `/srv/mcias/master.key` | `0640` | `mcias:mcias` | Verify permissions: ```sh ls -la /srv/mcias/ ```