@noy-db/at-aws-kms 0.2.0-pre.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.
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/index.cjs +53 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 vLannaAi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# @noy-db/at-aws-kms
|
|
2
|
+
|
|
3
|
+
**AWS KMS sealing key provider for noy-db [managed-passphrase mode](https://github.com/vLannaAi/noy-db/issues/14).**
|
|
4
|
+
|
|
5
|
+
An `at-*` provider that seals and unseals the hub-generated random passphrase via AWS KMS Encrypt / Decrypt. Every seal and unseal is an authenticated KMS API call — giving you a CloudTrail-backed access log of every time a user's vault is opened, with no additional instrumentation required.
|
|
6
|
+
|
|
7
|
+
Like all `at-*` providers, this is a *trusted host* provider: the host you deploy it on CAN decrypt what it unseals. The security boundary is your AWS IAM policy — access is controlled by which roles hold `kms:Decrypt` on the KMS key, not by a secret the host keeps in memory.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @noy-db/hub @noy-db/at-aws-kms @noy-db/on-shamir
|
|
13
|
+
# or: npm install @noy-db/hub @noy-db/at-aws-kms @noy-db/on-shamir
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# 1. Create a KMS key once (or reuse an existing ENCRYPT_DECRYPT key):
|
|
20
|
+
aws kms create-key --description "noy-db sealing key"
|
|
21
|
+
# Note the KeyId or ARN from the output.
|
|
22
|
+
|
|
23
|
+
# 2. Grant your host's IAM role kms:Encrypt + kms:Decrypt on that key.
|
|
24
|
+
# Credentials are picked up automatically from the SDK's ambient chain
|
|
25
|
+
# (IAM instance role, ECS task role, ~/.aws/credentials, env vars, etc.).
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// 3. In your app:
|
|
30
|
+
import { createNoydb } from '@noy-db/hub'
|
|
31
|
+
import { awsKmsSealingProvider } from '@noy-db/at-aws-kms'
|
|
32
|
+
import { shamirRecoveryProvider } from '@noy-db/on-shamir'
|
|
33
|
+
|
|
34
|
+
const db = await createNoydb({
|
|
35
|
+
store,
|
|
36
|
+
user: 'alice',
|
|
37
|
+
passphraseMode: 'managed',
|
|
38
|
+
sealingKey: awsKmsSealingProvider({ keyId: 'arn:aws:kms:us-east-1:123456789012:key/abc' }),
|
|
39
|
+
shamirRecovery: shamirRecoveryProvider(),
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const vault = await db.openVault('acme')
|
|
43
|
+
// Hub generated a 256-bit random on first open, sealed it via KMS Encrypt,
|
|
44
|
+
// and persisted to _meta/sealed-passphrase. The user never sees a passphrase.
|
|
45
|
+
// On reopen, at-aws-kms calls KMS Decrypt transparently.
|
|
46
|
+
// CloudTrail logs every Encrypt/Decrypt call with caller identity + key ARN.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## When to use this provider
|
|
50
|
+
|
|
51
|
+
- ✅ Compliance regimes requiring auditable key access logs (FedRAMP, HIPAA with managed-encryption requirements, SOC 2 Type II).
|
|
52
|
+
- ✅ Workloads already running on AWS where a KMS key costs less than engineering an equivalent audit trail.
|
|
53
|
+
- ✅ Any case where you want automatic CMK rotation without rotating app-side key material.
|
|
54
|
+
|
|
55
|
+
## When NOT to use this provider
|
|
56
|
+
|
|
57
|
+
- ❌ Non-AWS or multi-cloud deployments where adding an AWS dependency is undesirable. Use [`@noy-db/at-env`](../at-env) for a zero-extra-dependency option.
|
|
58
|
+
- ❌ Local dev / CI where you don't want real KMS calls or AWS credentials in CI. Use [`@noy-db/at-env`](../at-env) or `MemorySealingKeyProvider` from `@noy-db/hub` instead.
|
|
59
|
+
|
|
60
|
+
## Key rotation
|
|
61
|
+
|
|
62
|
+
KMS supports automatic key rotation for symmetric keys. Enable it on the CMK and KMS handles the rest — your `keyId` stays the same, no app changes needed. Cross-key migration (moving sealed passphrases to a different CMK) requires manual re-sealing with `unseal` + `seal` under the new key.
|
|
63
|
+
|
|
64
|
+
## API
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
function awsKmsSealingProvider(opts: {
|
|
68
|
+
keyId: string // KMS key id or full ARN
|
|
69
|
+
client?: Pick<KMSClient, 'send'> // optional pre-built client (useful for tests)
|
|
70
|
+
}): SealingKeyProvider
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Never pass raw AWS credentials in the options — inject a pre-configured `KMSClient` for non-default auth. The default `new KMSClient({})` resolves credentials via the SDK's ambient chain.
|
|
74
|
+
|
|
75
|
+
Returns a [`SealingKeyProvider`](../hub/src/team/managed-passphrase.ts) — the contract `@noy-db/hub`'s managed-passphrase mode consumes.
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
awsKmsSealingProvider: () => awsKmsSealingProvider
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var import_client_kms = require("@aws-sdk/client-kms");
|
|
27
|
+
function awsKmsSealingProvider(opts) {
|
|
28
|
+
const client = opts.client ?? new import_client_kms.KMSClient({});
|
|
29
|
+
return {
|
|
30
|
+
id: `aws-kms:${opts.keyId}`,
|
|
31
|
+
async seal(passphrase) {
|
|
32
|
+
const out = await client.send(
|
|
33
|
+
new import_client_kms.EncryptCommand({ KeyId: opts.keyId, Plaintext: passphrase })
|
|
34
|
+
);
|
|
35
|
+
const blob = out.CiphertextBlob;
|
|
36
|
+
if (!blob) throw new Error("@noy-db/at-aws-kms: KMS Encrypt returned no CiphertextBlob");
|
|
37
|
+
return blob instanceof Uint8Array ? blob : new Uint8Array(blob);
|
|
38
|
+
},
|
|
39
|
+
async unseal(sealed) {
|
|
40
|
+
const out = await client.send(
|
|
41
|
+
new import_client_kms.DecryptCommand({ CiphertextBlob: sealed, KeyId: opts.keyId })
|
|
42
|
+
);
|
|
43
|
+
const pt = out.Plaintext;
|
|
44
|
+
if (!pt) throw new Error("@noy-db/at-aws-kms: KMS Decrypt returned no Plaintext");
|
|
45
|
+
return pt instanceof Uint8Array ? pt : new Uint8Array(pt);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
50
|
+
0 && (module.exports = {
|
|
51
|
+
awsKmsSealingProvider
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * **@noy-db/at-aws-kms** — AWS KMS sealing key provider for noy-db\n * managed-passphrase mode (#188).\n *\n * An `at-*` provider that seals and unseals the hub-generated random\n * passphrase via AWS KMS Encrypt / Decrypt. Every seal and unseal is an\n * authenticated KMS API call, giving you a CloudTrail-backed access log of\n * every time a user's vault is opened — no additional instrumentation\n * required.\n *\n * ## When to use\n *\n * - Compliance regimes requiring auditable key access logs (FedRAMP, HIPAA\n * with managed-encryption requirements, SOC 2 Type II).\n * - Workloads already running on AWS where a KMS key costs less than\n * engineering an equivalent audit trail.\n * - Any case where you want automatic CMK rotation without rotating your\n * app's sealing key material manually.\n *\n * ## Setup\n *\n * ```bash\n * # 1. Create a KMS key (one-time, in your AWS console or CLI):\n * aws kms create-key --description \"noy-db sealing key\"\n * # Note the KeyId/ARN from the output.\n *\n * # 2. Grant the host's IAM role kms:Encrypt + kms:Decrypt on that key.\n * # Credentials are picked up automatically from the SDK's ambient chain\n * # (IAM role, ~/.aws/credentials, env vars — see AWS SDK docs).\n * ```\n *\n * ```ts\n * // 3. In your app:\n * import { createNoydb } from '@noy-db/hub'\n * import { awsKmsSealingProvider } from '@noy-db/at-aws-kms'\n * import { shamirRecoveryProvider } from '@noy-db/on-shamir'\n *\n * const db = await createNoydb({\n * store,\n * user: 'alice',\n * passphraseMode: 'managed',\n * sealingKey: awsKmsSealingProvider({ keyId: 'arn:aws:kms:us-east-1:123:key/abc' }),\n * shamirRecovery: shamirRecoveryProvider(),\n * })\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { SealingKeyProvider } from '@noy-db/hub'\nimport {\n KMSClient,\n EncryptCommand,\n DecryptCommand,\n type EncryptCommandOutput,\n type DecryptCommandOutput,\n} from '@aws-sdk/client-kms'\n\n/** Options for {@link awsKmsSealingProvider}. */\nexport interface AwsKmsSealingProviderOptions {\n /** KMS key id or ARN (e.g. `arn:aws:kms:us-east-1:123:key/abc`). */\n readonly keyId: string\n /** Optional pre-built client (DI for tests). Default `new KMSClient({})` (ambient creds). */\n readonly client?: Pick<KMSClient, 'send'>\n}\n\n/**\n * Build a {@link SealingKeyProvider} backed by AWS KMS Encrypt / Decrypt.\n *\n * Credentials are resolved by the SDK's ambient chain — IAM instance roles,\n * environment variables, or `~/.aws/credentials`. Never pass raw credentials\n * in the options; inject a pre-configured client for non-default auth instead.\n *\n * @throws Error when KMS returns no ciphertext or no plaintext (guards\n * against unexpected SDK-response shapes).\n * Any KMS API error (AccessDenied, InvalidKeyUsage, etc.) propagates as-is.\n */\nexport function awsKmsSealingProvider(opts: AwsKmsSealingProviderOptions): SealingKeyProvider {\n const client = opts.client ?? new KMSClient({})\n return {\n id: `aws-kms:${opts.keyId}`,\n\n async seal(passphrase) {\n const out: EncryptCommandOutput = await client.send(\n new EncryptCommand({ KeyId: opts.keyId, Plaintext: passphrase }),\n )\n const blob = out.CiphertextBlob\n if (!blob) throw new Error('@noy-db/at-aws-kms: KMS Encrypt returned no CiphertextBlob')\n return blob instanceof Uint8Array ? blob : new Uint8Array(blob)\n },\n\n async unseal(sealed) {\n const out: DecryptCommandOutput = await client.send(\n new DecryptCommand({ CiphertextBlob: sealed, KeyId: opts.keyId }),\n )\n const pt = out.Plaintext\n if (!pt) throw new Error('@noy-db/at-aws-kms: KMS Decrypt returned no Plaintext')\n return pt instanceof Uint8Array ? pt : new Uint8Array(pt)\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkDA,wBAMO;AAqBA,SAAS,sBAAsB,MAAwD;AAC5F,QAAM,SAAS,KAAK,UAAU,IAAI,4BAAU,CAAC,CAAC;AAC9C,SAAO;AAAA,IACL,IAAI,WAAW,KAAK,KAAK;AAAA,IAEzB,MAAM,KAAK,YAAY;AACrB,YAAM,MAA4B,MAAM,OAAO;AAAA,QAC7C,IAAI,iCAAe,EAAE,OAAO,KAAK,OAAO,WAAW,WAAW,CAAC;AAAA,MACjE;AACA,YAAM,OAAO,IAAI;AACjB,UAAI,CAAC,KAAM,OAAM,IAAI,MAAM,4DAA4D;AACvF,aAAO,gBAAgB,aAAa,OAAO,IAAI,WAAW,IAAI;AAAA,IAChE;AAAA,IAEA,MAAM,OAAO,QAAQ;AACnB,YAAM,MAA4B,MAAM,OAAO;AAAA,QAC7C,IAAI,iCAAe,EAAE,gBAAgB,QAAQ,OAAO,KAAK,MAAM,CAAC;AAAA,MAClE;AACA,YAAM,KAAK,IAAI;AACf,UAAI,CAAC,GAAI,OAAM,IAAI,MAAM,uDAAuD;AAChF,aAAO,cAAc,aAAa,KAAK,IAAI,WAAW,EAAE;AAAA,IAC1D;AAAA,EACF;AACF;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { SealingKeyProvider } from '@noy-db/hub';
|
|
2
|
+
import { KMSClient } from '@aws-sdk/client-kms';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* **@noy-db/at-aws-kms** — AWS KMS sealing key provider for noy-db
|
|
6
|
+
* managed-passphrase mode (#188).
|
|
7
|
+
*
|
|
8
|
+
* An `at-*` provider that seals and unseals the hub-generated random
|
|
9
|
+
* passphrase via AWS KMS Encrypt / Decrypt. Every seal and unseal is an
|
|
10
|
+
* authenticated KMS API call, giving you a CloudTrail-backed access log of
|
|
11
|
+
* every time a user's vault is opened — no additional instrumentation
|
|
12
|
+
* required.
|
|
13
|
+
*
|
|
14
|
+
* ## When to use
|
|
15
|
+
*
|
|
16
|
+
* - Compliance regimes requiring auditable key access logs (FedRAMP, HIPAA
|
|
17
|
+
* with managed-encryption requirements, SOC 2 Type II).
|
|
18
|
+
* - Workloads already running on AWS where a KMS key costs less than
|
|
19
|
+
* engineering an equivalent audit trail.
|
|
20
|
+
* - Any case where you want automatic CMK rotation without rotating your
|
|
21
|
+
* app's sealing key material manually.
|
|
22
|
+
*
|
|
23
|
+
* ## Setup
|
|
24
|
+
*
|
|
25
|
+
* ```bash
|
|
26
|
+
* # 1. Create a KMS key (one-time, in your AWS console or CLI):
|
|
27
|
+
* aws kms create-key --description "noy-db sealing key"
|
|
28
|
+
* # Note the KeyId/ARN from the output.
|
|
29
|
+
*
|
|
30
|
+
* # 2. Grant the host's IAM role kms:Encrypt + kms:Decrypt on that key.
|
|
31
|
+
* # Credentials are picked up automatically from the SDK's ambient chain
|
|
32
|
+
* # (IAM role, ~/.aws/credentials, env vars — see AWS SDK docs).
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* // 3. In your app:
|
|
37
|
+
* import { createNoydb } from '@noy-db/hub'
|
|
38
|
+
* import { awsKmsSealingProvider } from '@noy-db/at-aws-kms'
|
|
39
|
+
* import { shamirRecoveryProvider } from '@noy-db/on-shamir'
|
|
40
|
+
*
|
|
41
|
+
* const db = await createNoydb({
|
|
42
|
+
* store,
|
|
43
|
+
* user: 'alice',
|
|
44
|
+
* passphraseMode: 'managed',
|
|
45
|
+
* sealingKey: awsKmsSealingProvider({ keyId: 'arn:aws:kms:us-east-1:123:key/abc' }),
|
|
46
|
+
* shamirRecovery: shamirRecoveryProvider(),
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @packageDocumentation
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/** Options for {@link awsKmsSealingProvider}. */
|
|
54
|
+
interface AwsKmsSealingProviderOptions {
|
|
55
|
+
/** KMS key id or ARN (e.g. `arn:aws:kms:us-east-1:123:key/abc`). */
|
|
56
|
+
readonly keyId: string;
|
|
57
|
+
/** Optional pre-built client (DI for tests). Default `new KMSClient({})` (ambient creds). */
|
|
58
|
+
readonly client?: Pick<KMSClient, 'send'>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build a {@link SealingKeyProvider} backed by AWS KMS Encrypt / Decrypt.
|
|
62
|
+
*
|
|
63
|
+
* Credentials are resolved by the SDK's ambient chain — IAM instance roles,
|
|
64
|
+
* environment variables, or `~/.aws/credentials`. Never pass raw credentials
|
|
65
|
+
* in the options; inject a pre-configured client for non-default auth instead.
|
|
66
|
+
*
|
|
67
|
+
* @throws Error when KMS returns no ciphertext or no plaintext (guards
|
|
68
|
+
* against unexpected SDK-response shapes).
|
|
69
|
+
* Any KMS API error (AccessDenied, InvalidKeyUsage, etc.) propagates as-is.
|
|
70
|
+
*/
|
|
71
|
+
declare function awsKmsSealingProvider(opts: AwsKmsSealingProviderOptions): SealingKeyProvider;
|
|
72
|
+
|
|
73
|
+
export { type AwsKmsSealingProviderOptions, awsKmsSealingProvider };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { SealingKeyProvider } from '@noy-db/hub';
|
|
2
|
+
import { KMSClient } from '@aws-sdk/client-kms';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* **@noy-db/at-aws-kms** — AWS KMS sealing key provider for noy-db
|
|
6
|
+
* managed-passphrase mode (#188).
|
|
7
|
+
*
|
|
8
|
+
* An `at-*` provider that seals and unseals the hub-generated random
|
|
9
|
+
* passphrase via AWS KMS Encrypt / Decrypt. Every seal and unseal is an
|
|
10
|
+
* authenticated KMS API call, giving you a CloudTrail-backed access log of
|
|
11
|
+
* every time a user's vault is opened — no additional instrumentation
|
|
12
|
+
* required.
|
|
13
|
+
*
|
|
14
|
+
* ## When to use
|
|
15
|
+
*
|
|
16
|
+
* - Compliance regimes requiring auditable key access logs (FedRAMP, HIPAA
|
|
17
|
+
* with managed-encryption requirements, SOC 2 Type II).
|
|
18
|
+
* - Workloads already running on AWS where a KMS key costs less than
|
|
19
|
+
* engineering an equivalent audit trail.
|
|
20
|
+
* - Any case where you want automatic CMK rotation without rotating your
|
|
21
|
+
* app's sealing key material manually.
|
|
22
|
+
*
|
|
23
|
+
* ## Setup
|
|
24
|
+
*
|
|
25
|
+
* ```bash
|
|
26
|
+
* # 1. Create a KMS key (one-time, in your AWS console or CLI):
|
|
27
|
+
* aws kms create-key --description "noy-db sealing key"
|
|
28
|
+
* # Note the KeyId/ARN from the output.
|
|
29
|
+
*
|
|
30
|
+
* # 2. Grant the host's IAM role kms:Encrypt + kms:Decrypt on that key.
|
|
31
|
+
* # Credentials are picked up automatically from the SDK's ambient chain
|
|
32
|
+
* # (IAM role, ~/.aws/credentials, env vars — see AWS SDK docs).
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* // 3. In your app:
|
|
37
|
+
* import { createNoydb } from '@noy-db/hub'
|
|
38
|
+
* import { awsKmsSealingProvider } from '@noy-db/at-aws-kms'
|
|
39
|
+
* import { shamirRecoveryProvider } from '@noy-db/on-shamir'
|
|
40
|
+
*
|
|
41
|
+
* const db = await createNoydb({
|
|
42
|
+
* store,
|
|
43
|
+
* user: 'alice',
|
|
44
|
+
* passphraseMode: 'managed',
|
|
45
|
+
* sealingKey: awsKmsSealingProvider({ keyId: 'arn:aws:kms:us-east-1:123:key/abc' }),
|
|
46
|
+
* shamirRecovery: shamirRecoveryProvider(),
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @packageDocumentation
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/** Options for {@link awsKmsSealingProvider}. */
|
|
54
|
+
interface AwsKmsSealingProviderOptions {
|
|
55
|
+
/** KMS key id or ARN (e.g. `arn:aws:kms:us-east-1:123:key/abc`). */
|
|
56
|
+
readonly keyId: string;
|
|
57
|
+
/** Optional pre-built client (DI for tests). Default `new KMSClient({})` (ambient creds). */
|
|
58
|
+
readonly client?: Pick<KMSClient, 'send'>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build a {@link SealingKeyProvider} backed by AWS KMS Encrypt / Decrypt.
|
|
62
|
+
*
|
|
63
|
+
* Credentials are resolved by the SDK's ambient chain — IAM instance roles,
|
|
64
|
+
* environment variables, or `~/.aws/credentials`. Never pass raw credentials
|
|
65
|
+
* in the options; inject a pre-configured client for non-default auth instead.
|
|
66
|
+
*
|
|
67
|
+
* @throws Error when KMS returns no ciphertext or no plaintext (guards
|
|
68
|
+
* against unexpected SDK-response shapes).
|
|
69
|
+
* Any KMS API error (AccessDenied, InvalidKeyUsage, etc.) propagates as-is.
|
|
70
|
+
*/
|
|
71
|
+
declare function awsKmsSealingProvider(opts: AwsKmsSealingProviderOptions): SealingKeyProvider;
|
|
72
|
+
|
|
73
|
+
export { type AwsKmsSealingProviderOptions, awsKmsSealingProvider };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
KMSClient,
|
|
4
|
+
EncryptCommand,
|
|
5
|
+
DecryptCommand
|
|
6
|
+
} from "@aws-sdk/client-kms";
|
|
7
|
+
function awsKmsSealingProvider(opts) {
|
|
8
|
+
const client = opts.client ?? new KMSClient({});
|
|
9
|
+
return {
|
|
10
|
+
id: `aws-kms:${opts.keyId}`,
|
|
11
|
+
async seal(passphrase) {
|
|
12
|
+
const out = await client.send(
|
|
13
|
+
new EncryptCommand({ KeyId: opts.keyId, Plaintext: passphrase })
|
|
14
|
+
);
|
|
15
|
+
const blob = out.CiphertextBlob;
|
|
16
|
+
if (!blob) throw new Error("@noy-db/at-aws-kms: KMS Encrypt returned no CiphertextBlob");
|
|
17
|
+
return blob instanceof Uint8Array ? blob : new Uint8Array(blob);
|
|
18
|
+
},
|
|
19
|
+
async unseal(sealed) {
|
|
20
|
+
const out = await client.send(
|
|
21
|
+
new DecryptCommand({ CiphertextBlob: sealed, KeyId: opts.keyId })
|
|
22
|
+
);
|
|
23
|
+
const pt = out.Plaintext;
|
|
24
|
+
if (!pt) throw new Error("@noy-db/at-aws-kms: KMS Decrypt returned no Plaintext");
|
|
25
|
+
return pt instanceof Uint8Array ? pt : new Uint8Array(pt);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
awsKmsSealingProvider
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * **@noy-db/at-aws-kms** — AWS KMS sealing key provider for noy-db\n * managed-passphrase mode (#188).\n *\n * An `at-*` provider that seals and unseals the hub-generated random\n * passphrase via AWS KMS Encrypt / Decrypt. Every seal and unseal is an\n * authenticated KMS API call, giving you a CloudTrail-backed access log of\n * every time a user's vault is opened — no additional instrumentation\n * required.\n *\n * ## When to use\n *\n * - Compliance regimes requiring auditable key access logs (FedRAMP, HIPAA\n * with managed-encryption requirements, SOC 2 Type II).\n * - Workloads already running on AWS where a KMS key costs less than\n * engineering an equivalent audit trail.\n * - Any case where you want automatic CMK rotation without rotating your\n * app's sealing key material manually.\n *\n * ## Setup\n *\n * ```bash\n * # 1. Create a KMS key (one-time, in your AWS console or CLI):\n * aws kms create-key --description \"noy-db sealing key\"\n * # Note the KeyId/ARN from the output.\n *\n * # 2. Grant the host's IAM role kms:Encrypt + kms:Decrypt on that key.\n * # Credentials are picked up automatically from the SDK's ambient chain\n * # (IAM role, ~/.aws/credentials, env vars — see AWS SDK docs).\n * ```\n *\n * ```ts\n * // 3. In your app:\n * import { createNoydb } from '@noy-db/hub'\n * import { awsKmsSealingProvider } from '@noy-db/at-aws-kms'\n * import { shamirRecoveryProvider } from '@noy-db/on-shamir'\n *\n * const db = await createNoydb({\n * store,\n * user: 'alice',\n * passphraseMode: 'managed',\n * sealingKey: awsKmsSealingProvider({ keyId: 'arn:aws:kms:us-east-1:123:key/abc' }),\n * shamirRecovery: shamirRecoveryProvider(),\n * })\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { SealingKeyProvider } from '@noy-db/hub'\nimport {\n KMSClient,\n EncryptCommand,\n DecryptCommand,\n type EncryptCommandOutput,\n type DecryptCommandOutput,\n} from '@aws-sdk/client-kms'\n\n/** Options for {@link awsKmsSealingProvider}. */\nexport interface AwsKmsSealingProviderOptions {\n /** KMS key id or ARN (e.g. `arn:aws:kms:us-east-1:123:key/abc`). */\n readonly keyId: string\n /** Optional pre-built client (DI for tests). Default `new KMSClient({})` (ambient creds). */\n readonly client?: Pick<KMSClient, 'send'>\n}\n\n/**\n * Build a {@link SealingKeyProvider} backed by AWS KMS Encrypt / Decrypt.\n *\n * Credentials are resolved by the SDK's ambient chain — IAM instance roles,\n * environment variables, or `~/.aws/credentials`. Never pass raw credentials\n * in the options; inject a pre-configured client for non-default auth instead.\n *\n * @throws Error when KMS returns no ciphertext or no plaintext (guards\n * against unexpected SDK-response shapes).\n * Any KMS API error (AccessDenied, InvalidKeyUsage, etc.) propagates as-is.\n */\nexport function awsKmsSealingProvider(opts: AwsKmsSealingProviderOptions): SealingKeyProvider {\n const client = opts.client ?? new KMSClient({})\n return {\n id: `aws-kms:${opts.keyId}`,\n\n async seal(passphrase) {\n const out: EncryptCommandOutput = await client.send(\n new EncryptCommand({ KeyId: opts.keyId, Plaintext: passphrase }),\n )\n const blob = out.CiphertextBlob\n if (!blob) throw new Error('@noy-db/at-aws-kms: KMS Encrypt returned no CiphertextBlob')\n return blob instanceof Uint8Array ? blob : new Uint8Array(blob)\n },\n\n async unseal(sealed) {\n const out: DecryptCommandOutput = await client.send(\n new DecryptCommand({ CiphertextBlob: sealed, KeyId: opts.keyId }),\n )\n const pt = out.Plaintext\n if (!pt) throw new Error('@noy-db/at-aws-kms: KMS Decrypt returned no Plaintext')\n return pt instanceof Uint8Array ? pt : new Uint8Array(pt)\n },\n }\n}\n"],"mappings":";AAkDA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAqBA,SAAS,sBAAsB,MAAwD;AAC5F,QAAM,SAAS,KAAK,UAAU,IAAI,UAAU,CAAC,CAAC;AAC9C,SAAO;AAAA,IACL,IAAI,WAAW,KAAK,KAAK;AAAA,IAEzB,MAAM,KAAK,YAAY;AACrB,YAAM,MAA4B,MAAM,OAAO;AAAA,QAC7C,IAAI,eAAe,EAAE,OAAO,KAAK,OAAO,WAAW,WAAW,CAAC;AAAA,MACjE;AACA,YAAM,OAAO,IAAI;AACjB,UAAI,CAAC,KAAM,OAAM,IAAI,MAAM,4DAA4D;AACvF,aAAO,gBAAgB,aAAa,OAAO,IAAI,WAAW,IAAI;AAAA,IAChE;AAAA,IAEA,MAAM,OAAO,QAAQ;AACnB,YAAM,MAA4B,MAAM,OAAO;AAAA,QAC7C,IAAI,eAAe,EAAE,gBAAgB,QAAQ,OAAO,KAAK,MAAM,CAAC;AAAA,MAClE;AACA,YAAM,KAAK,IAAI;AACf,UAAI,CAAC,GAAI,OAAM,IAAI,MAAM,uDAAuD;AAChF,aAAO,cAAc,aAAa,KAAK,IAAI,WAAW,EAAE;AAAA,IAC1D;AAAA,EACF;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@noy-db/at-aws-kms",
|
|
3
|
+
"version": "0.2.0-pre.1",
|
|
4
|
+
"description": "AWS KMS sealing key provider for noy-db managed-passphrase mode — seal/unseal via KMS Encrypt/Decrypt, with KMS access logs.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "vLannaAi <vicio@lanna.ai>",
|
|
7
|
+
"homepage": "https://github.com/vLannaAi/noy-db/tree/main/packages/at-aws-kms#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/vLannaAi/noy-db.git",
|
|
11
|
+
"directory": "packages/at-aws-kms"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/vLannaAi/noy-db/issues"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"require": {
|
|
25
|
+
"types": "./dist/index.d.cts",
|
|
26
|
+
"default": "./dist/index.cjs"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"main": "./dist/index.cjs",
|
|
31
|
+
"module": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18.0.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@aws-sdk/client-kms": "^3.0.0",
|
|
43
|
+
"@noy-db/hub": "0.2.0-pre.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "^22.0.0",
|
|
47
|
+
"@aws-sdk/client-kms": "^3.0.0",
|
|
48
|
+
"@noy-db/on-shamir": "0.2.0-pre.1",
|
|
49
|
+
"@noy-db/hub": "0.2.0-pre.1",
|
|
50
|
+
"@noy-db/to-memory": "0.2.0-pre.1"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"noy-db",
|
|
54
|
+
"at-aws-kms",
|
|
55
|
+
"aws-kms",
|
|
56
|
+
"kms",
|
|
57
|
+
"sealing-key-provider",
|
|
58
|
+
"managed-passphrase",
|
|
59
|
+
"encryption",
|
|
60
|
+
"zero-knowledge"
|
|
61
|
+
],
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public",
|
|
64
|
+
"tag": "latest"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "tsup",
|
|
68
|
+
"test": "vitest run",
|
|
69
|
+
"lint": "eslint src/",
|
|
70
|
+
"typecheck": "tsc --noEmit"
|
|
71
|
+
}
|
|
72
|
+
}
|