From c819f559680a68d73ea91ad7cfa6ff4d195bd68c Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Sat, 21 Mar 2026 18:02:51 -0500 Subject: [PATCH] Initial commit --- README.md | 53 +++++++++++++++++++++++++++++++++++++ todo.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 README.md create mode 100644 todo.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c1a7dfd --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# arcline-vault + +Self-hosted encrypted secrets store. AES-256-GCM encrypted key-value pairs organized by environment, exposed via a REST API and CLI. No HashiCorp Vault complexity, no SaaS subscription. + +Solves the `.env` file problem for small teams without sending secrets to a third party. + +## Status + +Planned. Not yet started. + +## Stack + +- Go — REST API server + CLI client in one binary +- SQLite for storage (encrypted at rest) +- AES-256-GCM with envelope encryption (master key per server, data key per secret) +- Auth: API key (bearer token, stored as bcrypt hash) +- Transport: HTTPS only + +## Usage + +```sh +# Start the server +arcline-vault server --config vault.yaml + +# Manage secrets +arcline-vault set DATABASE_URL "postgres://..." --env production +arcline-vault get DATABASE_URL --env production +arcline-vault list --env production +arcline-vault delete DATABASE_URL --env production +arcline-vault export --env production > .env +arcline-vault import .env --env production +``` + +## Security model + +- Master key loaded from environment variable only — never written to disk +- Each secret encrypted with its own data key, wrapped by the master key +- API keys stored as bcrypt hashes; plaintext never stored after creation +- Full audit log: timestamp, API key prefix, action, secret name +- Read-only API keys supported + +## Config + +```yaml +listen: "0.0.0.0:8200" +tls: + cert: /etc/ssl/arcline-vault/cert.pem + key: /etc/ssl/arcline-vault/key.pem +database: /var/lib/arcline-vault/vault.db +master_key_env: VAULT_MASTER_KEY # 32-byte hex +``` + +See [todo.md](todo.md) for the full task list, API reference, and threat model notes. diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..0374a93 --- /dev/null +++ b/todo.md @@ -0,0 +1,78 @@ +# arcline-vault — Self-Hosted Encrypted Secrets Store + +AES-256-GCM encrypted key-value store for small teams. REST API + CLI. +Solves "where do I put my .env files" without paying for HashiCorp Vault or Doppler. + +## Stack +- Language: Go +- Storage: SQLite (encrypted at rest) +- Encryption: AES-256-GCM (envelope encryption — master key → data key per secret) +- Auth: API key (bearer token, stored as bcrypt hash) +- Transport: HTTPS only (TLS cert via Let's Encrypt or provided cert) + +## Concepts +- **Secret** — a named key-value pair (name, value, description, tags) +- **Environment** — a namespace grouping secrets (e.g. `production`, `staging`) +- **API key** — bearer token granting access to one or more environments + +## REST API +``` +GET /v1/envs # list environments +POST /v1/envs # create environment + +GET /v1/envs/{env}/secrets # list secret names (values redacted) +POST /v1/envs/{env}/secrets # create/update secret +GET /v1/envs/{env}/secrets/{name} # get single secret value +DELETE /v1/envs/{env}/secrets/{name} # delete secret + +GET /v1/envs/{env}/export # export as .env format +GET /v1/envs/{env}/export?format=json +``` + +## CLI interface +``` +arcline-vault server --config vault.yaml # start the server + +arcline-vault set DATABASE_URL "postgres://..." --env production +arcline-vault get DATABASE_URL --env production +arcline-vault list --env production +arcline-vault delete DATABASE_URL --env production +arcline-vault export --env production > .env # dump to .env file +arcline-vault import .env --env production # load from .env file +``` + +## Config (vault.yaml) +```yaml +listen: "0.0.0.0:8200" +tls: + cert: /etc/ssl/arcline-vault/cert.pem + key: /etc/ssl/arcline-vault/key.pem +database: /var/lib/arcline-vault/vault.db +master_key_env: VAULT_MASTER_KEY # 32-byte hex, set via environment +``` + +## Security model +- Master key loaded from environment variable (never stored on disk) +- Each secret encrypted with its own data key (wrapped by master key) +- API keys stored as bcrypt hashes — server never sees plaintext key again +- All access logged (timestamp, API key prefix, action, secret name) +- Read-only API keys supported (read-only flag on key) + +## Tasks +- [ ] Project scaffold +- [ ] SQLite schema (environments, secrets, api_keys, audit_log) +- [ ] Encryption layer (AES-256-GCM, envelope encryption) +- [ ] Master key loading + validation on startup +- [ ] REST API server (net/http or chi router) +- [ ] API key middleware (bearer token → bcrypt verify) +- [ ] Environment CRUD handlers +- [ ] Secret CRUD handlers +- [ ] Export endpoint (.env + JSON formats) +- [ ] CLI client (reads VAULT_URL + VAULT_TOKEN env vars) +- [ ] .env import parser +- [ ] TLS setup (provided cert or ACME) +- [ ] Audit log +- [ ] Read-only API key support +- [ ] systemd unit file +- [ ] README: threat model, key rotation guide, nginx reverse proxy config +- [ ] Cross-compile Makefile