@andrewheberle/serverless-ssh-ca 0.19.1 → 0.20.1

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.
Files changed (47) hide show
  1. package/README.md +60 -3
  2. package/dist/db/index.d.ts.map +1 -1
  3. package/dist/db/index.js +3 -4
  4. package/dist/db/index.js.map +1 -1
  5. package/dist/db/migrate.d.ts +41 -0
  6. package/dist/db/migrate.d.ts.map +1 -0
  7. package/dist/db/migrate.js +84 -0
  8. package/dist/db/migrate.js.map +1 -0
  9. package/dist/db/migrations/0001_initial_schema.d.ts +1 -1
  10. package/dist/db/migrations/0001_initial_schema.d.ts.map +1 -1
  11. package/dist/db/migrations/0001_initial_schema.js +9 -10
  12. package/dist/db/migrations/0001_initial_schema.js.map +1 -1
  13. package/dist/db/migrations/index.d.ts +1 -1
  14. package/dist/db/migrations/index.d.ts.map +1 -1
  15. package/dist/index.d.ts +28 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +17 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/node/env.d.ts +72 -0
  20. package/dist/node/env.d.ts.map +1 -0
  21. package/dist/node/env.js +74 -0
  22. package/dist/node/env.js.map +1 -0
  23. package/dist/node/index.d.ts +23 -0
  24. package/dist/node/index.d.ts.map +1 -0
  25. package/dist/node/index.js +22 -0
  26. package/dist/node/index.js.map +1 -0
  27. package/dist/node/secret.d.ts +24 -0
  28. package/dist/node/secret.d.ts.map +1 -0
  29. package/dist/node/secret.js +28 -0
  30. package/dist/node/secret.js.map +1 -0
  31. package/dist/node/sqlite.d.ts +47 -0
  32. package/dist/node/sqlite.d.ts.map +1 -0
  33. package/dist/node/sqlite.js +273 -0
  34. package/dist/node/sqlite.js.map +1 -0
  35. package/dist/types.d.ts +47 -3
  36. package/dist/types.d.ts.map +1 -1
  37. package/package.json +6 -2
  38. package/src/db/index.ts +3 -4
  39. package/src/db/migrate.ts +107 -0
  40. package/src/db/migrations/0001_initial_schema.ts +10 -11
  41. package/src/db/migrations/index.ts +1 -1
  42. package/src/index.ts +37 -1
  43. package/src/node/env.ts +90 -0
  44. package/src/node/index.ts +22 -0
  45. package/src/node/secret.ts +30 -0
  46. package/src/node/sqlite.ts +315 -0
  47. package/src/types.ts +50 -3
package/README.md CHANGED
@@ -15,8 +15,9 @@ import app from "@andrewheberle/serverless-ssh-ca"
15
15
  export default app
16
16
  ```
17
17
 
18
- This package is built for Cloudflare Workers, and Workers is the only runtime
19
- it is tested on. There are no plans to support other runtimes at this time.
18
+ This package is built for Cloudflare Workers and can also run on Node.js 24
19
+ (see [Running on Node.js](#running-on-nodejs)). These are the only runtimes it
20
+ is tested on.
20
21
 
21
22
  The package doesn't use any Workers-specific APIs and doesn't depend on
22
23
  `@cloudflare/workers-types`. It needs:
@@ -30,6 +31,62 @@ Its exported types describe only these needs, so the `Env` generated by
30
31
  `wrangler types` (with `DB` as a `D1Database` and `PRIVATE_KEY` as a
31
32
  `SecretsStoreSecret`) can be passed directly as `SshCaBindings`.
32
33
 
34
+ ### Running on Node.js
35
+
36
+ Node.js 24 or later is required. Helpers for Node.js are imported from
37
+ `@andrewheberle/serverless-ssh-ca/node`:
38
+
39
+ | Helper | Purpose |
40
+ |---|---|
41
+ | `fromNodeSqlite(db)` | Uses a built-in `node:sqlite` database as the `DB` binding |
42
+ | `secretFromFile(path)` | Reads the CA private key from a file (re-read each time it is needed) |
43
+ | `secretFromString(value)` | Uses a string as the CA private key |
44
+ | `bindingsFromEnv({ DB, PRIVATE_KEY })` | Reads and validates the remaining configuration from `process.env` |
45
+
46
+ `createSshCa(bindings)` returns a `fetch(request)` handler that takes a
47
+ standard `Request` and returns a `Response`, and a `cleanup()` task that
48
+ replaces the Workers cron trigger.
49
+
50
+ The handler can be served by any server that works with `Request` and
51
+ `Response`. For example, with [`@hono/node-server`](https://www.npmjs.com/package/@hono/node-server)
52
+ (installed separately with `npm install @hono/node-server`):
53
+
54
+ ```ts
55
+ import { DatabaseSync } from "node:sqlite"
56
+ import { serve } from "@hono/node-server"
57
+ import { createSshCa } from "@andrewheberle/serverless-ssh-ca"
58
+ import { bindingsFromEnv, fromNodeSqlite, secretFromFile } from "@andrewheberle/serverless-ssh-ca/node"
59
+
60
+ const ca = createSshCa(bindingsFromEnv({
61
+ DB: fromNodeSqlite(new DatabaseSync("/var/lib/ssh-ca/ssh-ca.sqlite")),
62
+ PRIVATE_KEY: secretFromFile("/etc/ssh-ca/ca_key"),
63
+ }))
64
+
65
+ // remove expired certificates once a day
66
+ setInterval(() => void ca.cleanup(), 24 * 60 * 60 * 1000)
67
+
68
+ serve({ fetch: (req) => ca.fetch(req), port: 8787 })
69
+ ```
70
+
71
+ Notes:
72
+
73
+ - The configuration environment variables have the same names and formats
74
+ as the `vars` in the Workers [`wrangler.jsonc`](https://github.com/andrewheberle/serverless-ssh-ca/blob/main/packages/workers-integration/wrangler.jsonc).
75
+ `bindingsFromEnv` validates them at start up and throws an
76
+ `InvalidConfigurationError` that lists every missing or invalid variable.
77
+ - The database schema is created and migrated automatically on first use, as
78
+ on Workers. Use a file path for `DatabaseSync` (not `:memory:`) so issued
79
+ and revoked certificates survive restarts.
80
+ - Only SQLite databases are supported. Other SQLite-compatible databases can
81
+ be used by implementing the `CaDatabase` interface.
82
+ - The CA private key has the same requirements as on Workers (see
83
+ [CA Private Key](#ca-private-key)). Keep the key file readable only by the
84
+ user running the CA.
85
+ - `cleanup()` can also be run on a schedule outside the process (for example
86
+ from a systemd timer or cron job) instead of using `setInterval`.
87
+ - Put the CA behind a reverse proxy that terminates TLS, as clients send
88
+ identity tokens to it.
89
+
33
90
  See the following respositories for additional information:
34
91
 
35
92
 
@@ -193,7 +250,7 @@ must be an Ed25519 or ECDSA (`nistp256`, `nistp384` or `nistp521`) key:
193
250
  ssh-keygen -t ed25519 -N "" -C "" -f ssh-ca
194
251
  ```
195
252
 
196
- RSA CA keys are not supported on the Workers runtime. With an RSA CA key
253
+ RSA CA keys are not supported. With an RSA CA key
197
254
  configured, every request that uses the CA key (including `/api/v3/ca` and
198
255
  the KRL endpoints) returns a `500` error, and the reason is logged:
199
256
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAoB,MAAM,OAAO,CAAA;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAIhD,oBAAY,eAAe;IAC1B,IAAI,IAAA;IACJ,IAAI,IAAA;CACJ;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,IAAI,CAAA;IACjB,YAAY,EAAE,IAAI,CAAA;IAClB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAA;IACvB,gBAAgB,EAAE,eAAe,CAAA;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC5B,YAAY,EAAE,iBAAiB,CAAA;CAC/B,CAAA;AAqBD,eAAO,MAAM,SAAS,QAAe,aAAa,kBAsBjD,CAAA;AAED,eAAO,MAAM,iBAAiB,QAAe,aAAa,eAAe,WAAW,SAAS,MAAM,oBAAmB,eAAe,kBA2BpI,CAAA;AAED,eAAO,MAAM,SAAS,QAAe,aAAa,UAAU,MAAM,KAAG,OAAO,CAAC,OAAO,CAYnF,CAAA;AAED,oBAAY,gBAAgB;IAC3B,QAAQ,IAAA;IACR,OAAO,IAAA;IACP,SAAS,IAAA;IACT,WAAW,IAAA;CACX;AAED,eAAO,MAAM,gBAAgB,QAAe,aAAa,UAAU,MAAM,aAAa,MAAM,mBAAmB,eAAe,KAAG,OAAO,CAAC,gBAAgB,CAwBxJ,CAAA;AAED,eAAO,MAAM,iBAAiB,QAAe,aAAa,mBAAmB,eAAe,KAAG,OAAO,CAAC,MAAM,EAAE,CAoB9G,CAAA;AAED,KAAK,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAA;AAE/D,eAAO,MAAM,iBAAiB,QAAe,aAAa,UAAU,MAAM,KAAG,OAAO,CAAC,kBAAkB,EAAE,CAuBxG,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAoB,MAAM,OAAO,CAAA;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAKhD,oBAAY,eAAe;IAC1B,IAAI,IAAA;IACJ,IAAI,IAAA;CACJ;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,IAAI,CAAA;IACjB,YAAY,EAAE,IAAI,CAAA;IAClB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAA;IACvB,gBAAgB,EAAE,eAAe,CAAA;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC5B,YAAY,EAAE,iBAAiB,CAAA;CAC/B,CAAA;AAmBD,eAAO,MAAM,SAAS,QAAe,aAAa,kBAsBjD,CAAA;AAED,eAAO,MAAM,iBAAiB,QAAe,aAAa,eAAe,WAAW,SAAS,MAAM,oBAAmB,eAAe,kBA2BpI,CAAA;AAED,eAAO,MAAM,SAAS,QAAe,aAAa,UAAU,MAAM,KAAG,OAAO,CAAC,OAAO,CAYnF,CAAA;AAED,oBAAY,gBAAgB;IAC3B,QAAQ,IAAA;IACR,OAAO,IAAA;IACP,SAAS,IAAA;IACT,WAAW,IAAA;CACX;AAED,eAAO,MAAM,gBAAgB,QAAe,aAAa,UAAU,MAAM,aAAa,MAAM,mBAAmB,eAAe,KAAG,OAAO,CAAC,gBAAgB,CAwBxJ,CAAA;AAED,eAAO,MAAM,iBAAiB,QAAe,aAAa,mBAAmB,eAAe,KAAG,OAAO,CAAC,MAAM,EAAE,CAoB9G,CAAA;AAED,KAAK,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAA;AAE/D,eAAO,MAAM,iBAAiB,QAAe,aAAa,UAAU,MAAM,KAAG,OAAO,CAAC,kBAAkB,EAAE,CAuBxG,CAAA"}
package/dist/db/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { logger } from "../logger.js";
2
2
  import { D1QB } from "workers-qb";
3
+ import { migrateOnce } from "./migrate.js";
3
4
  import { migrations } from "./migrations/index.js";
4
5
  export var CertificateType;
5
6
  (function (CertificateType) {
@@ -10,11 +11,9 @@ const connect = async (env) => {
10
11
  const l = logger(env);
11
12
  try {
12
13
  l.debug("connecting to database");
13
- const qb = new D1QB(env.DB);
14
- const migrationBuilder = qb.migrations({ migrations });
15
- const appliedMigrations = await migrationBuilder.apply();
14
+ const appliedMigrations = await migrateOnce(env.DB, migrations);
16
15
  l.debug("applied database migrations", "migrations", appliedMigrations.length, "migration_names", appliedMigrations.map(m => m.name));
17
- return qb;
16
+ return new D1QB(env.DB);
18
17
  }
19
18
  catch (err) {
20
19
  l.error("error connecting to database", "error", err);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAElD,MAAM,CAAN,IAAY,eAGX;AAHD,WAAY,eAAe;IAC1B,qDAAI,CAAA;IACJ,qDAAI,CAAA;AACL,CAAC,EAHW,eAAe,KAAf,eAAe,QAG1B;AAmBD,MAAM,OAAO,GAAG,KAAK,EAAE,GAAkB,EAAiC,EAAE;IAC3E,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;IAErB,IAAI,CAAC;QACJ,CAAC,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;QAEjC,MAAM,iBAAiB,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;QAE/D,CAAC,CAAC,KAAK,CAAC,6BAA6B,EAAE,YAAY,EAAE,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QAErI,OAAO,IAAI,IAAI,CAAiB,GAAG,CAAC,EAAE,CAAC,CAAA;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,CAAC,CAAC,KAAK,CAAC,8BAA8B,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;QACrD,MAAM,GAAG,CAAA;IACV,CAAC;AACF,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,GAAkB,EAAE,EAAE;IACrD,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,wBAAwB,CAAC,CAAA;IAErE,IAAI,GAAG,CAAC,wBAAwB,KAAK,UAAU,EAAE,CAAC;QACjD,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;QACnC,OAAM;IACP,CAAC;IAED,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;IACnC,IAAI,CAAC;QACJ,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;QAC7B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC;YAC3B,SAAS,EAAE,cAAc;YACzB,KAAK,EAAE;gBACN,UAAU,EAAE,0DAA0D;gBACtE,MAAM,EAAE,GAAG,CAAC,wBAAwB;aACpC;SACD,CAAC,CAAC,OAAO,EAAE,CAAA;QACZ,CAAC,CAAC,IAAI,CAAC,4BAA4B,EAAE,SAAS,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACnE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,CAAC,CAAC,KAAK,CAAC,+BAA+B,EAAE,WAAW,EAAE,GAAG,CAAC,wBAAwB,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IAClG,CAAC;AACF,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,GAAkB,EAAE,WAAwB,EAAE,KAAa,EAAE,eAAe,GAAoB,eAAe,CAAC,IAAI,EAAE,EAAE;IAC/J,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;IACpD,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAW,EAAU,EAAE;QACjE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAA;IACpB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACZ,MAAM,UAAU,GAAG,WAAW,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,CAAuD,EAAU,EAAE;QACtH,iDAAiD;QACjD,OAAO,CAAC,CAAC,IAAc,CAAA;IACxB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACZ,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;IAC7B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC;QAC3B,SAAS,EAAE,cAAc;QACzB,IAAI,EAAE;YACL,MAAM,EAAE,GAAG,MAAM,EAAE;YACnB,MAAM,EAAE,KAAK;YACb,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,UAAU;YACtB,WAAW,EAAE,WAAW,CAAC,SAAS,CAAC,WAAW,EAAE;YAChD,YAAY,EAAE,WAAW,CAAC,UAAU,CAAC,WAAW,EAAE;YAClD,gBAAgB,EAAE,eAAe;YACjC,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC;SAClD;KACD,CAAC,CAAC,OAAO,EAAE,CAAA;IAEZ,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAA;IACtC,CAAC;AACF,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,GAAkB,EAAE,MAAc,EAAoB,EAAE;IACvF,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;IAC7B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC;QAC7B,SAAS,EAAE,cAAc;QACzB,MAAM,EAAE,CAAC,QAAQ,CAAC;QAClB,KAAK,EAAE;YACN,UAAU,EAAE,mCAAmC;YAC/C,MAAM,EAAE,GAAG,MAAM,EAAE;SACnB;KACD,CAAC,CAAC,OAAO,EAAE,CAAA;IAEZ,OAAO,GAAG,CAAC,OAAO,KAAK,SAAS,CAAA;AACjC,CAAC,CAAA;AAED,MAAM,CAAN,IAAY,gBAKX;AALD,WAAY,gBAAgB;IAC3B,+DAAQ,CAAA;IACR,6DAAO,CAAA;IACP,iEAAS,CAAA;IACT,qEAAW,CAAA;AACZ,CAAC,EALW,gBAAgB,KAAhB,gBAAgB,QAK3B;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,GAAkB,EAAE,MAAc,EAAE,SAAiB,EAAE,eAAgC,EAA6B,EAAE;IAC5J,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;IAC7B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC;QAC7B,SAAS,EAAE,cAAc;QACzB,MAAM,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;QACpC,KAAK,EAAE;YACN,UAAU,EAAE,wDAAwD;YACpE,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC;SACjD;KACD,CAAC,CAAC,OAAO,EAAE,CAAA;IAEZ,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,gBAAgB,CAAC,QAAQ,CAAA;IACjC,CAAC;IAED,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QACrC,OAAO,gBAAgB,CAAC,OAAO,CAAA;IAChC,CAAC;IAED,IAAI,SAAS,KAAK,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QAC1C,OAAO,gBAAgB,CAAC,SAAS,CAAA;IAClC,CAAC;IAED,OAAO,gBAAgB,CAAC,WAAW,CAAA;AACpC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,GAAkB,EAAE,eAAgC,EAAqB,EAAE;IAClH,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;IAC7B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC;QAC7B,SAAS,EAAE,cAAc;QACzB,MAAM,EAAE,CAAC,QAAQ,CAAC;QAClB,KAAK,EAAE;YACN,UAAU,EAAE,mHAAmH;YAC/H,MAAM,EAAE,eAAe;SACvB;KACD,CAAC,CAAC,OAAO,EAAE,CAAA;IAEZ,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,EAAE,CAAA;IACV,CAAC;IAED,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;AAC5C,CAAC,CAAA;AAID,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,GAAkB,EAAE,MAAc,EAAiC,EAAE;IAC5G,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;IAC7B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,CAAqB;QAC/C,SAAS,EAAE,cAAc;QACzB,IAAI,EAAE;YACL,UAAU,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,WAAW,EAAE;SACpC;QACD,KAAK,EAAE;YACN,UAAU,EAAE,YAAY;YACxB,MAAM,EAAE,GAAG,MAAM,EAAE;SACnB;QACD,SAAS,EAAE,CAAC,YAAY,CAAC;KACzB,CAAC,CAAC,OAAO,EAAE,CAAA;IAEZ,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,EAAE,CAAA;IACV,CAAC;IAED,OAAO,GAAG,CAAC,OAAO,CAAA;AACnB,CAAC,CAAA"}
@@ -0,0 +1,41 @@
1
+ import type { CaDatabase } from "../types.js";
2
+ /**
3
+ * A database schema migration.
4
+ *
5
+ * Migrations are applied in order and recorded by `name` in the `migrations`
6
+ * table, so a name must never change once released. Each statement must be a
7
+ * single SQL statement.
8
+ */
9
+ export type Migration = {
10
+ /** Unique name recorded once the migration has been applied */
11
+ name: string;
12
+ /** The SQL statements to run, in order, as one transaction */
13
+ statements: string[];
14
+ };
15
+ /**
16
+ * Apply any migrations that have not yet been applied to the database.
17
+ *
18
+ * Each migration is run with {@link CaDatabase.batch} so it applies atomically,
19
+ * and its row in the `migrations` table is inserted first. When several callers
20
+ * race to apply the same migration only one succeeds; the others fail on that
21
+ * insert before running any of the migration's statements and their batch rolls
22
+ * back, so migrations that are not idempotent are safe to apply concurrently.
23
+ *
24
+ * @param db The database to migrate, see {@link CaDatabase}
25
+ * @param migrations The migrations to apply in order, see {@link Migration}
26
+ * @returns The migrations applied by this call, excluding any applied concurrently by another caller
27
+ */
28
+ export declare const applyMigrations: (db: CaDatabase, migrations: readonly Migration[]) => Promise<Migration[]>;
29
+ /**
30
+ * Apply migrations to a database at most once per database binding, see
31
+ * {@link applyMigrations}.
32
+ *
33
+ * Concurrent and later callers share the result of the first call, unless it
34
+ * fails, in which case the next call tries again.
35
+ *
36
+ * @param db The database to migrate, see {@link CaDatabase}
37
+ * @param migrations The migrations to apply in order, see {@link Migration}
38
+ * @returns The migrations applied, or an empty array if this database binding has already been migrated
39
+ */
40
+ export declare const migrateOnce: (db: CaDatabase, migrations: readonly Migration[]) => Promise<Migration[]>;
41
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACvB,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,UAAU,EAAE,MAAM,EAAE,CAAA;CACpB,CAAA;AAqBD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,OAAc,UAAU,cAAc,SAAS,SAAS,EAAE,KAAG,OAAO,CAAC,SAAS,EAAE,CAyB3G,CAAA;AAID;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,OAAc,UAAU,cAAc,SAAS,SAAS,EAAE,KAAG,OAAO,CAAC,SAAS,EAAE,CAiBvG,CAAA"}
@@ -0,0 +1,84 @@
1
+ import z from "zod";
2
+ // matches the table previously created by workers-qb so existing databases are not migrated again
3
+ const createMigrationsTable = `CREATE TABLE IF NOT EXISTS migrations (
4
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
5
+ name TEXT UNIQUE,
6
+ applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
7
+ )`;
8
+ const MigrationRows = z.array(z.object({ name: z.string() }));
9
+ const appliedNames = async (db) => {
10
+ const { results } = await db.prepare("SELECT name FROM migrations").all();
11
+ return new Set(MigrationRows.parse(results).map(row => row.name));
12
+ };
13
+ const isApplied = async (db, name) => {
14
+ const { results } = await db.prepare("SELECT name FROM migrations WHERE name = ?").bind(name).all();
15
+ return results.length > 0;
16
+ };
17
+ /**
18
+ * Apply any migrations that have not yet been applied to the database.
19
+ *
20
+ * Each migration is run with {@link CaDatabase.batch} so it applies atomically,
21
+ * and its row in the `migrations` table is inserted first. When several callers
22
+ * race to apply the same migration only one succeeds; the others fail on that
23
+ * insert before running any of the migration's statements and their batch rolls
24
+ * back, so migrations that are not idempotent are safe to apply concurrently.
25
+ *
26
+ * @param db The database to migrate, see {@link CaDatabase}
27
+ * @param migrations The migrations to apply in order, see {@link Migration}
28
+ * @returns The migrations applied by this call, excluding any applied concurrently by another caller
29
+ */
30
+ export const applyMigrations = async (db, migrations) => {
31
+ await db.prepare(createMigrationsTable).run();
32
+ const existing = await appliedNames(db);
33
+ const applied = [];
34
+ for (const migration of migrations) {
35
+ if (existing.has(migration.name)) {
36
+ continue;
37
+ }
38
+ try {
39
+ await db.batch([
40
+ db.prepare("INSERT INTO migrations (name) VALUES (?)").bind(migration.name),
41
+ ...migration.statements.map(sql => db.prepare(sql)),
42
+ ]);
43
+ applied.push(migration);
44
+ }
45
+ catch (err) {
46
+ // another caller applying the same migration is not an error
47
+ if (!(await isApplied(db, migration.name))) {
48
+ throw err;
49
+ }
50
+ }
51
+ }
52
+ return applied;
53
+ };
54
+ const migrated = new WeakMap();
55
+ /**
56
+ * Apply migrations to a database at most once per database binding, see
57
+ * {@link applyMigrations}.
58
+ *
59
+ * Concurrent and later callers share the result of the first call, unless it
60
+ * fails, in which case the next call tries again.
61
+ *
62
+ * @param db The database to migrate, see {@link CaDatabase}
63
+ * @param migrations The migrations to apply in order, see {@link Migration}
64
+ * @returns The migrations applied, or an empty array if this database binding has already been migrated
65
+ */
66
+ export const migrateOnce = async (db, migrations) => {
67
+ const pending = migrated.get(db);
68
+ if (pending !== undefined) {
69
+ await pending;
70
+ return [];
71
+ }
72
+ const result = applyMigrations(db, migrations);
73
+ migrated.set(db, result);
74
+ try {
75
+ return await result;
76
+ }
77
+ catch (err) {
78
+ if (migrated.get(db) === result) {
79
+ migrated.delete(db);
80
+ }
81
+ throw err;
82
+ }
83
+ };
84
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/db/migrate.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { type Migration } from "workers-qb";
1
+ import type { Migration } from "../migrate.js";
2
2
  export declare const migration: Migration;
3
3
  //# sourceMappingURL=0001_initial_schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"0001_initial_schema.d.ts","sourceRoot":"","sources":["../../../src/db/migrations/0001_initial_schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,eAAO,MAAM,SAAS,EAAE,SAsBvB,CAAA"}
1
+ {"version":3,"file":"0001_initial_schema.d.ts","sourceRoot":"","sources":["../../../src/db/migrations/0001_initial_schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAE9C,eAAO,MAAM,SAAS,EAAE,SAqBvB,CAAA"}
@@ -1,7 +1,7 @@
1
1
  export const migration = {
2
2
  name: "0001_initial_schema",
3
- sql: `
4
- CREATE TABLE IF NOT EXISTS certificates (
3
+ statements: [
4
+ `CREATE TABLE IF NOT EXISTS certificates (
5
5
  id INTEGER PRIMARY KEY,
6
6
  serial TEXT UNIQUE NOT NULL,
7
7
  key_id TEXT NOT NULL,
@@ -12,13 +12,12 @@ export const migration = {
12
12
  revoked_at TIMESTAMP,
13
13
  certificate_type INTEGER NOT NULL DEFAULT 0,
14
14
  public_key TEXT
15
- );
16
-
17
- CREATE INDEX IF NOT EXISTS idx_certificates_serial ON certificates(serial);
18
- CREATE INDEX IF NOT EXISTS idx_certificates_valid_after ON certificates(valid_after);
19
- CREATE INDEX IF NOT EXISTS idx_certificates_valid_before ON certificates(valid_before);
20
- CREATE INDEX IF NOT EXISTS idx_certificates_revoked_at ON certificates(revoked_at);
21
- CREATE INDEX IF NOT EXISTS idx_certificates_certificate_type ON certificates(certificate_type);
22
- `
15
+ )`,
16
+ "CREATE INDEX IF NOT EXISTS idx_certificates_serial ON certificates(serial)",
17
+ "CREATE INDEX IF NOT EXISTS idx_certificates_valid_after ON certificates(valid_after)",
18
+ "CREATE INDEX IF NOT EXISTS idx_certificates_valid_before ON certificates(valid_before)",
19
+ "CREATE INDEX IF NOT EXISTS idx_certificates_revoked_at ON certificates(revoked_at)",
20
+ "CREATE INDEX IF NOT EXISTS idx_certificates_certificate_type ON certificates(certificate_type)",
21
+ ]
23
22
  };
24
23
  //# sourceMappingURL=0001_initial_schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"0001_initial_schema.js","sourceRoot":"","sources":["../../../src/db/migrations/0001_initial_schema.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAc;IACnC,IAAI,EAAE,qBAAqB;IAC3B,GAAG,EAAE;;;;;;;;;;;;;;;;;;;EAmBJ;CACD,CAAA"}
1
+ {"version":3,"file":"0001_initial_schema.js","sourceRoot":"","sources":["../../../src/db/migrations/0001_initial_schema.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAc;IACnC,IAAI,EAAE,qBAAqB;IAC3B,UAAU,EAAE;QACX;;;;;;;;;;;IAWE;QACF,4EAA4E;QAC5E,sFAAsF;QACtF,wFAAwF;QACxF,oFAAoF;QACpF,gGAAgG;KAChG;CACD,CAAA"}
@@ -1,3 +1,3 @@
1
- import { type Migration } from "workers-qb";
1
+ import type { Migration } from "../migrate.js";
2
2
  export declare const migrations: Migration[];
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/db/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AAG3C,eAAO,MAAM,UAAU,EAAE,SAAS,EAEjC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/db/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAG9C,eAAO,MAAM,UAAU,EAAE,SAAS,EAEjC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,33 @@
1
1
  import type { ExecutionContext } from "hono";
2
2
  import type { SshCaBindings } from "./types.js";
3
- export type { CaDatabase, CaSecret, SshCaBindings } from "./types.js";
3
+ export type { CaDatabase, CaDatabaseQueryResult, CaDatabaseResult, CaPreparedStatement, CaSecret, SshCaBindings } from "./types.js";
4
+ /**
5
+ * A runtime neutral instance of the CA, returned by {@link createSshCa}.
6
+ */
7
+ export interface SshCa {
8
+ /**
9
+ * Handle a request to the CA's API, suitable for any server that speaks
10
+ * the Fetch API `Request` and `Response` types.
11
+ */
12
+ fetch(req: Request): Promise<Response>;
13
+ /**
14
+ * Remove expired certificates from the database according to
15
+ * `DB_CERTIFICATE_RETENTION`. This should be run periodically (for example
16
+ * once a day), as the `scheduled` handler does on Cloudflare Workers.
17
+ */
18
+ cleanup(): Promise<void>;
19
+ }
20
+ /**
21
+ * Create an instance of the CA bound to a fixed set of bindings, for use on
22
+ * runtimes other than Cloudflare Workers.
23
+ *
24
+ * On Workers use the default export instead, which receives its bindings from
25
+ * the runtime on each request.
26
+ *
27
+ * @param env The bindings (configuration, database and private key) for the CA, see {@link SshCaBindings}
28
+ * @returns The CA's request handler and database cleanup task, see {@link SshCa}
29
+ */
30
+ export declare const createSshCa: (env: SshCaBindings) => SshCa;
4
31
  declare const _default: {
5
32
  fetch(req: Request, env: SshCaBindings, ctx: ExecutionContext): Promise<Response> | Response;
6
33
  scheduled(controller: unknown, env: SshCaBindings, ctx: ExecutionContext): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,MAAM,CAAA;AAG5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC/C,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;;eAWtD,OAAO,OAAO,aAAa,OAAO,gBAAgB;0BAMjC,OAAO,OAAO,aAAa,OAAO,gBAAgB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,MAAM,CAAA;AAG5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC/C,YAAY,EAAE,UAAU,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAQnI;;GAEG;AACH,MAAM,WAAW,KAAK;IAClB;;;OAGG;IACH,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IACtC;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,QAAS,aAAa,KAAG,KAOhD,CAAA;;eAKc,OAAO,OAAO,aAAa,OAAO,gBAAgB;0BAMjC,OAAO,OAAO,aAAa,OAAO,gBAAgB"}
package/dist/index.js CHANGED
@@ -1,5 +1,22 @@
1
1
  import { dbCleanup } from "./db/index.js";
2
2
  import { createApp } from "./router.js";
3
+ /**
4
+ * Create an instance of the CA bound to a fixed set of bindings, for use on
5
+ * runtimes other than Cloudflare Workers.
6
+ *
7
+ * On Workers use the default export instead, which receives its bindings from
8
+ * the runtime on each request.
9
+ *
10
+ * @param env The bindings (configuration, database and private key) for the CA, see {@link SshCaBindings}
11
+ * @returns The CA's request handler and database cleanup task, see {@link SshCa}
12
+ */
13
+ export const createSshCa = (env) => {
14
+ const app = createApp(env);
15
+ return {
16
+ fetch: async (req) => await app.fetch(req, env),
17
+ cleanup: async () => await dbCleanup(env),
18
+ };
19
+ };
3
20
  let app;
4
21
  export default {
5
22
  fetch(req, env, ctx) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAUvC,IAAI,GAA6C,CAAA;AAEjD,eAAe;IACX,KAAK,CAAC,GAAY,EAAE,GAAkB,EAAE,GAAqB;QACzD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACpB,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;QACxB,CAAC;QACD,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;IACnC,CAAC;IACD,KAAK,CAAC,SAAS,CAAC,UAAmB,EAAE,GAAkB,EAAE,GAAqB;QAC1E,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IACjC,CAAC;CACmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AA2BvC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAkB,EAAS,EAAE;IACrD,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;IAE1B,OAAO;QACH,KAAK,EAAE,KAAK,EAAE,GAAY,EAAqB,EAAE,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC;QAC3E,OAAO,EAAE,KAAK,IAAmB,EAAE,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC;KAC3D,CAAA;AACL,CAAC,CAAA;AAED,IAAI,GAA6C,CAAA;AAEjD,eAAe;IACX,KAAK,CAAC,GAAY,EAAE,GAAkB,EAAE,GAAqB;QACzD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACpB,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;QACxB,CAAC;QACD,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;IACnC,CAAC;IACD,KAAK,CAAC,SAAS,CAAC,UAAmB,EAAE,GAAkB,EAAE,GAAqB;QAC1E,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IACjC,CAAC;CACmB,CAAA"}
@@ -0,0 +1,72 @@
1
+ import z from "zod";
2
+ import type { CaDatabase, CaSecret, SshCaBindings } from "../types.js";
3
+ /**
4
+ * The environment variables read by {@link bindingsFromEnv}, which match the
5
+ * Workers vars documented for the CA.
6
+ */
7
+ export declare const EnvSchema: z.ZodObject<{
8
+ DB_CERTIFICATE_RETENTION: z.ZodUnion<readonly [z.ZodLiteral<"infinite">, z.ZodString]>;
9
+ SSH_CERTIFICATE_EXTENSIONS: z.ZodString;
10
+ SSH_CERTIFICATE_LIFETIME: z.ZodString;
11
+ SSH_CERTIFICATE_INCLUDE_SELF: z.ZodOptional<z.ZodEnum<{
12
+ false: "false";
13
+ true: "true";
14
+ }>>;
15
+ SSH_CERTIFICATE_INCLUDE_SELF_EMAIL: z.ZodOptional<z.ZodEnum<{
16
+ false: "false";
17
+ true: "true";
18
+ }>>;
19
+ SSH_CERTIFICATE_PRINCIPALS: z.ZodOptional<z.ZodString>;
20
+ SSH_HOST_CERTIFICATE_LIFETIME: z.ZodString;
21
+ SSH_HOST_CERTIFICATE_ALLOWED_EMAILS: z.ZodOptional<z.ZodString>;
22
+ SSH_HOST_CERTIFICATE_ALLOWED_ROLES: z.ZodOptional<z.ZodString>;
23
+ ISSUER_DN: z.ZodString;
24
+ JWT_JWKS_URL: z.ZodURL;
25
+ JWT_AUD: z.ZodOptional<z.ZodString>;
26
+ JWT_ISSUER: z.ZodString;
27
+ JWT_ALGORITHMS: z.ZodString;
28
+ JWT_SSH_CERTIFICATE_PRINCIPALS_CLAIM: z.ZodString;
29
+ CERTIFICATE_REQUEST_TIME_SKEW_MAX: z.ZodString;
30
+ LOG_LEVEL: z.ZodOptional<z.ZodEnum<{
31
+ debug: "debug";
32
+ error: "error";
33
+ info: "info";
34
+ none: "none";
35
+ warning: "warning";
36
+ }>>;
37
+ }, z.core.$strip>;
38
+ /**
39
+ * The CA's configuration as read from environment variables, see {@link EnvSchema}.
40
+ */
41
+ export type CaEnv = z.infer<typeof EnvSchema>;
42
+ /**
43
+ * Thrown by {@link bindingsFromEnv} when the environment is not a valid configuration.
44
+ */
45
+ export declare class InvalidConfigurationError extends Error {
46
+ constructor(message: string);
47
+ }
48
+ /**
49
+ * Build the CA's bindings from environment variables, for runtimes where
50
+ * configuration is not supplied as Workers bindings.
51
+ *
52
+ * The variables have the same names and formats as the Workers vars, and are
53
+ * validated before use so that misconfiguration is reported at start up.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const env = bindingsFromEnv({
58
+ * DB: fromNodeSqlite(new DatabaseSync("ssh-ca.sqlite")),
59
+ * PRIVATE_KEY: secretFromFile("/etc/ssh-ca/ca_key"),
60
+ * })
61
+ * ```
62
+ *
63
+ * @param bindings The database and private key, see {@link CaDatabase} and {@link CaSecret}
64
+ * @param source The environment variables to read, `process.env` by default
65
+ * @returns The bindings to pass to `createSshCa`
66
+ * @throws {@link InvalidConfigurationError} if a variable is missing or invalid
67
+ */
68
+ export declare const bindingsFromEnv: (bindings: {
69
+ DB: CaDatabase;
70
+ PRIVATE_KEY: CaSecret;
71
+ }, source?: Record<string, string | undefined>) => SshCaBindings;
72
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/node/env.ts"],"names":[],"mappings":"AACA,OAAO,CAAC,MAAM,KAAK,CAAA;AACnB,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAYtE;;;GAGG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsBpB,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAA;AAE7C;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IACnD,YAAY,OAAO,EAAE,MAAM,EAK1B;CACD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,aACjB;IAAE,EAAE,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,QAAQ,CAAA;CAAE,WAC3C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KACxC,aAOF,CAAA"}
@@ -0,0 +1,74 @@
1
+ import { seconds } from "itty-time";
2
+ import z from "zod";
3
+ const required = z.string().trim().min(1, { message: "must be set" });
4
+ // a duration in the format accepted by itty-time, such as "24 hours"
5
+ const duration = (opts) => required.refine(v => {
6
+ const s = seconds(v);
7
+ return Number.isFinite(s) && (opts.allowZero ? s >= 0 : s > 0);
8
+ }, { message: opts.allowZero ? "must be a duration such as \"90 seconds\"" : "must be a positive duration such as \"24 hours\"" });
9
+ const boolean = z.enum(["true", "false"], { message: "must be \"true\" or \"false\"" });
10
+ /**
11
+ * The environment variables read by {@link bindingsFromEnv}, which match the
12
+ * Workers vars documented for the CA.
13
+ */
14
+ export const EnvSchema = z.object({
15
+ DB_CERTIFICATE_RETENTION: z.union([
16
+ z.literal("infinite"),
17
+ // an SQLite date modifier such as "1 year" or "90 days"
18
+ z.string().regex(/^[+-]?\d+(\.\d+)? (second|minute|hour|day|month|year)s?$/),
19
+ ], { message: "must be \"infinite\" or a period such as \"1 year\"" }),
20
+ SSH_CERTIFICATE_EXTENSIONS: z.string(),
21
+ SSH_CERTIFICATE_LIFETIME: duration({ allowZero: false }),
22
+ SSH_CERTIFICATE_INCLUDE_SELF: boolean.optional(),
23
+ SSH_CERTIFICATE_INCLUDE_SELF_EMAIL: boolean.optional(),
24
+ SSH_CERTIFICATE_PRINCIPALS: z.string().optional(),
25
+ SSH_HOST_CERTIFICATE_LIFETIME: duration({ allowZero: false }),
26
+ SSH_HOST_CERTIFICATE_ALLOWED_EMAILS: z.string().optional(),
27
+ SSH_HOST_CERTIFICATE_ALLOWED_ROLES: z.string().optional(),
28
+ ISSUER_DN: required,
29
+ JWT_JWKS_URL: z.url({ protocol: /^https?$/, message: "must be an http or https URL" }),
30
+ JWT_AUD: z.string().optional(),
31
+ JWT_ISSUER: required,
32
+ JWT_ALGORITHMS: required,
33
+ JWT_SSH_CERTIFICATE_PRINCIPALS_CLAIM: required,
34
+ CERTIFICATE_REQUEST_TIME_SKEW_MAX: duration({ allowZero: true }),
35
+ LOG_LEVEL: z.enum(["none", "error", "warning", "info", "debug"]).optional(),
36
+ });
37
+ /**
38
+ * Thrown by {@link bindingsFromEnv} when the environment is not a valid configuration.
39
+ */
40
+ export class InvalidConfigurationError extends Error {
41
+ constructor(message) {
42
+ super(message);
43
+ this.name = "InvalidConfigurationError";
44
+ Object.setPrototypeOf(this, InvalidConfigurationError.prototype);
45
+ }
46
+ }
47
+ /**
48
+ * Build the CA's bindings from environment variables, for runtimes where
49
+ * configuration is not supplied as Workers bindings.
50
+ *
51
+ * The variables have the same names and formats as the Workers vars, and are
52
+ * validated before use so that misconfiguration is reported at start up.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const env = bindingsFromEnv({
57
+ * DB: fromNodeSqlite(new DatabaseSync("ssh-ca.sqlite")),
58
+ * PRIVATE_KEY: secretFromFile("/etc/ssh-ca/ca_key"),
59
+ * })
60
+ * ```
61
+ *
62
+ * @param bindings The database and private key, see {@link CaDatabase} and {@link CaSecret}
63
+ * @param source The environment variables to read, `process.env` by default
64
+ * @returns The bindings to pass to `createSshCa`
65
+ * @throws {@link InvalidConfigurationError} if a variable is missing or invalid
66
+ */
67
+ export const bindingsFromEnv = (bindings, source = process.env) => {
68
+ const result = EnvSchema.safeParse(source);
69
+ if (!result.success) {
70
+ throw new InvalidConfigurationError(`invalid configuration:\n${z.prettifyError(result.error)}`);
71
+ }
72
+ return { ...result.data, DB: bindings.DB, PRIVATE_KEY: bindings.PRIVATE_KEY };
73
+ };
74
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/node/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,CAAC,MAAM,KAAK,CAAA;AAGnB,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAA;AAErE,qEAAqE;AACrE,MAAM,QAAQ,GAAG,CAAC,IAA4B,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;IACtE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACpB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;AAC/D,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,2CAA2C,CAAC,CAAC,CAAC,kDAAkD,EAAE,CAAC,CAAA;AAElI,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC,CAAA;AAEvF;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,wBAAwB,EAAE,CAAC,CAAC,KAAK,CAAC;QACjC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QACrB,wDAAwD;QACxD,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,0DAA0D,CAAC;KAC5E,EAAE,EAAE,OAAO,EAAE,qDAAqD,EAAE,CAAC;IACtE,0BAA0B,EAAE,CAAC,CAAC,MAAM,EAAE;IACtC,wBAAwB,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACxD,4BAA4B,EAAE,OAAO,CAAC,QAAQ,EAAE;IAChD,kCAAkC,EAAE,OAAO,CAAC,QAAQ,EAAE;IACtD,0BAA0B,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjD,6BAA6B,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC7D,mCAAmC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1D,kCAAkC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzD,SAAS,EAAE,QAAQ;IACnB,YAAY,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC;IACtF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,UAAU,EAAE,QAAQ;IACpB,cAAc,EAAE,QAAQ;IACxB,oCAAoC,EAAE,QAAQ;IAC9C,iCAAiC,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAChE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC3E,CAAC,CAAA;AAOF;;GAEG;AACH,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IACnD,YAAY,OAAe;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAA;QAEvC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAA;IACjE,CAAC;CACD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC9B,QAAmD,EACnD,MAAM,GAAuC,OAAO,CAAC,GAAG,EACxC,EAAE;IAClB,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;IAC1C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,yBAAyB,CAAC,2BAA2B,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAChG,CAAC;IAED,OAAO,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAA;AAC9E,CAAC,CAAA"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Helpers for running the CA on Node.js, imported from
3
+ * `@andrewheberle/serverless-ssh-ca/node`.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { DatabaseSync } from "node:sqlite"
8
+ * import { createSshCa } from "@andrewheberle/serverless-ssh-ca"
9
+ * import { bindingsFromEnv, fromNodeSqlite, secretFromFile } from "@andrewheberle/serverless-ssh-ca/node"
10
+ *
11
+ * const ca = createSshCa(bindingsFromEnv({
12
+ * DB: fromNodeSqlite(new DatabaseSync("ssh-ca.sqlite")),
13
+ * PRIVATE_KEY: secretFromFile("/etc/ssh-ca/ca_key"),
14
+ * }))
15
+ * ```
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ export { bindingsFromEnv, EnvSchema, InvalidConfigurationError } from "./env.js";
20
+ export type { CaEnv } from "./env.js";
21
+ export { secretFromFile, secretFromString } from "./secret.js";
22
+ export { fromNodeSqlite } from "./sqlite.js";
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA;AAChF,YAAY,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Helpers for running the CA on Node.js, imported from
3
+ * `@andrewheberle/serverless-ssh-ca/node`.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { DatabaseSync } from "node:sqlite"
8
+ * import { createSshCa } from "@andrewheberle/serverless-ssh-ca"
9
+ * import { bindingsFromEnv, fromNodeSqlite, secretFromFile } from "@andrewheberle/serverless-ssh-ca/node"
10
+ *
11
+ * const ca = createSshCa(bindingsFromEnv({
12
+ * DB: fromNodeSqlite(new DatabaseSync("ssh-ca.sqlite")),
13
+ * PRIVATE_KEY: secretFromFile("/etc/ssh-ca/ca_key"),
14
+ * }))
15
+ * ```
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ export { bindingsFromEnv, EnvSchema, InvalidConfigurationError } from "./env.js";
20
+ export { secretFromFile, secretFromString } from "./secret.js";
21
+ export { fromNodeSqlite } from "./sqlite.js";
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA;AAEhF,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}