@faizahmed/secret-keystore 1.1.0 → 1.1.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 (3) hide show
  1. package/README.md +20 -11
  2. package/SECURITY.md +20 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -12,6 +12,15 @@ A secure secrets management library for Node.js applications using AWS KMS encry
12
12
 
13
13
  > **Design principle:** the only thing a developer ever handles is a **KMS Key ID** — which is *not* a secret. No private keys, no passphrases, no key material. AWS KMS holds all key material server-side and authorizes access via IAM, and decrypted values live **only in memory** (never in `process.env`, never on disk) to keep the blast radius of any RCE as small as possible.
14
14
 
15
+ ## Guides & Deep-Dives
16
+
17
+ A full walkthrough lives on the blog, as part of the ***[Mastering Encryption](https://blog.faizahmed.in/series/encryption)*** series:
18
+
19
+ - **[Encrypted .env for Node.js with AWS KMS: The Complete Guide](https://blog.faizahmed.in/encrypted-env-aws-kms-nodejs-complete-guide)** — the overview and map.
20
+ - **[Your .env Is a Loaded Gun: A Saner Threat Model for Node.js Secrets](https://blog.faizahmed.in/nodejs-secrets-threat-model-aws-kms)** — why `process.env` is the problem.
21
+ - **[Encrypt Your .env with One Command: The secret-keystore CLI](https://blog.faizahmed.in/secret-keystore-cli-encrypt-env-aws-kms)** — every CLI command, hands-on.
22
+ - **[Loading Secrets at Runtime Without Leaking Them](https://blog.faizahmed.in/secret-keystore-runtime-config-loader-nodejs)** — `config()`, the keystore, rotation, and Nitro attestation.
23
+
15
24
  ## Table of Contents
16
25
 
17
26
  - [Features](#features)
@@ -201,7 +210,7 @@ npm pack
201
210
  # pnpm
202
211
  pnpm pack
203
212
 
204
- # This creates: faizahmedfarooqui-secret-keystore-1.0.0.tgz (scoped package name)
213
+ # This creates: faizahmed-secret-keystore-1.1.1.tgz (scoped package name)
205
214
  ```
206
215
 
207
216
  Or use the provided script:
@@ -217,14 +226,14 @@ In your consumer project:
217
226
 
218
227
  ```bash
219
228
  # Copy the tarball to your project
220
- cp ../secret-keystore/faizahmedfarooqui-secret-keystore-1.0.0.tgz ./
229
+ cp ../secret-keystore/faizahmed-secret-keystore-1.1.1.tgz ./
221
230
 
222
231
  # Install from tarball
223
232
  # npm
224
- npm install ./faizahmedfarooqui-secret-keystore-1.0.0.tgz
233
+ npm install ./faizahmed-secret-keystore-1.1.1.tgz
225
234
 
226
235
  # pnpm
227
- pnpm add ./faizahmedfarooqui-secret-keystore-1.0.0.tgz
236
+ pnpm add ./faizahmed-secret-keystore-1.1.1.tgz
228
237
  ```
229
238
 
230
239
  Or add a script to your consumer's `package.json`:
@@ -233,7 +242,7 @@ Or add a script to your consumer's `package.json`:
233
242
  {
234
243
  "scripts": {
235
244
  "pack:keystore": "cd ../secret-keystore && npm pack --pack-destination ../your-project",
236
- "install:keystore": "npm run pack:keystore && npm install ./faizahmedfarooqui-secret-keystore-*.tgz"
245
+ "install:keystore": "npm run pack:keystore && npm install ./faizahmed-secret-keystore-*.tgz"
237
246
  }
238
247
  }
239
248
  ```
@@ -245,7 +254,7 @@ After installing, your `package.json` will reference the local tarball:
245
254
  ```json
246
255
  {
247
256
  "dependencies": {
248
- "@faizahmed/secret-keystore": "file:./faizahmedfarooqui-secret-keystore-1.0.0.tgz"
257
+ "@faizahmed/secret-keystore": "file:./faizahmed-secret-keystore-1.1.1.tgz"
249
258
  }
250
259
  }
251
260
  ```
@@ -263,7 +272,7 @@ WORKDIR /app
263
272
  COPY package.json yarn.lock ./
264
273
 
265
274
  # Copy the local tarball (must be in the Docker build context)
266
- COPY faizahmedfarooqui-secret-keystore-1.0.0.tgz ./
275
+ COPY faizahmed-secret-keystore-1.1.1.tgz ./
267
276
 
268
277
  # Install dependencies (tarball is referenced in package.json)
269
278
  RUN yarn install --frozen-lockfile
@@ -277,18 +286,18 @@ RUN yarn install --frozen-lockfile
277
286
  # 1. In the keystore library directory
278
287
  cd secret-keystore
279
288
  npm pack # or: pnpm pack
280
- mv faizahmedfarooqui-secret-keystore-*.tgz ../your-consumer-project/
289
+ mv faizahmed-secret-keystore-*.tgz ../your-consumer-project/
281
290
 
282
291
  # 2. In your consumer project
283
292
  cd ../your-consumer-project
284
293
 
285
294
  # Update package.json to reference the tarball
286
- # "dependencies": { "@faizahmed/secret-keystore": "file:./faizahmedfarooqui-secret-keystore-1.0.0.tgz" }
295
+ # "dependencies": { "@faizahmed/secret-keystore": "file:./faizahmed-secret-keystore-1.1.1.tgz" }
287
296
 
288
297
  npm install # or: pnpm install
289
298
 
290
299
  # 3. Commit the tarball to your repo (for CI/CD)
291
- git add faizahmedfarooqui-secret-keystore-*.tgz
300
+ git add faizahmed-secret-keystore-*.tgz
292
301
  git commit -m "Add @faizahmed/secret-keystore tarball for Docker builds"
293
302
  ```
294
303
 
@@ -398,7 +407,7 @@ bootstrap();
398
407
  ## CLI Reference
399
408
 
400
409
  ```bash
401
- npx @faizahmed/secret-keystore <encrypt|decrypt> [options]
410
+ npx @faizahmed/secret-keystore <command> [options]
402
411
  ```
403
412
 
404
413
  ### Commands
package/SECURITY.md CHANGED
@@ -9,6 +9,7 @@ This document explains the security model of [`@faizahmed/secret-keystore`](http
9
9
  - [Overview](#overview)
10
10
  - [Threat Scenarios](#threat-scenarios)
11
11
  - [Security Layers](#security-layers)
12
+ - [CLI Security Notes](#cli-security-notes)
12
13
  - [Security-First Dependency Policy](#security-first-dependency-policy)
13
14
  - [Nitro Enclave Attestation](#nitro-enclave-attestation)
14
15
  - [Full Attestation Flow](#full-attestation-flow)
@@ -79,7 +80,7 @@ Even with both:
79
80
  ```mermaid
80
81
  flowchart TB
81
82
  subgraph CONFIG["Config File"]
82
- A["DB_PASSWORD=ENC[AQICAHh...encrypted...]"]
83
+ A["DB_PASSWORD=ENC#91;AQICAHh...encrypted...#93;"]
83
84
  end
84
85
 
85
86
  subgraph KMS["AWS KMS"]
@@ -122,6 +123,22 @@ flowchart TB
122
123
  - Accessible only via `keyStore.get()` API
123
124
  - Secure memory wipe on `destroy()`
124
125
 
126
+ The zero-config **`config()`** loader follows the same rule. It discovers and cascades your `.env` files (`.env` → `.env.local` → `.env.<NODE_ENV>` → `.env.<NODE_ENV>.local`), decrypts them via KMS, and loads everything into the in-memory keystore it returns. Nothing decrypted is written to disk, and nothing is placed in `process.env`.
127
+
128
+ > **⚠️ `populateProcessEnv` is a deliberate footgun.** `config({ populateProcessEnv: true })` copies decrypted values into `process.env` for drop-in `dotenv` compatibility. This **re-introduces the bulk-exposure blast radius this library exists to remove** — a single `env` dump or `/proc/[pid]/environ` read would leak everything. It is **off by default**, emits a runtime warning when enabled, and should be avoided in production. Prefer reading from the returned keystore via `.get()`.
129
+
130
+ ## CLI Security Notes
131
+
132
+ The CLI commands keep the same blast-radius discipline, with a couple of deliberate, time-boxed exceptions worth understanding:
133
+
134
+ | Command | Security note |
135
+ |---------|---------------|
136
+ | `encrypt` / `decrypt` | `decrypt` writes plaintext to disk (in place or `--output`). To *run* an app, prefer `run` or `config()` so plaintext never lands on disk. |
137
+ | `run` | Decrypts and launches your command with secrets in the **child process's** environment. The parent never holds them — but code inside the child can read them via `env`, which is unavoidable for any process runner. Use `config()` if you can modify the app and want secrets to stay out of `process.env` entirely. |
138
+ | `edit` | Decrypts into a `0600`-permission temp file, opens `$EDITOR`, re-encrypts on save, then overwrites and deletes (shreds) the temp file. Plaintext exists on disk only while the editor is open. |
139
+ | `rotate` | Re-encrypts already-encrypted values under a new KMS Key ID (decrypting with the old key in a single pass). Plaintext is only ever held in memory. Use it after suspected key exposure. |
140
+ | `keys` / `status` | Read-only inspection. They print key names and encrypted/plaintext status only — **never secret values** — so they're safe to use in CI and logs. |
141
+
125
142
  ## Security-First Dependency Policy
126
143
 
127
144
  > **Critical Decision:** This library intentionally avoids third-party dependencies for all security-sensitive operations.
@@ -468,6 +485,7 @@ const keyStore = await createSecretKeyStore(source, kmsKeyId, {
468
485
  | **Test Recovery** | Ensure you can recover if KMS access is lost |
469
486
  | **Document Key Policies** | Keep track of what each key policy allows |
470
487
  | **Rotate Secrets Regularly** | Re-encrypt with new values periodically |
488
+ | **Rotate KMS Keys** | Use `rotate --old-kms-key-id=... --kms-key-id=...` to re-encrypt under a new key, especially after suspected exposure |
471
489
 
472
490
  ## Security Checklist
473
491
 
@@ -487,6 +505,7 @@ const keyStore = await createSecretKeyStore(source, kmsKeyId, {
487
505
  - [ ] Secure memory wipe enabled (default)
488
506
  - [ ] In-memory AES-256-GCM encryption enabled (default)
489
507
  - [ ] No secrets logged, even in debug mode
508
+ - [ ] If using `config()`, `populateProcessEnv` left at its default (`false`) — secrets stay out of `process.env`
490
509
 
491
510
  ### Nitro Enclave Attestation (Maximum Security)
492
511
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faizahmed/secret-keystore",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Secure secrets management with AWS KMS encryption, in-memory keystore, and Nitro Enclave attestation support",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",