{"id":50115776,"url":"https://github.com/ankkho/nestjs-cipher","last_synced_at":"2026-05-23T15:05:08.493Z","repository":{"id":354835221,"uuid":"1225450359","full_name":"ankkho/nestjs-cipher","owner":"ankkho","description":"NestJS module: AES-256-GCM envelope encryption with multi-tenant KMS support","archived":false,"fork":false,"pushed_at":"2026-05-12T08:42:23.000Z","size":295,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-12T10:36:54.394Z","etag":null,"topics":["aes-256-gcm","aws","azure","backend","encryption","gcp","kms","multi-tenant","nestjs","nestjs-module","nodejs","pii","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ankkho.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-30T09:37:37.000Z","updated_at":"2026-05-12T08:42:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ankkho/nestjs-cipher","commit_stats":null,"previous_names":["ankkho/nestjs-cipher"],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/ankkho/nestjs-cipher","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankkho%2Fnestjs-cipher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankkho%2Fnestjs-cipher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankkho%2Fnestjs-cipher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankkho%2Fnestjs-cipher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ankkho","download_url":"https://codeload.github.com/ankkho/nestjs-cipher/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankkho%2Fnestjs-cipher/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33400262,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes-256-gcm","aws","azure","backend","encryption","gcp","kms","multi-tenant","nestjs","nestjs-module","nodejs","pii","typescript"],"created_at":"2026-05-23T15:04:45.927Z","updated_at":"2026-05-23T15:05:08.085Z","avatar_url":"https://github.com/ankkho.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nestjs-cipher\n\n![TypeScript](https://img.shields.io/badge/TypeScript-5.9+-blue) ![NestJS](https://img.shields.io/badge/NestJS-11-red) ![Node.js](https://img.shields.io/badge/Node.js-20+-green) ![pnpm](https://img.shields.io/badge/pnpm-10.32+-F69D3D) ![License](https://img.shields.io/badge/License-MIT-yellow)\n\n\u003e Production-grade NestJS encryption module. Encrypt sensitive data (emails, PII, tokens) with **AES-256-GCM** + **Google Cloud KMS** (AWS/Azure coming soon). Local mode for development.\n\n## Table of Contents\n\n- [Features](#features)\n- [Providers](#providers)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Configuration](#configuration)\n- [How It Works](#how-it-works)\n- [Multi-Tenant Architecture](#multi-tenant-architecture)\n- [Observability](#observability)\n- [Security Best Practices](#security-best-practices)\n- [Testing with Example](#testing-with-example)\n- [Troubleshooting](#troubleshooting)\n- [Production Deployment](#production-deployment)\n- [Infrastructure (OpenTofu)](#infrastructure-opentofu)\n- [Development](#development)\n- [Resources](#resources)\n\n## Features\n\n- **Envelope Encryption:** AES-256-GCM local encryption with optional KMS key wrapping\n- **Zero-Trust DEK:** Data Encryption Keys zeroed from memory after each operation\n- **DEK Caching:** Unwrapped DEKs cached in-memory (5 min TTL) to skip KMS on repeated reads\n- **Multi-Tenant:** Automatic tenant/user-level key isolation\n- **Fast:** ~10-20ms per operation (90% local, minimal KMS calls)\n- **Observable:** Pino logging + OpenTelemetry instrumentation\n- **Production-Ready:** Full TypeScript, CI/CD validated\n\n## Providers\n\n`nestjs-cipher` supports multiple KMS providers. Choose based on your deployment environment:\n\n| Provider | Use Case | Setup | Key Rotation | Compliance |\n| --- | --- | --- | --- | --- |\n| **LOCAL** | Development \u0026 testing | None | Manual | None |\n| **GCP_KMS** | Production (recommended) | Medium | Auto (90d) | SOC 2, ISO 27001, PCI-DSS |\n\n**LOCAL** — In-memory keys; no persistence. Dev and CI/CD only.\n\n**GCP_KMS** — Enterprise-grade key management with audit logging, auto-rotation, and multi-region support. Note: GCP Cloud KMS is a paid service.\n\n**Coming Soon:** AWS KMS, Azure Key Vault\n\n## Installation\n\n```bash\npnpm install @ankkho/nestjs-cipher\n```\n\n**Requirements:**\n- Node.js 20.0.0 LTS or higher\n- pnpm 10.32.0+\n\n## Quick Start\n\n### ⭐ ConfigService (Recommended)\n\nAll environment variables via **NestJS ConfigService**:\n\n```typescript\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { CipherModule, Providers } from '@ankkho/nestjs-cipher';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot(),\n    CipherModule.forRootAsync({\n      imports: [ConfigModule],\n      inject: [ConfigService],\n      useFactory: (config: ConfigService) =\u003e ({\n        provider: Providers.GCP_KMS,\n        gcp: {\n          projectId: config.getOrThrow('GCP_KMS_PROJECT_ID'),\n          keyRing: config.getOrThrow('GCP_KMS_KEY_RING'),\n          location: config.getOrThrow('GCP_KMS_LOCATION'),\n        },\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n**Environment:** `.env`\n```bash\nGCP_KMS_PROJECT_ID=my-project\nGCP_KMS_LOCATION=us-central1\nGCP_KMS_KEY_RING=pii-ring\n```\n\n### LocalProvider (Development Only)\n\n```typescript\nimport { CipherModule, Providers } from '@ankkho/nestjs-cipher';\n\n@Module({\n  imports: [CipherModule.forRoot({ provider: Providers.LOCAL })],\n})\nexport class AppModule {}\n```\n\n**⚠️ In-memory keys only.** Not for production.\n\n### Use Service\n\n```typescript\nimport { CipherService } from '@ankkho/nestjs-cipher';\n\n@Injectable()\nexport class UserService {\n  constructor(private cipher: CipherService) {}\n\n  async createUser(email: string, tenantId: string) {\n    const encrypted = await this.cipher.encrypt(email, { tenantId });\n    await db.users.create({ email_encrypted: encrypted });\n  }\n\n  async getUser(userId: string) {\n    const stored = await db.users.findOne(userId);\n    const email = await this.cipher.decrypt(stored.email_encrypted, {\n      tenantId: stored.tenant_id,\n    });\n    return { ...stored, email };\n  }\n}\n```\n\n## Configuration\n\n### GCP KMS\n\n**Credentials:** Uses [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/application-default-credentials).\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json\n# OR\ngcloud auth application-default login\n```\n\n**Permissions:** Service account requires `roles/cloudkms.cryptographer`.\n\n### Local (Development)\n\nNo setup required. Keys stored in-memory only.\n\n## How It Works\n\n```\n1. Generate random 32-byte DEK\n2. Encrypt plaintext locally (AES-256-GCM)\n3. Wrap DEK with KMS\n4. Zero DEK from memory\n5. Return: { v, ciphertext, wrappedDek, iv, tag }\n```\n\n**Requirements:**\n- At least one of `tenantId` or `userId` required\n- Same context for encrypt \u0026 decrypt\n- `wrappedDek` safe to store (encrypted by KMS)\n- DEK never persisted; zeroed after each operation\n\n**Payload:**\n```json\n{\n  \"v\": 1,\n  \"ciphertext\": \"...\",\n  \"wrappedDek\": \"...\",\n  \"iv\": \"...\",\n  \"tag\": \"...\"\n}\n```\n\n**Versioning:** Use `v` field for algorithm migrations. Decrypt old `v:1` → re-encrypt to `v:2` during background jobs.\n\n## Multi-Tenant Architecture\n\nEach tenant gets a distinct KMS key:\n\n```\ntenantId: 'org-100' → .../cryptoKeys/tenant-org-100\nuserId: 'usr-42'    → .../cryptoKeys/user-usr-42\n```\n\n**Result:** Tenant A cannot decrypt Tenant B's data.\n\n**Envelope Encryption Benefits:**\n- Generate random DEK per operation\n- Encrypt data locally (AES-256-GCM)\n- Wrap DEK once with KMS\n- Single KMS call per operation → cost-effective at scale\n\n## Observability\n\nOpenTelemetry spans: `nestjs-cipher.encrypt`, `nestjs-cipher.decrypt`\n\n**Attributes:**\n- `cipher.provider` — KMS provider (e.g., `GCP_KMS`)\n- `cipher.context.type` — `tenant` or `user`\n- `cipher.payload.version` — Payload version\n\n**Setup:** Automatic if OTel SDK is configured.\n\n## Security Best Practices\n\n1. ✅ Store credentials in secure vault; never commit keys\n2. ✅ Grant service account least privilege (`roles/cloudkms.cryptographer` only)\n3. ✅ Enable automatic key rotation (90 days recommended)\n4. ✅ Monitor Cloud Audit Logs for unauthorized access\n5. ✅ Use TLS for all communication\n\n## Testing with Example\n\n### LocalProvider (Development)\n\n```bash\npnpm build:example \u0026\u0026 pnpm example\n```\n\n### GCP KMS with OpenTofu (Production)\n\nFull setup with infrastructure provisioning:\n\n```bash\ncd example/tofu-gcp \u0026\u0026 source .env.gcp \u0026\u0026 pnpm build \u0026\u0026 pnpm example:gcp\n```\n\nSee [example/tofu-gcp/README.md](./example/tofu-gcp/README.md) for details.\n\n## Troubleshooting\n\n| Issue | Solution |\n| --- | --- |\n| Module fails at startup | Check credentials are set and have correct KMS permissions |\n| Decryption fails | Verify same `tenantId`/`userId` context used for encrypt \u0026 decrypt |\n| High latency | Check network connectivity to KMS provider; DEK caching is built-in (5 min TTL) |\n| Credential validation errors | Ensure `GOOGLE_APPLICATION_CREDENTIALS` is set or `gcloud auth application-default login` run |\n\n## Production Deployment\n\n- Use `Providers.GCP_KMS` (not Local)\n- Store credentials in secure vault (GCP Secret Manager, Vault, etc.)\n- Grant service account `roles/cloudkms.cryptographer` only\n- Enable Cloud Audit Logs for monitoring\n- Set up alerts for KMS API errors and quota\n- Create keys in multiple regions for failover\n- Rotate credentials immediately if compromised\n\n## Infrastructure (OpenTofu)\n\n\u003e Environments: `dev`, `test`, `stage`, `prod`.\n\nGCP KMS infrastructure is provisioned with [OpenTofu](https://opentofu.org/).\n\nProvider: [`GCP KMS`](./infra/tofu/gcp/README.md).\n\n## Development\n\n### Requirements\n- Node.js 20.0.0 LTS or higher\n- pnpm 10.32.0+\n\n### Commands\n\n```bash\n# Install dependencies\npnpm install\n\n# Build library\npnpm build\n\n# Build example\npnpm build:example\n\n# Run example (compiled code)\npnpm example\n\n# Run tests\npnpm test\n\n# Lint and format\npnpm lint:fix\n\n# Type check\npnpm typecheck\n```\n\nSee [.github/README.md](.github/README.md) for CI/CD and repository best practices.\n\n## Resources\n\n- [Contributing](./CONTRIBUTING.md) — Contribution guidelines\n- [Release Process](./RELEASE_README.md) — Automated release workflow\n- [Security Policy](./.github/SECURITY.md) — Security \u0026 reporting\n- [Example](./example) — Working sample\n- [Infrastructure (OpenTofu)](./infra/tofu/gcp/README.md) — GCP KMS setup\n\n## License\n\nMIT\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fankkho%2Fnestjs-cipher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fankkho%2Fnestjs-cipher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fankkho%2Fnestjs-cipher/lists"}