Implement Phase 8: operational artifacts

- Makefile: build/test/lint/generate/man/install/clean/dist/docker;
  CGO_ENABLED=1 throughout; VERSION from git describe --tags --always
- Dockerfile: multi-stage (golang:1.26-bookworm builder ->
  debian:bookworm-slim runtime); non-root uid 10001 (mcias),
  VOLUME /data, EXPOSE 8443/9443; no toolchain in final image
- dist/mcias.service: hardened systemd unit (ProtectSystem=strict,
  ProtectHome, PrivateTmp, NoNewPrivileges, MemoryDenyWriteExecute,
  CapabilityBoundingSet= empty, EnvironmentFile, LimitNOFILE=65536)
- dist/mcias.env.example: passphrase env file template
- dist/mcias.conf.example: fully-commented production TOML config
- dist/mcias-dev.conf.example: local dev config (/tmp, short expiry)
- dist/mcias.conf.docker.example: container config template
- dist/install.sh: POSIX sh idempotent installer; creates mcias
  user/group, installs binaries, /etc/mcias, /var/lib/mcias,
  systemd unit, man pages; prints post-install instructions
- man/man1/mciassrv.1: mdoc synopsis/config/API/signals/files
- man/man1/mciasctl.1: mdoc all subcommands/env/examples
- man/man1/mciasdb.1: mdoc trust model/safety/all subcommands
- man/man1/mciasgrpcctl.1: mdoc gRPC commands/grpcurl example
- README.md: user-facing quick-start, first-run setup, build
  instructions, CLI references, Docker deployment, security notes
- .gitignore: added /bin/, dist/mcias_*.tar.gz, man/man1/*.gz
This commit is contained in:
2026-03-11 15:11:36 -07:00
parent 8f706f10ec
commit 941c71f2d1
15 changed files with 1715 additions and 54 deletions

124
man/man1/mciasctl.1 Normal file
View File

@@ -0,0 +1,124 @@
.Dd March 11, 2026
.Dt MCIASCTL 1
.Os
.Sh NAME
.Nm mciasctl
.Nd MCIAS admin CLI (REST)
.Sh SYNOPSIS
.Nm
.Op Fl server Ar url
.Op Fl token Ar jwt
.Op Fl cacert Ar path
.Ar command
.Op Ar subcommand
.Op Ar flags
.Sh DESCRIPTION
.Nm
is the administrator command-line interface for MCIAS.
It connects to a running
.Xr mciassrv 1
instance via the REST API over HTTPS and provides subcommands for managing
accounts, roles, tokens, and Postgres credentials.
.Pp
Authentication is performed using a bearer JWT.
The token must have the
.Qq admin
role for most operations.
Pass the token with the
.Fl token
flag or by setting the
.Ev MCIAS_TOKEN
environment variable.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl server Ar url
Base URL of the mciassrv instance.
Default:
.Qq https://localhost:8443 .
Can also be set with the
.Ev MCIAS_SERVER
environment variable.
.It Fl token Ar jwt
Bearer token for authentication.
Can also be set with the
.Ev MCIAS_TOKEN
environment variable.
.It Fl cacert Ar path
Path to a CA certificate in PEM format for TLS verification.
Useful when mciassrv uses a self-signed certificate.
If omitted, the system certificate pool is used.
.El
.Sh COMMANDS
.Ss account
.Bl -tag -width Ds
.It Nm Ic account Ic list
Lists all accounts.
Credential fields are never included in the output.
.It Nm Ic account Ic create Fl username Ar name Fl password Ar pass Op Fl type Ar human|system
Creates a new account.
.Fl type
defaults to
.Qq human .
.It Nm Ic account Ic get Fl id Ar uuid
Returns the account with the given UUID.
.It Nm Ic account Ic update Fl id Ar uuid Op Fl status Ar active|inactive
Updates account fields.
Currently only status can be updated.
.It Nm Ic account Ic delete Fl id Ar uuid
Soft-deletes the account and revokes all its tokens.
.El
.Ss role
.Bl -tag -width Ds
.It Nm Ic role Ic list Fl id Ar uuid
Lists the roles assigned to the account.
.It Nm Ic role Ic set Fl id Ar uuid Fl roles Ar role1,role2,...
Replaces the role set for the account with the comma-separated list.
.El
.Ss token
.Bl -tag -width Ds
.It Nm Ic token Ic issue Fl id Ar uuid
Issues a new service token for a system account.
.It Nm Ic token Ic revoke Fl jti Ar jti
Revokes the token with the given JTI.
.El
.Ss pgcreds
.Bl -tag -width Ds
.It Nm Ic pgcreds Ic set Fl id Ar uuid Fl host Ar host Fl port Ar port Fl db Ar db Fl user Ar user Fl password Ar pass
Sets Postgres credentials for the account.
The credentials are encrypted with AES-256-GCM using the server master key.
.It Nm Ic pgcreds Ic get Fl id Ar uuid
Retrieves and prints the Postgres credentials.
The password is included in plaintext; treat the output as sensitive.
.El
.Sh ENVIRONMENT
.Bl -tag -width Ds
.It Ev MCIAS_TOKEN
Bearer token used for authentication when
.Fl token
is not specified.
.It Ev MCIAS_SERVER
Base URL of the mciassrv instance when
.Fl server
is not specified.
.El
.Sh EXAMPLES
List all accounts:
.Bd -literal -offset indent
mciasctl -server https://auth.example.com -token $ADMIN_TOKEN account list
.Ed
.Pp
Create a human account:
.Bd -literal -offset indent
mciasctl account create -username alice -password s3cr3t
.Ed
.Pp
Grant the admin role:
.Bd -literal -offset indent
mciasctl role set -id $UUID -roles admin
.Ed
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr mciassrv 1 ,
.Xr mciasdb 1 ,
.Xr mciasgrpcctl 1

203
man/man1/mciasdb.1 Normal file
View File

@@ -0,0 +1,203 @@
.Dd March 11, 2026
.Dt MCIASDB 1
.Os
.Sh NAME
.Nm mciasdb
.Nd MCIAS database maintenance tool
.Sh SYNOPSIS
.Nm
.Op Fl config Ar path
.Ar command
.Op Ar subcommand
.Op Ar flags
.Sh DESCRIPTION
.Nm
is the MCIAS database maintenance tool.
It operates
.Em directly
on the SQLite database file, bypassing the mciassrv REST API.
.Pp
Use
.Nm
for:
.Bl -bullet -compact
.It
Break-glass recovery when the server is unavailable.
.It
Offline account and role management before first server start.
.It
Schema verification and migration.
.It
Token pruning and audit log inspection.
.El
.Pp
.Nm
requires the same master key configuration as
.Xr mciassrv 1
to decrypt secrets at rest.
.Sh TRUST MODEL AND SAFETY WARNINGS
.Nm
has
.Em direct write access
to the database and can modify any record without going through the server's
validation logic.
Use it only when necessary.
.Bl -bullet
.It
Run
.Nm
on the same host as the database file.
Never copy the database to an untrusted host.
.It
The master key passphrase (or keyfile) must be available.
Set the environment variable named by
.Sy passphrase_env
in the config, or ensure the keyfile is accessible.
.It
All write operations append an audit log entry tagged
.Qq actor:mciasdb .
.It
Avoid running
.Nm
while mciassrv is under heavy write load; SQLite WAL mode provides some
isolation, but schema migrations acquire an exclusive lock.
.El
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl config Ar path
Path to the TOML configuration file.
Defaults to
.Pa mcias.toml
in the current directory.
.El
.Sh COMMANDS
.Ss schema
.Bl -tag -width Ds
.It Nm Ic schema Ic verify
Reports the current schema version.
Exits 0 if the schema is up to date; exits 1 if migrations are pending.
.It Nm Ic schema Ic migrate
Applies any pending migrations and reports each one applied.
Exits 0 on success.
.El
.Ss account
.Bl -tag -width Ds
.It Nm Ic account Ic list
Prints UUID, username, type, and status for all accounts.
.It Nm Ic account Ic get Fl -id Ar uuid
Prints the account record for the given UUID.
.It Nm Ic account Ic create Fl -username Ar name Fl -type Ar human|system
Inserts a new account row and prints the new UUID.
.It Nm Ic account Ic set-password Fl -id Ar uuid
Prompts for a new password twice (confirmation).
Re-hashes with Argon2id and updates the row.
No
.Fl -password
flag is provided; the password is always read interactively.
.It Nm Ic account Ic set-status Fl -id Ar uuid Fl -status Ar STATUS
Updates the account status.
Valid statuses:
.Qq active ,
.Qq inactive ,
.Qq deleted .
.It Nm Ic account Ic reset-totp Fl -id Ar uuid
Clears the TOTP secret and disables TOTP for the account.
The user will be able to log in with password only until they re-enrol.
.El
.Ss role
.Bl -tag -width Ds
.It Nm Ic role Ic list Fl -id Ar uuid
Prints the roles assigned to the account.
.It Nm Ic role Ic grant Fl -id Ar uuid Fl -role Ar role
Adds a role to the account.
.It Nm Ic role Ic revoke Fl -id Ar uuid Fl -role Ar role
Removes a role from the account.
.El
.Ss token
.Bl -tag -width Ds
.It Nm Ic token Ic list Fl -id Ar uuid
Prints JTI, issued_at, expires_at, and revoked_at for all tokens associated
with the account.
.It Nm Ic token Ic revoke Fl -jti Ar jti
Sets revoked_at to the current time on the specified token row.
.It Nm Ic token Ic revoke-all Fl -id Ar uuid
Revokes all non-revoked tokens for the account.
A no-op (exits 0) if no active tokens exist.
.El
.Ss prune
.Bl -tag -width Ds
.It Nm Ic prune Ic tokens
Deletes rows from the token_revocation table where expires_at is in the past.
Prints the number of rows removed.
.El
.Ss audit
.Bl -tag -width Ds
.It Nm Ic audit Ic tail Op Fl -n Ar N
Prints the last N audit events, newest last.
Default: 50.
.It Nm Ic audit Ic query Op Fl -account Ar uuid Op Fl -type Ar event_type Op Fl -since Ar timestamp Op Fl -json
Queries the audit log.
Filters are combinable (AND semantics).
.Fl -since
accepts an RFC 3339 timestamp.
.Fl -json
emits newline-delimited JSON instead of tabular output.
.El
.Ss pgcreds
.Bl -tag -width Ds
.It Nm Ic pgcreds Ic get Fl -id Ar uuid
Decrypts and prints the Postgres credentials for the account.
A warning header is printed before the output because the password is
displayed in plaintext.
.It Nm Ic pgcreds Ic set Fl -id Ar uuid Fl -host Ar host Fl -port Ar port Fl -db Ar db Fl -user Ar user
Prompts for the Postgres password interactively (no
.Fl -password
flag).
Encrypts with AES-256-GCM using the master key and stores the record.
.El
.Sh EXAMPLES
Verify schema after upgrade:
.Bd -literal -offset indent
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /etc/mcias/mcias.conf schema verify
.Ed
.Pp
Create an admin account before first server start:
.Bd -literal -offset indent
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /etc/mcias/mcias.conf \\
account create --username admin --type human
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /etc/mcias/mcias.conf \\
account set-password --id <UUID>
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /etc/mcias/mcias.conf \\
role grant --id <UUID> --role admin
.Ed
.Pp
Tail the last 20 audit events:
.Bd -literal -offset indent
MCIAS_MASTER_PASSPHRASE=... mciasdb --config /etc/mcias/mcias.conf \\
audit tail --n 20
.Ed
.Sh ENVIRONMENT
The environment variable named by
.Sy passphrase_env
in the configuration file must be set to the master key passphrase, unless
.Sy keyfile
is used instead.
.Pp
Example (with default config):
.Bd -literal -offset indent
export MCIAS_MASTER_PASSPHRASE=your-passphrase
mciasdb --config /etc/mcias/mcias.conf account list
.Ed
.Sh EXIT STATUS
.Ex -std
.Sh FILES
.Bl -tag -width Ds
.It Pa /etc/mcias/mcias.conf
Default configuration file location.
.It Pa /var/lib/mcias/mcias.db
SQLite database.
.El
.Sh SEE ALSO
.Xr mciassrv 1 ,
.Xr mciasctl 1 ,
.Xr mciasgrpcctl 1

122
man/man1/mciasgrpcctl.1 Normal file
View File

@@ -0,0 +1,122 @@
.Dd March 11, 2026
.Dt MCIASGRPCCTL 1
.Os
.Sh NAME
.Nm mciasgrpcctl
.Nd MCIAS gRPC admin CLI
.Sh SYNOPSIS
.Nm
.Op Fl server Ar addr
.Op Fl token Ar jwt
.Op Fl cacert Ar path
.Ar command
.Op Ar subcommand
.Op Ar flags
.Sh DESCRIPTION
.Nm
is the gRPC companion to
.Xr mciasctl 1 .
It connects to the gRPC/TLS listener of a running
.Xr mciassrv 1
instance and provides subcommands mirroring the REST admin CLI.
.Pp
The gRPC listener must be enabled in the mciassrv configuration
.Pq Sy grpc_addr
for
.Nm
to connect.
.Pp
Authentication is performed using a bearer JWT passed as gRPC metadata.
The token must have the
.Qq admin
role for most operations.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl server Ar addr
gRPC server address in
.Ar host:port
format.
Default:
.Qq localhost:9443 .
.It Fl token Ar jwt
Bearer token for authentication.
Can also be set with the
.Ev MCIAS_TOKEN
environment variable.
.It Fl cacert Ar path
Path to a CA certificate in PEM format for TLS verification.
Useful when mciassrv uses a self-signed certificate.
.El
.Sh COMMANDS
.Ss Informational (no authentication required)
.Bl -tag -width Ds
.It Nm Ic health
Calls the Health RPC.
Prints
.Qq ok
and exits 0 if the server is healthy.
.It Nm Ic pubkey
Returns the server's Ed25519 public key as a JWK.
.El
.Ss account
.Bl -tag -width Ds
.It Nm Ic account Ic list
Lists all accounts.
.It Nm Ic account Ic create Fl username Ar name Fl password Ar pass Op Fl type Ar human|system
Creates a new account.
.It Nm Ic account Ic get Fl id Ar uuid
Returns the account with the given UUID.
.It Nm Ic account Ic update Fl id Ar uuid Fl status Ar active|inactive
Updates account status.
.It Nm Ic account Ic delete Fl id Ar uuid
Soft-deletes the account and revokes all its tokens.
.El
.Ss role
.Bl -tag -width Ds
.It Nm Ic role Ic list Fl id Ar uuid
Lists roles for the account.
.It Nm Ic role Ic set Fl id Ar uuid Fl roles Ar role1,role2,...
Replaces the role set for the account.
.El
.Ss token
.Bl -tag -width Ds
.It Nm Ic token Ic validate Fl token Ar jwt
Validates the given token and prints its claims.
.It Nm Ic token Ic issue Fl id Ar uuid
Issues a new service token for a system account.
.It Nm Ic token Ic revoke Fl jti Ar jti
Revokes the token with the given JTI.
.El
.Ss pgcreds
.Bl -tag -width Ds
.It Nm Ic pgcreds Ic get Fl id Ar uuid
Returns the Postgres credentials for the account.
.It Nm Ic pgcreds Ic set Fl id Ar uuid Fl host Ar host Op Fl port Ar port Fl db Ar db Fl user Ar user Fl password Ar pass
Sets Postgres credentials for the account.
.El
.Sh ENVIRONMENT
.Bl -tag -width Ds
.It Ev MCIAS_TOKEN
Bearer token used for authentication when
.Fl token
is not specified.
.El
.Sh EXAMPLES
Check server health over gRPC:
.Bd -literal -offset indent
mciasgrpcctl -server auth.example.com:9443 -cacert /etc/mcias/ca.crt health
.Ed
.Pp
Using grpcurl as an alternative client:
.Bd -literal -offset indent
grpcurl -cacert /etc/mcias/ca.crt \\
-H "authorization: Bearer $TOKEN" \\
auth.example.com:9443 \\
mcias.v1.AdminService/Health
.Ed
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr mciassrv 1 ,
.Xr mciasctl 1 ,
.Xr mciasdb 1

228
man/man1/mciassrv.1 Normal file
View File

@@ -0,0 +1,228 @@
.Dd March 11, 2026
.Dt MCIASSRV 1
.Os
.Sh NAME
.Nm mciassrv
.Nd MCIAS authentication server
.Sh SYNOPSIS
.Nm
.Fl config
.Ar path
.Sh DESCRIPTION
.Nm
is the MCIAS (Metacircular Identity and Access System) authentication server.
It provides a single-sign-on (SSO) and identity and access management (IAM)
service for personal applications.
.Pp
.Nm
reads a TOML configuration file, derives the AES-256 master encryption key,
loads or generates an Ed25519 signing key, opens the SQLite database, applies
any pending schema migrations, and starts an HTTPS listener.
.Pp
If the
.Sy grpc_addr
field is set in the configuration file, a gRPC/TLS listener is also started
on the specified address.
Both listeners share the same signing key, database connection, and
configuration.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl config Ar path
Path to the TOML configuration file.
Defaults to
.Pa mcias.toml
in the current directory.
.El
.Sh CONFIGURATION
The configuration file is in TOML format.
See
.Pa /etc/mcias/mcias.conf
(or
.Pa dist/mcias.conf.example
in the source tree) for a fully-commented reference configuration.
.Pp
The following sections are recognised:
.Bl -tag -width Ds
.It Sy [server]
.Bl -tag -width Ds
.It Sy listen_addr
.Pq required
Host and port for the HTTPS REST listener.
Example:
.Qq 0.0.0.0:8443 .
.It Sy grpc_addr
.Pq optional
Host and port for the gRPC/TLS listener.
If omitted, gRPC is disabled.
Example:
.Qq 0.0.0.0:9443 .
.It Sy tls_cert
.Pq required
Path to the TLS certificate file in PEM format.
.It Sy tls_key
.Pq required
Path to the TLS private key file in PEM format.
.El
.It Sy [database]
.Bl -tag -width Ds
.It Sy path
.Pq required
Path to the SQLite database file.
WAL mode and foreign key enforcement are enabled automatically.
.El
.It Sy [tokens]
.Bl -tag -width Ds
.It Sy issuer
.Pq required
Issuer claim embedded in every JWT.
Use the base URL of your MCIAS server.
.It Sy default_expiry
.Pq optional, default 720h
Token expiry for interactive logins.
Go duration string.
.It Sy admin_expiry
.Pq optional, default 8h
Token expiry for tokens with the
.Qq admin
role.
.It Sy service_expiry
.Pq optional, default 8760h
Token expiry for system account tokens.
.El
.It Sy [argon2]
.Bl -tag -width Ds
.It Sy time
.Pq optional, default 3
Argon2id time cost.
Must be >= 2 (OWASP 2023 minimum).
.It Sy memory
.Pq optional, default 65536
Argon2id memory cost in KiB.
Must be >= 65536 (64 MB, OWASP 2023 minimum).
.It Sy threads
.Pq optional, default 4
Argon2id parallelism.
.El
.It Sy [master_key]
Exactly one of the following must be set:
.Bl -tag -width Ds
.It Sy passphrase_env
Name of the environment variable containing the master key passphrase.
The passphrase is read at startup and the environment variable is immediately
cleared.
.It Sy keyfile
Path to a file containing exactly 32 bytes of raw AES-256 key material.
.El
.El
.Sh REST API
.Nm
exposes the following REST endpoints over HTTPS:
.Bl -tag -width Ds
.It GET /v1/health
Returns
.Qq {"status":"ok"}
with HTTP 200.
No authentication required.
.It GET /v1/keys/public
Returns the Ed25519 public key as a JWK.
No authentication required.
.It POST /v1/auth/login
Authenticates a user and issues a JWT.
Body: JSON with
.Sy username ,
.Sy password ,
and optionally
.Sy totp_code .
Returns
.Sy token
and
.Sy expires_at .
.It POST /v1/auth/logout
Revokes the current JWT.
Requires a valid Bearer token.
Returns HTTP 204.
.It POST /v1/auth/renew
Renews the current JWT, revoking the old one.
Requires a valid Bearer token.
Returns
.Sy token
and
.Sy expires_at .
.It POST /v1/token/validate
Validates a submitted token and returns its claims.
.It DELETE /v1/token/{jti}
Revokes a token by JTI.
Requires admin role.
.It POST /v1/accounts
Creates a new account.
Requires admin role.
.It GET /v1/accounts
Lists all accounts (no credential fields in response).
Requires admin role.
.It GET /v1/accounts/{id}
Returns a single account.
Requires admin role.
.It PATCH /v1/accounts/{id}
Updates an account.
Requires admin role.
.It DELETE /v1/accounts/{id}
Soft-deletes an account and revokes all its tokens.
Requires admin role.
.It GET /v1/accounts/{id}/roles
Returns the role set for an account.
Requires admin role.
.It PUT /v1/accounts/{id}/roles
Replaces the role set for an account.
Requires admin role.
.It POST /v1/auth/totp/enroll
Generates a TOTP secret and returns the otpauth URI.
Requires authentication.
.It POST /v1/auth/totp/confirm
Confirms TOTP enrollment.
Requires authentication.
.It DELETE /v1/auth/totp
Removes TOTP from an account.
Requires admin role.
.It GET /v1/accounts/{id}/pgcreds
Returns the Postgres credentials for an account (decrypted).
Requires admin role.
.It PUT /v1/accounts/{id}/pgcreds
Sets Postgres credentials for an account.
Requires admin role.
.El
.Sh SIGNALS
.Bl -tag -width Ds
.It Dv SIGINT , SIGTERM
Initiate graceful shutdown.
In-flight requests are drained for up to 15 seconds before the server exits.
.El
.Sh EXIT STATUS
.Ex -std
.Sh FILES
.Bl -tag -width Ds
.It Pa /etc/mcias/mcias.conf
Default configuration file location.
.It Pa /etc/mcias/server.crt
TLS certificate (operator-supplied).
.It Pa /etc/mcias/server.key
TLS private key (operator-supplied).
.It Pa /var/lib/mcias/mcias.db
SQLite database.
.It Pa /etc/systemd/system/mcias.service
systemd service unit.
.El
.Sh SEE ALSO
.Xr mciasctl 1 ,
.Xr mciasdb 1 ,
.Xr mciasgrpcctl 1
.Sh SECURITY
.Nm
enforces TLS 1.2 as the minimum protocol version.
All JWTs are signed with Ed25519; the
.Sy alg
header is validated before any other processing to defeat algorithm confusion
attacks.
Password hashing uses Argon2id with parameters meeting or exceeding the
OWASP 2023 recommendations.
Credential fields (password hashes, TOTP secrets, Postgres passwords) are
never included in any API response.