@coffre/cli 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/access-CO1kGjWW.js +74 -0
- package/dist/connect-BONR52al.js +770 -0
- package/dist/connect-BZdPYNbZ.js +2 -0
- package/dist/esm-B69mMLcR.js +2 -0
- package/dist/esm-Bts-esAl.js +4202 -0
- package/dist/keys-D9CG_wYV.js +64 -0
- package/dist/main.js +12 -73
- package/dist/migrations/postgres/0000_baseline.sql +505 -0
- package/dist/migrations/postgres/meta/0000_snapshot.json +1939 -0
- package/dist/migrations/postgres/meta/_journal.json +13 -0
- package/dist/migrator-W1a-ooWi.js +37 -0
- package/dist/node-postgres-BlNvYfq_.js +2 -0
- package/dist/node-postgres-_y-EeSHQ.js +2831 -0
- package/dist/portable-CPh2thNN.js +87 -0
- package/dist/relations-CJCGPRst.js +2712 -0
- package/dist/schema-sqlite-Byp7B3yI.js +1078 -0
- package/dist/setup-DPHVyr2N.js +521 -0
- package/dist/templates/node/README.md +38 -33
- package/dist/templates/node/package.json +3 -3
- package/dist/templates/node/server.env.example +4 -3
- package/dist/templates/node/src/server.ts +1 -1
- package/dist/templates/node/src/vault.ts +5 -3
- package/dist/templates/node/vault.env.example +4 -5
- package/dist/templates/workers/README.md +40 -42
- package/dist/templates/workers/app/wrangler.jsonc +1 -0
- package/dist/templates/workers/package.json +4 -4
- package/dist/templates/workers/vault/src/worker.ts +5 -4
- package/dist/templates/workers/vault/wrangler.jsonc +4 -3
- package/package.json +7 -4
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
# the vault's user alone.
|
|
3
3
|
|
|
4
4
|
VAULT_SOCKET=vault.sock
|
|
5
|
-
#
|
|
5
|
+
# From `coffre setup`: the server's database, as the vault's own login.
|
|
6
6
|
DATABASE_URL=postgres://coffre_vault_runtime:CHANGE_ME@127.0.0.1:5432/coffre
|
|
7
7
|
|
|
8
|
-
#
|
|
9
|
-
# and
|
|
8
|
+
# From `coffre setup`, saved in your password manager first: the
|
|
9
|
+
# key-encryption key, and its name. A rotation gives the new one a new name.
|
|
10
|
+
# The vault derives the key it signs its records with from it.
|
|
10
11
|
KEK_ID=kek-1
|
|
11
12
|
KEK=
|
|
12
|
-
# 32 random bytes, base64: signs the audit checkpoints.
|
|
13
|
-
SIGNING_KEY=
|
|
14
13
|
|
|
15
14
|
# Comma-separated emails: the first people in, whom nobody can remove.
|
|
16
15
|
ROOT_ADMINS=you@example.com
|
|
@@ -17,63 +17,61 @@ Worker secrets. Everything below runs from this directory.
|
|
|
17
17
|
- `app/wrangler.jsonc`: `PUBLIC_URL`, and `GITHUB_CLIENT_ID` from a GitHub
|
|
18
18
|
OAuth app whose callback is `<PUBLIC_URL>/auth/callback/github`.
|
|
19
19
|
- `vault/wrangler.jsonc`: `ROOT_ADMINS`, the emails of the first people in,
|
|
20
|
-
and `KEK_ID`,
|
|
20
|
+
and `KEK_ID`, which `coffre setup` gives you below.
|
|
21
21
|
|
|
22
|
-
## 2. The database
|
|
22
|
+
## 2. The database and keys
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
migrations; `coffre_runtime`, which the app runs as; and
|
|
26
|
-
`coffre_vault_runtime`, which the vault runs as. Create the two as plain
|
|
27
|
-
logins. As the database's administrator, connect with `psql` and run:
|
|
28
|
-
|
|
29
|
-
```sql
|
|
30
|
-
CREATE ROLE coffre_runtime LOGIN INHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS;
|
|
31
|
-
CREATE ROLE coffre_vault_runtime LOGIN INHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS;
|
|
32
|
-
\password coffre_runtime
|
|
33
|
-
\password coffre_vault_runtime
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Each `\password` prompts for a different generated password. The owner
|
|
37
|
-
must be able to create and grant roles: the migration creates `coffre_app`
|
|
38
|
-
and `coffre_vault`, and grants each login its own group. Only the vault may
|
|
39
|
-
write members and grants, and each appends to the log only as itself.
|
|
40
|
-
URL-encode special characters in the passwords in these URLs:
|
|
24
|
+
Make a Postgres database, then, from this directory:
|
|
41
25
|
|
|
42
26
|
```sh
|
|
43
|
-
|
|
44
|
-
pnpm migrate "postgres://owner:…@db.example.com:5432/coffre"
|
|
45
|
-
pnpm exec wrangler hyperdrive create coffre --caching-disabled \
|
|
46
|
-
--connection-string="postgres://coffre_runtime:…@db.example.com:5432/coffre"
|
|
47
|
-
pnpm exec wrangler hyperdrive create coffre-vault --caching-disabled \
|
|
48
|
-
--connection-string="postgres://coffre_vault_runtime:…@db.example.com:5432/coffre"
|
|
27
|
+
npx @coffre/cli setup
|
|
49
28
|
```
|
|
50
29
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
30
|
+
Run it with the CLI you ran `coffre init` with. It asks for the database
|
|
31
|
+
administrator's connection string at a hidden prompt (a script can pipe it
|
|
32
|
+
in, or set `COFFRE_SETUP_DATABASE_URL`; never pass it as an argument). It
|
|
33
|
+
makes the two logins coffre runs as, `coffre_runtime` for the app and
|
|
34
|
+
`coffre_vault_runtime` for the vault, migrates the database, checks that
|
|
35
|
+
each login holds only its rights, and prints every value at once: the two
|
|
36
|
+
keys, the KEK's id, and each login's connection string. It keeps no copy and
|
|
37
|
+
writes no file. Save its output in your password manager, with the GitHub
|
|
38
|
+
client secret, before anything else. There is one key for each Worker, so
|
|
39
|
+
that the app, which faces the network, never holds what decrypts a value:
|
|
40
|
+
|
|
41
|
+
- `KEK`, the vault's, decrypts every value, and the vault derives from it the
|
|
42
|
+
key it signs its records with. Lose it, and every value is lost.
|
|
43
|
+
- `AUDIT_CHAIN_KEY`, the app's, signs the app's log entries, sessions and
|
|
44
|
+
tokens. Lose it, and everyone is signed out and the log stops verifying.
|
|
45
|
+
|
|
46
|
+
To do the same by hand, see
|
|
47
|
+
[deploy.md](https://github.com/erwinkn/coffre/blob/main/docs/deploy.md#appendix-the-database-by-hand).
|
|
48
|
+
|
|
49
|
+
## 3. Hyperdrive and secrets
|
|
50
|
+
|
|
51
|
+
Run the two `wrangler hyperdrive create` commands setup printed: one config
|
|
52
|
+
per login, each `--caching-disabled`. Hyperdrive otherwise caches reads for
|
|
53
|
+
up to a minute, and a revoked token or a signed-out session could keep
|
|
54
|
+
working that long. `wrangler.jsonc` cannot set it, so for a config made
|
|
55
|
+
another way, check `caching` in `wrangler hyperdrive get <id>`.
|
|
55
56
|
|
|
56
57
|
Put the ids they print under `hyperdrive`, the first in
|
|
57
|
-
`app/wrangler.jsonc` and the second in `vault/wrangler.jsonc
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
## 3. Secrets
|
|
62
|
-
|
|
63
|
-
Generate three separate keys with `openssl rand -base64 32` and save them
|
|
64
|
-
in your password manager first. The commands below prompt for the saved
|
|
65
|
-
values; save the GitHub client secret there too.
|
|
58
|
+
`app/wrangler.jsonc` and the second in `vault/wrangler.jsonc`, and `KEK_ID`
|
|
59
|
+
in `vault/wrangler.jsonc`. Then set the secrets; each command prompts for
|
|
60
|
+
the saved value:
|
|
66
61
|
|
|
67
62
|
```sh
|
|
68
63
|
pnpm exec wrangler secret put KEK -c vault/wrangler.jsonc
|
|
69
|
-
pnpm exec wrangler secret put SIGNING_KEY -c vault/wrangler.jsonc
|
|
70
64
|
pnpm exec wrangler secret put AUDIT_CHAIN_KEY -c app/wrangler.jsonc
|
|
71
65
|
pnpm exec wrangler secret put GITHUB_CLIENT_SECRET -c app/wrangler.jsonc
|
|
72
66
|
```
|
|
73
67
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
Run `pnpm migrate`, with the administrator's URL in `DATABASE_URL`, after
|
|
69
|
+
every upgrade of `@coffre/server`, before deploying it.
|
|
70
|
+
|
|
71
|
+
Keep older KEKs after a rotation, for good: what they wrapped still needs
|
|
72
|
+
them, and so does what the vault signed under them before it. With AWS KMS
|
|
73
|
+
instead of a key of your own, the vault also needs a `SIGNING_KEY`
|
|
74
|
+
([keys](https://github.com/erwinkn/coffre/blob/main/docs/keys.md#aws-kms)).
|
|
77
75
|
|
|
78
76
|
## 4. Deploy
|
|
79
77
|
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"GITHUB_CLIENT_ID": "replace-with-your-client-id"
|
|
18
18
|
},
|
|
19
19
|
"secrets": {
|
|
20
|
+
// AUDIT_CHAIN_KEY is from `coffre setup`; the app never gets the vault's keys.
|
|
20
21
|
"required": ["GITHUB_CLIENT_SECRET", "AUDIT_CHAIN_KEY"]
|
|
21
22
|
},
|
|
22
23
|
// `wrangler hyperdrive create coffre --caching-disabled --connection-string=<runtime login URL>`
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
"conformance": "coffre-conformance workers"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@coffre/server": "0.1.
|
|
18
|
-
"@coffre/ui": "0.1.
|
|
19
|
-
"@coffre/vault": "0.1.
|
|
17
|
+
"@coffre/server": "0.1.2",
|
|
18
|
+
"@coffre/ui": "0.1.2",
|
|
19
|
+
"@coffre/vault": "0.1.2"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@cloudflare/workers-types": "5.20260920.1",
|
|
23
|
-
"@coffre/conformance": "0.1.
|
|
23
|
+
"@coffre/conformance": "0.1.2",
|
|
24
24
|
"typescript": "5.9.3",
|
|
25
25
|
"wrangler": "4.118.0"
|
|
26
26
|
}
|
|
@@ -7,15 +7,16 @@ type Env = {
|
|
|
7
7
|
VAULT_HYPERDRIVE: Hyperdrive;
|
|
8
8
|
KEK_ID: string;
|
|
9
9
|
KEK: string;
|
|
10
|
-
SIGNING_KEY: string;
|
|
11
10
|
ROOT_ADMINS: string;
|
|
12
11
|
};
|
|
13
12
|
|
|
14
13
|
export default vault((env: Env) => ({
|
|
15
14
|
database: postgres(env.VAULT_HYPERDRIVE),
|
|
16
15
|
kek: { id: env.KEK_ID, key: env.KEK },
|
|
17
|
-
// After a rotation, the KEKs before it, so the data keys they wrapped
|
|
18
|
-
//
|
|
16
|
+
// After a rotation, the KEKs before it, so the data keys they wrapped still
|
|
17
|
+
// open and the records signed under them before it still verify:
|
|
18
|
+
// previousKeks: [{ id: 'kek-2026-09', key: env.KEK_2026_09 }],
|
|
19
19
|
rootAdmins: env.ROOT_ADMINS.split(',').map((email) => email.trim()),
|
|
20
|
-
|
|
20
|
+
// The vault derives its signing key from the KEK. With a KEK a key service
|
|
21
|
+
// holds, such as awsKms(…), it needs one of its own: signingKey: env.SIGNING_KEY.
|
|
21
22
|
}));
|
|
@@ -11,14 +11,15 @@
|
|
|
11
11
|
"workers_dev": false,
|
|
12
12
|
"observability": { "enabled": true },
|
|
13
13
|
"vars": {
|
|
14
|
-
// Names the KEK below
|
|
14
|
+
// Names the KEK below: from `coffre setup`. A rotation gives the new one a new id.
|
|
15
15
|
"KEK_ID": "kek-1",
|
|
16
16
|
// Comma-separated emails: the first people in, whom nobody can remove.
|
|
17
17
|
"ROOT_ADMINS": "you@example.com"
|
|
18
18
|
},
|
|
19
19
|
"secrets": {
|
|
20
|
-
//
|
|
21
|
-
|
|
20
|
+
// From `coffre setup`: wrangler secret put KEK. The vault derives the key
|
|
21
|
+
// it signs its records with from it.
|
|
22
|
+
"required": ["KEK"]
|
|
22
23
|
},
|
|
23
24
|
// The app's database, as the vault's own login: `wrangler hyperdrive
|
|
24
25
|
// create coffre-vault --caching-disabled --connection-string=<vault login
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffre/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "The coffre command line: secrets in your shell, and `coffre init` for a new deployment.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -23,13 +23,16 @@
|
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "26.1.1",
|
|
26
|
+
"@types/pg": "8.20.0",
|
|
27
|
+
"pg": "8.16.3",
|
|
26
28
|
"tsdown": "0.23.0",
|
|
27
29
|
"typescript": "5.9.3",
|
|
28
|
-
"@coffre/client": "0.1.
|
|
29
|
-
"@coffre/core": "0.1.
|
|
30
|
+
"@coffre/client": "0.1.2",
|
|
31
|
+
"@coffre/core": "0.1.2",
|
|
32
|
+
"@coffre/db": "0.1.2"
|
|
30
33
|
},
|
|
31
34
|
"scripts": {
|
|
32
|
-
"build": "tsdown && node scripts/copy-templates.ts",
|
|
35
|
+
"build": "tsdown && node scripts/copy-templates.ts && node scripts/copy-migrations.ts",
|
|
33
36
|
"typecheck": "tsc --noEmit",
|
|
34
37
|
"test": "node --conditions=coffre:source --test"
|
|
35
38
|
}
|