Why: the server is a single static binary with no dependencies, so its container should be nothing but that binary. Shipping one also makes the master key easy to lose, which needed handling rather than documenting. What: - Dockerfile: two stages, runtime is scratch plus the binary and a CA bundle for reaching an OIDC provider, running as uid 65532. About 9 MB. The build stage copies only go.mod, cmd/keeporgd and internal, so client or docs changes do not invalidate it. - The image has no shell, so HEALTHCHECK runs `keeporgd -healthcheck`, a new flag that probes /healthz on the configured address and exits non-zero with a reason. podman needs --format docker to keep the healthcheck at all, which the Makefile passes when it picks podman. - New -master-key-file flag, so a mounted secret works without a config file. - The server now checks at startup whether the master key still opens the stored vault keys, and says so. Without it, a container restarted without its key discovers the problem one failed merge at a time. - make docker, docker-run and docker-save; a compose example with read_only, cap_drop ALL and no-new-privileges. - The client and the server now version independently, so their Debian changelogs are split per package and `make changelog` takes PKG=. Server 0.3.0; the clients stay at 0.2.0. Proved: built with podman and run. The container serves /healthz and /web, its own healthcheck reports healthy, and a vault created through it was edited from the same base by keepassxc-cli twice, merged by the server into version 3, and read back with both entries intact. Restarted without the master key it warns "1 of 1 stored vault keys do not open with this master key" and answers a merging push with 409 merge_failed, leaving the vault untouched; restored, it logs "1 vault keys available for merging" and merges again. The same key supplied through -master-key-file from a mounted file works identically. Both .deb packages build with their own changelog, and make check is clean.
83 lines
3.3 KiB
Markdown
83 lines
3.3 KiB
Markdown
# KeepOrg
|
|
|
|
A synchronization adapter for KeePass. Your databases stay ordinary `.kdbx`
|
|
files that KeePassXC, KeePass2 or KeePassDX opens directly; a server keeps
|
|
them in step between everyone who has access.
|
|
|
|
When two people save at once, the server can **merge** both edits: it opens
|
|
the two copies in memory, folds them together by KeePass's own rules and
|
|
stores the result. Nothing is lost, and no one has to reconcile two files by
|
|
hand.
|
|
|
|
Merging means decrypting, so a merge vault's password is kept on the server,
|
|
encrypted under a master key held outside the data directory. That makes the
|
|
server part of your trust boundary. Vaults on any other conflict strategy
|
|
keep their key off the server entirely, exactly as before.
|
|
|
|
- **Server** (`keeporgd`, Linux): hosts many KDBX databases, controls access
|
|
with a tree of user groups, accepts registrations by invite link or OIDC,
|
|
merges concurrent edits, and pushes updates to connected clients. Its web
|
|
page at `/web` is for creating a vault and setting its password.
|
|
- **Desktop client** (`keeporg`, Linux, macOS, Windows, BSD): mirrors every
|
|
assigned database into one directory as a real file, pushes each save and
|
|
applies what others push.
|
|
- **Android client**: the same, published to every file picker as a storage
|
|
provider.
|
|
|
|
No third-party dependencies, no cgo, no FUSE. The KDBX 4 codec, including
|
|
ChaCha20, BLAKE2b and Argon2, is part of the repository and is tested against
|
|
both the relevant RFCs and a real KeePassXC.
|
|
|
|
## Quick start
|
|
|
|
```sh
|
|
make check # gofmt, vet, tests
|
|
make all # keeporgd and keeporg for this host
|
|
|
|
# a server for trying it out, on 127.0.0.1:8765
|
|
KEEPORG_ADMIN_PASSWORD=dev-password-1 make run-server
|
|
|
|
# in another shell
|
|
build/linux-arm64/keeporg login -server http://127.0.0.1:8765 -user admin
|
|
build/linux-arm64/keeporg groups
|
|
build/linux-arm64/keeporg vault -create "Team Vault" -group <group-id>
|
|
build/linux-arm64/keeporg run
|
|
```
|
|
|
|
`Team Vault.kdbx` appears in `~/KeepOrg`; open it in KeePassXC with the vault
|
|
password you just set. Every save is pushed, and a save that races with a
|
|
colleague's is merged rather than refused.
|
|
|
|
Or open `http://127.0.0.1:8765/web` and create the vault from the browser.
|
|
|
|
## Packaging
|
|
|
|
```sh
|
|
make deb # Debian packages for the client and the server
|
|
make docker # server container image, scratch-based, about 9 MB
|
|
make dmg # macOS disk image with an /Applications symlink (on macOS)
|
|
make windows # Windows zip with a Task Scheduler job
|
|
make android # unsigned release APK (needs the Android SDK)
|
|
make help # every target
|
|
```
|
|
|
|
Running the server in a container:
|
|
|
|
```bash
|
|
podman run -d -p 8765:8765 \
|
|
-e KEEPORG_MASTER_KEY="$(head -c 32 /dev/urandom | base64)" \
|
|
-e KEEPORG_ADMIN_PASSWORD=change-me \
|
|
-v keeporg-data:/var/lib/keeporg \
|
|
keeporgd:latest -addr :8765 -data /var/lib/keeporg -url https://keeporg.example.com
|
|
```
|
|
|
|
Keep that master key: it unwraps the vault keys, and without it the server
|
|
can no longer merge. See [packaging/docker/compose.yaml](packaging/docker/compose.yaml).
|
|
|
|
## Documentation
|
|
|
|
- [docs/HANDOVER.md](docs/HANDOVER.md) — architecture, the decisions behind
|
|
it, operations, and what is left to do.
|
|
- [docs/PROTOCOL.md](docs/PROTOCOL.md) — the HTTP API.
|
|
- [android/README.md](android/README.md) — the Android module.
|