@memberjunction/encryption 0.0.1 → 2.129.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +391 -28
- package/dist/EncryptionEngine.d.ts +351 -0
- package/dist/EncryptionEngine.d.ts.map +1 -0
- package/dist/EncryptionEngine.js +683 -0
- package/dist/EncryptionEngine.js.map +1 -0
- package/dist/EncryptionKeySourceBase.d.ts +203 -0
- package/dist/EncryptionKeySourceBase.d.ts.map +1 -0
- package/dist/EncryptionKeySourceBase.js +133 -0
- package/dist/EncryptionKeySourceBase.js.map +1 -0
- package/dist/actions/EnableFieldEncryptionAction.d.ts +87 -0
- package/dist/actions/EnableFieldEncryptionAction.d.ts.map +1 -0
- package/dist/actions/EnableFieldEncryptionAction.js +308 -0
- package/dist/actions/EnableFieldEncryptionAction.js.map +1 -0
- package/dist/actions/RotateEncryptionKeyAction.d.ts +79 -0
- package/dist/actions/RotateEncryptionKeyAction.d.ts.map +1 -0
- package/dist/actions/RotateEncryptionKeyAction.js +343 -0
- package/dist/actions/RotateEncryptionKeyAction.js.map +1 -0
- package/dist/actions/index.d.ts +12 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +17 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +216 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +15 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/providers/AWSKMSKeySource.d.ts +110 -0
- package/dist/providers/AWSKMSKeySource.d.ts.map +1 -0
- package/dist/providers/AWSKMSKeySource.js +245 -0
- package/dist/providers/AWSKMSKeySource.js.map +1 -0
- package/dist/providers/AzureKeyVaultKeySource.d.ts +109 -0
- package/dist/providers/AzureKeyVaultKeySource.d.ts.map +1 -0
- package/dist/providers/AzureKeyVaultKeySource.js +268 -0
- package/dist/providers/AzureKeyVaultKeySource.js.map +1 -0
- package/dist/providers/ConfigFileKeySource.d.ts +173 -0
- package/dist/providers/ConfigFileKeySource.d.ts.map +1 -0
- package/dist/providers/ConfigFileKeySource.js +310 -0
- package/dist/providers/ConfigFileKeySource.js.map +1 -0
- package/dist/providers/EnvVarKeySource.d.ts +152 -0
- package/dist/providers/EnvVarKeySource.d.ts.map +1 -0
- package/dist/providers/EnvVarKeySource.js +251 -0
- package/dist/providers/EnvVarKeySource.js.map +1 -0
- package/package.json +65 -6
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Azure Key Vault encryption key source provider.
|
|
3
|
+
*
|
|
4
|
+
* This provider retrieves encryption keys from Azure Key Vault secrets.
|
|
5
|
+
* Keys are stored as base64-encoded strings in Key Vault secrets.
|
|
6
|
+
*
|
|
7
|
+
* ## Configuration
|
|
8
|
+
*
|
|
9
|
+
* The provider uses DefaultAzureCredential which supports:
|
|
10
|
+
* - Environment variables (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
|
|
11
|
+
* - Managed Identity (when running on Azure)
|
|
12
|
+
* - Azure CLI credentials
|
|
13
|
+
* - Visual Studio Code credentials
|
|
14
|
+
*
|
|
15
|
+
* ## Usage
|
|
16
|
+
*
|
|
17
|
+
* 1. Create a Key Vault in Azure
|
|
18
|
+
* 2. Store the encryption key as a base64-encoded secret
|
|
19
|
+
* 3. Set the KeyLookupValue to the vault URL and secret name
|
|
20
|
+
* 4. Ensure the application has Secret Get permission
|
|
21
|
+
*
|
|
22
|
+
* ## Lookup Value Format
|
|
23
|
+
*
|
|
24
|
+
* The KeyLookupValue should be in the format:
|
|
25
|
+
* `https://your-vault-name.vault.azure.net/secrets/secret-name`
|
|
26
|
+
*
|
|
27
|
+
* Or just the secret name if AZURE_KEYVAULT_URL is set:
|
|
28
|
+
* `my-encryption-key`
|
|
29
|
+
*
|
|
30
|
+
* ## Environment Variables
|
|
31
|
+
*
|
|
32
|
+
* - `AZURE_KEYVAULT_URL`: Default Key Vault URL (optional)
|
|
33
|
+
* - `AZURE_CLIENT_ID`: Service principal client ID (optional if using managed identity)
|
|
34
|
+
* - `AZURE_CLIENT_SECRET`: Service principal secret (optional if using managed identity)
|
|
35
|
+
* - `AZURE_TENANT_ID`: Azure AD tenant ID (optional if using managed identity)
|
|
36
|
+
*
|
|
37
|
+
* @module @memberjunction/encryption
|
|
38
|
+
*/
|
|
39
|
+
/// <reference types="node" />
|
|
40
|
+
import { EncryptionKeySourceBase } from '../EncryptionKeySourceBase';
|
|
41
|
+
/**
|
|
42
|
+
* Azure Key Vault key source provider.
|
|
43
|
+
*
|
|
44
|
+
* Retrieves encryption keys from Azure Key Vault secrets.
|
|
45
|
+
* Secrets should contain base64-encoded key material.
|
|
46
|
+
*
|
|
47
|
+
* ## Security Notes
|
|
48
|
+
*
|
|
49
|
+
* - Keys are stored encrypted at rest in Key Vault
|
|
50
|
+
* - Access is controlled by Azure RBAC or Key Vault access policies
|
|
51
|
+
* - All operations are logged in Azure Monitor
|
|
52
|
+
* - Supports secret versioning and soft-delete
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* // In database: KeyLookupValue = 'https://my-vault.vault.azure.net/secrets/mj-encryption-key'
|
|
57
|
+
* // Or if AZURE_KEYVAULT_URL is set: KeyLookupValue = 'mj-encryption-key'
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare class AzureKeyVaultKeySource extends EncryptionKeySourceBase {
|
|
61
|
+
private _clients;
|
|
62
|
+
private _initialized;
|
|
63
|
+
private _defaultVaultUrl;
|
|
64
|
+
/**
|
|
65
|
+
* Human-readable name for this key source.
|
|
66
|
+
*/
|
|
67
|
+
get SourceName(): string;
|
|
68
|
+
/**
|
|
69
|
+
* Initializes the Azure Key Vault client.
|
|
70
|
+
*
|
|
71
|
+
* Lazy-loads the Azure SDK to avoid requiring it when not used.
|
|
72
|
+
* Uses DefaultAzureCredential for authentication.
|
|
73
|
+
*/
|
|
74
|
+
Initialize(): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Validates that the Azure Key Vault client is properly configured.
|
|
77
|
+
*
|
|
78
|
+
* @returns true if the client is initialized
|
|
79
|
+
*/
|
|
80
|
+
ValidateConfiguration(): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Checks if a secret name/URL appears to be valid.
|
|
83
|
+
*
|
|
84
|
+
* @param lookupValue - The secret URL or name
|
|
85
|
+
* @returns true if the lookup value appears valid
|
|
86
|
+
*/
|
|
87
|
+
KeyExists(lookupValue: string): Promise<boolean>;
|
|
88
|
+
/**
|
|
89
|
+
* Retrieves encryption key material from Azure Key Vault.
|
|
90
|
+
*
|
|
91
|
+
* @param lookupValue - Secret URL or name (if AZURE_KEYVAULT_URL is set)
|
|
92
|
+
* @param keyVersion - Optional secret version (uses latest if not specified)
|
|
93
|
+
* @returns Buffer containing the key material
|
|
94
|
+
*
|
|
95
|
+
* @throws Error if the secret cannot be retrieved
|
|
96
|
+
*/
|
|
97
|
+
GetKey(lookupValue: string, keyVersion?: string): Promise<Buffer>;
|
|
98
|
+
/**
|
|
99
|
+
* Parses a lookup value into vault URL and secret name.
|
|
100
|
+
*
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
private parseLookupValue;
|
|
104
|
+
/**
|
|
105
|
+
* Cleans up Azure Key Vault clients.
|
|
106
|
+
*/
|
|
107
|
+
Dispose(): Promise<void>;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=AzureKeyVaultKeySource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AzureKeyVaultKeySource.d.ts","sourceRoot":"","sources":["../../src/providers/AzureKeyVaultKeySource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;;AAGH,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAMrE;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,sBAAuB,SAAQ,uBAAuB;IAC/D,OAAO,CAAC,QAAQ,CAA+F;IAC/G,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,gBAAgB,CAAuB;IAE/C;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;;;OAKG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA2BjC;;;;OAIG;IACH,qBAAqB,IAAI,OAAO;IAShC;;;;;OAKG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBtD;;;;;;;;OAQG;IACG,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA6EvE;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IA4BxB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAIjC"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Azure Key Vault encryption key source provider.
|
|
4
|
+
*
|
|
5
|
+
* This provider retrieves encryption keys from Azure Key Vault secrets.
|
|
6
|
+
* Keys are stored as base64-encoded strings in Key Vault secrets.
|
|
7
|
+
*
|
|
8
|
+
* ## Configuration
|
|
9
|
+
*
|
|
10
|
+
* The provider uses DefaultAzureCredential which supports:
|
|
11
|
+
* - Environment variables (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
|
|
12
|
+
* - Managed Identity (when running on Azure)
|
|
13
|
+
* - Azure CLI credentials
|
|
14
|
+
* - Visual Studio Code credentials
|
|
15
|
+
*
|
|
16
|
+
* ## Usage
|
|
17
|
+
*
|
|
18
|
+
* 1. Create a Key Vault in Azure
|
|
19
|
+
* 2. Store the encryption key as a base64-encoded secret
|
|
20
|
+
* 3. Set the KeyLookupValue to the vault URL and secret name
|
|
21
|
+
* 4. Ensure the application has Secret Get permission
|
|
22
|
+
*
|
|
23
|
+
* ## Lookup Value Format
|
|
24
|
+
*
|
|
25
|
+
* The KeyLookupValue should be in the format:
|
|
26
|
+
* `https://your-vault-name.vault.azure.net/secrets/secret-name`
|
|
27
|
+
*
|
|
28
|
+
* Or just the secret name if AZURE_KEYVAULT_URL is set:
|
|
29
|
+
* `my-encryption-key`
|
|
30
|
+
*
|
|
31
|
+
* ## Environment Variables
|
|
32
|
+
*
|
|
33
|
+
* - `AZURE_KEYVAULT_URL`: Default Key Vault URL (optional)
|
|
34
|
+
* - `AZURE_CLIENT_ID`: Service principal client ID (optional if using managed identity)
|
|
35
|
+
* - `AZURE_CLIENT_SECRET`: Service principal secret (optional if using managed identity)
|
|
36
|
+
* - `AZURE_TENANT_ID`: Azure AD tenant ID (optional if using managed identity)
|
|
37
|
+
*
|
|
38
|
+
* @module @memberjunction/encryption
|
|
39
|
+
*/
|
|
40
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
41
|
+
if (k2 === undefined) k2 = k;
|
|
42
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
43
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
44
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
45
|
+
}
|
|
46
|
+
Object.defineProperty(o, k2, desc);
|
|
47
|
+
}) : (function(o, m, k, k2) {
|
|
48
|
+
if (k2 === undefined) k2 = k;
|
|
49
|
+
o[k2] = m[k];
|
|
50
|
+
}));
|
|
51
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
52
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
53
|
+
}) : function(o, v) {
|
|
54
|
+
o["default"] = v;
|
|
55
|
+
});
|
|
56
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
57
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
58
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
59
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
60
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
61
|
+
};
|
|
62
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
63
|
+
if (mod && mod.__esModule) return mod;
|
|
64
|
+
var result = {};
|
|
65
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
66
|
+
__setModuleDefault(result, mod);
|
|
67
|
+
return result;
|
|
68
|
+
};
|
|
69
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
70
|
+
exports.AzureKeyVaultKeySource = void 0;
|
|
71
|
+
const global_1 = require("@memberjunction/global");
|
|
72
|
+
const EncryptionKeySourceBase_1 = require("../EncryptionKeySourceBase");
|
|
73
|
+
// Lazy-load Azure SDK to avoid requiring it when not used
|
|
74
|
+
let SecretClient = null;
|
|
75
|
+
let DefaultAzureCredential = null;
|
|
76
|
+
/**
|
|
77
|
+
* Azure Key Vault key source provider.
|
|
78
|
+
*
|
|
79
|
+
* Retrieves encryption keys from Azure Key Vault secrets.
|
|
80
|
+
* Secrets should contain base64-encoded key material.
|
|
81
|
+
*
|
|
82
|
+
* ## Security Notes
|
|
83
|
+
*
|
|
84
|
+
* - Keys are stored encrypted at rest in Key Vault
|
|
85
|
+
* - Access is controlled by Azure RBAC or Key Vault access policies
|
|
86
|
+
* - All operations are logged in Azure Monitor
|
|
87
|
+
* - Supports secret versioning and soft-delete
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* // In database: KeyLookupValue = 'https://my-vault.vault.azure.net/secrets/mj-encryption-key'
|
|
92
|
+
* // Or if AZURE_KEYVAULT_URL is set: KeyLookupValue = 'mj-encryption-key'
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
let AzureKeyVaultKeySource = class AzureKeyVaultKeySource extends EncryptionKeySourceBase_1.EncryptionKeySourceBase {
|
|
96
|
+
_clients = new Map();
|
|
97
|
+
_initialized = false;
|
|
98
|
+
_defaultVaultUrl = null;
|
|
99
|
+
/**
|
|
100
|
+
* Human-readable name for this key source.
|
|
101
|
+
*/
|
|
102
|
+
get SourceName() {
|
|
103
|
+
return 'Azure Key Vault';
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Initializes the Azure Key Vault client.
|
|
107
|
+
*
|
|
108
|
+
* Lazy-loads the Azure SDK to avoid requiring it when not used.
|
|
109
|
+
* Uses DefaultAzureCredential for authentication.
|
|
110
|
+
*/
|
|
111
|
+
async Initialize() {
|
|
112
|
+
if (this._initialized) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
// Lazy-load Azure SDKs
|
|
117
|
+
const secretsModule = await Promise.resolve().then(() => __importStar(require('@azure/keyvault-secrets')));
|
|
118
|
+
const identityModule = await Promise.resolve().then(() => __importStar(require('@azure/identity')));
|
|
119
|
+
SecretClient = secretsModule.SecretClient;
|
|
120
|
+
DefaultAzureCredential = identityModule.DefaultAzureCredential;
|
|
121
|
+
// Get default vault URL if configured
|
|
122
|
+
this._defaultVaultUrl = process.env.AZURE_KEYVAULT_URL || null;
|
|
123
|
+
this._initialized = true;
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
127
|
+
throw new Error(`Failed to initialize Azure Key Vault client: ${message}. ` +
|
|
128
|
+
'Ensure @azure/keyvault-secrets and @azure/identity are installed: ' +
|
|
129
|
+
'npm install @azure/keyvault-secrets @azure/identity');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Validates that the Azure Key Vault client is properly configured.
|
|
134
|
+
*
|
|
135
|
+
* @returns true if the client is initialized
|
|
136
|
+
*/
|
|
137
|
+
ValidateConfiguration() {
|
|
138
|
+
if (!this._initialized) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
// Configuration is valid - credentials will be validated on first use
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Checks if a secret name/URL appears to be valid.
|
|
146
|
+
*
|
|
147
|
+
* @param lookupValue - The secret URL or name
|
|
148
|
+
* @returns true if the lookup value appears valid
|
|
149
|
+
*/
|
|
150
|
+
async KeyExists(lookupValue) {
|
|
151
|
+
if (!lookupValue) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
// Check for valid patterns
|
|
155
|
+
// Full URL: https://vault-name.vault.azure.net/secrets/secret-name
|
|
156
|
+
// Secret name only: my-secret-name (requires AZURE_KEYVAULT_URL)
|
|
157
|
+
const urlPattern = /^https:\/\/[a-zA-Z0-9-]+\.vault\.azure\.net\/secrets\/[a-zA-Z0-9-]+/;
|
|
158
|
+
const namePattern = /^[a-zA-Z0-9-]+$/;
|
|
159
|
+
if (urlPattern.test(lookupValue)) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
if (namePattern.test(lookupValue) && this._defaultVaultUrl) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Retrieves encryption key material from Azure Key Vault.
|
|
169
|
+
*
|
|
170
|
+
* @param lookupValue - Secret URL or name (if AZURE_KEYVAULT_URL is set)
|
|
171
|
+
* @param keyVersion - Optional secret version (uses latest if not specified)
|
|
172
|
+
* @returns Buffer containing the key material
|
|
173
|
+
*
|
|
174
|
+
* @throws Error if the secret cannot be retrieved
|
|
175
|
+
*/
|
|
176
|
+
async GetKey(lookupValue, keyVersion) {
|
|
177
|
+
if (!this._initialized) {
|
|
178
|
+
await this.Initialize();
|
|
179
|
+
}
|
|
180
|
+
if (!SecretClient || !DefaultAzureCredential) {
|
|
181
|
+
throw new Error('Azure Key Vault client not initialized');
|
|
182
|
+
}
|
|
183
|
+
if (!lookupValue) {
|
|
184
|
+
throw new Error('Azure Key Vault key source requires a lookup value. ' +
|
|
185
|
+
'Provide the secret URL or name.');
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
// Parse the lookup value to get vault URL and secret name
|
|
189
|
+
const { vaultUrl, secretName } = this.parseLookupValue(lookupValue);
|
|
190
|
+
// Get or create client for this vault
|
|
191
|
+
let client = this._clients.get(vaultUrl);
|
|
192
|
+
if (!client) {
|
|
193
|
+
const credential = new DefaultAzureCredential();
|
|
194
|
+
client = new SecretClient(vaultUrl, credential);
|
|
195
|
+
this._clients.set(vaultUrl, client);
|
|
196
|
+
}
|
|
197
|
+
// Build secret options
|
|
198
|
+
const options = keyVersion ? { version: keyVersion } : {};
|
|
199
|
+
// Get the secret
|
|
200
|
+
const secret = await client.getSecret(secretName, options);
|
|
201
|
+
if (!secret.value) {
|
|
202
|
+
throw new Error(`Secret "${secretName}" has no value`);
|
|
203
|
+
}
|
|
204
|
+
// Secret value should be base64-encoded key material
|
|
205
|
+
try {
|
|
206
|
+
return Buffer.from(secret.value, 'base64');
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
throw new Error(`Secret "${secretName}" is not valid base64. ` +
|
|
210
|
+
'Encryption keys must be stored as base64-encoded strings in Key Vault.');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
215
|
+
// Provide helpful error messages for common issues
|
|
216
|
+
if (message.includes('SecretNotFound')) {
|
|
217
|
+
throw new Error(`Azure Key Vault secret not found: ${lookupValue}. ` +
|
|
218
|
+
`Verify the secret exists in the vault.`);
|
|
219
|
+
}
|
|
220
|
+
if (message.includes('Forbidden') || message.includes('AccessDenied')) {
|
|
221
|
+
throw new Error(`Azure Key Vault access denied for: ${lookupValue}. ` +
|
|
222
|
+
`Ensure the application has Secret Get permission.`);
|
|
223
|
+
}
|
|
224
|
+
if (message.includes('AuthenticationError')) {
|
|
225
|
+
throw new Error(`Azure authentication failed. ` +
|
|
226
|
+
`Ensure credentials are configured (managed identity, service principal, or Azure CLI).`);
|
|
227
|
+
}
|
|
228
|
+
throw new Error(`Azure Key Vault key retrieval failed: ${message}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Parses a lookup value into vault URL and secret name.
|
|
233
|
+
*
|
|
234
|
+
* @private
|
|
235
|
+
*/
|
|
236
|
+
parseLookupValue(lookupValue) {
|
|
237
|
+
// Full URL format: https://vault-name.vault.azure.net/secrets/secret-name[/version]
|
|
238
|
+
const urlMatch = lookupValue.match(/^(https:\/\/[a-zA-Z0-9-]+\.vault\.azure\.net)\/secrets\/([a-zA-Z0-9-]+)/);
|
|
239
|
+
if (urlMatch) {
|
|
240
|
+
return {
|
|
241
|
+
vaultUrl: urlMatch[1],
|
|
242
|
+
secretName: urlMatch[2]
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// Simple name format (requires AZURE_KEYVAULT_URL)
|
|
246
|
+
if (this._defaultVaultUrl) {
|
|
247
|
+
return {
|
|
248
|
+
vaultUrl: this._defaultVaultUrl,
|
|
249
|
+
secretName: lookupValue
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
throw new Error(`Invalid Key Vault lookup value: "${lookupValue}". ` +
|
|
253
|
+
`Expected format: https://vault-name.vault.azure.net/secrets/secret-name ` +
|
|
254
|
+
`or set AZURE_KEYVAULT_URL and provide just the secret name.`);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Cleans up Azure Key Vault clients.
|
|
258
|
+
*/
|
|
259
|
+
async Dispose() {
|
|
260
|
+
this._clients.clear();
|
|
261
|
+
this._initialized = false;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
exports.AzureKeyVaultKeySource = AzureKeyVaultKeySource;
|
|
265
|
+
exports.AzureKeyVaultKeySource = AzureKeyVaultKeySource = __decorate([
|
|
266
|
+
(0, global_1.RegisterClass)(EncryptionKeySourceBase_1.EncryptionKeySourceBase, 'AzureKeyVaultKeySource')
|
|
267
|
+
], AzureKeyVaultKeySource);
|
|
268
|
+
//# sourceMappingURL=AzureKeyVaultKeySource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AzureKeyVaultKeySource.js","sourceRoot":"","sources":["../../src/providers/AzureKeyVaultKeySource.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Configuration file key source provider.
|
|
3
|
+
*
|
|
4
|
+
* This provider retrieves encryption keys from MemberJunction's
|
|
5
|
+
* configuration file (mj.config.cjs or other cosmiconfig-compatible formats).
|
|
6
|
+
*
|
|
7
|
+
* ## Usage
|
|
8
|
+
*
|
|
9
|
+
* 1. Add keys to your mj.config.cjs:
|
|
10
|
+
* ```javascript
|
|
11
|
+
* module.exports = {
|
|
12
|
+
* encryptionKeys: {
|
|
13
|
+
* pii_master: 'K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=',
|
|
14
|
+
* api_secrets: 'aW5kZXhfbmV3X2tleV9mb3JfdjJfcm90YXRpb24='
|
|
15
|
+
* }
|
|
16
|
+
* };
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* 2. Configure in database with:
|
|
20
|
+
* - EncryptionKeySourceID pointing to 'Configuration File' source
|
|
21
|
+
* - KeyLookupValue = 'pii_master' (the key name in the config)
|
|
22
|
+
*
|
|
23
|
+
* ## Key Format
|
|
24
|
+
*
|
|
25
|
+
* Keys must be base64-encoded strings. Generate with:
|
|
26
|
+
* ```bash
|
|
27
|
+
* openssl rand -base64 32 # For AES-256
|
|
28
|
+
* openssl rand -base64 16 # For AES-128
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* ## Security Considerations
|
|
32
|
+
*
|
|
33
|
+
* - Config files should have restricted file permissions (600 or 640)
|
|
34
|
+
* - Don't commit config files with keys to source control
|
|
35
|
+
* - Consider using .gitignore for mj.config.cjs
|
|
36
|
+
* - For production, prefer environment variables or secrets managers
|
|
37
|
+
*
|
|
38
|
+
* ## Key Rotation
|
|
39
|
+
*
|
|
40
|
+
* Add the new key with a versioned name:
|
|
41
|
+
* ```javascript
|
|
42
|
+
* encryptionKeys: {
|
|
43
|
+
* pii_master: '<current-key>',
|
|
44
|
+
* pii_master_v2: '<new-key>'
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @module @memberjunction/encryption
|
|
49
|
+
*/
|
|
50
|
+
/// <reference types="node" />
|
|
51
|
+
import { EncryptionKeySourceBase } from '../EncryptionKeySourceBase';
|
|
52
|
+
/**
|
|
53
|
+
* Encryption key source that retrieves keys from configuration files.
|
|
54
|
+
*
|
|
55
|
+
* Uses cosmiconfig to locate configuration in standard locations:
|
|
56
|
+
* - mj.config.cjs (recommended)
|
|
57
|
+
* - mj.config.js
|
|
58
|
+
* - .mjrc.json
|
|
59
|
+
* - .mjrc.yaml
|
|
60
|
+
*
|
|
61
|
+
* Keys are read from the `encryptionKeys` section of the configuration.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* // Configuration file (mj.config.cjs):
|
|
66
|
+
* module.exports = {
|
|
67
|
+
* encryptionKeys: {
|
|
68
|
+
* pii_master: 'base64-encoded-key-here',
|
|
69
|
+
* financial_data: 'another-base64-key'
|
|
70
|
+
* }
|
|
71
|
+
* };
|
|
72
|
+
*
|
|
73
|
+
* // Usage (typically automatic via ClassFactory):
|
|
74
|
+
* const source = new ConfigFileKeySource();
|
|
75
|
+
* await source.Initialize(); // Load the config file
|
|
76
|
+
*
|
|
77
|
+
* const key = await source.GetKey('pii_master');
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare class ConfigFileKeySource extends EncryptionKeySourceBase {
|
|
81
|
+
/**
|
|
82
|
+
* Loaded configuration from the config file.
|
|
83
|
+
* Set during Initialize(), null if not yet loaded.
|
|
84
|
+
*
|
|
85
|
+
* @private
|
|
86
|
+
*/
|
|
87
|
+
private _loadedConfig;
|
|
88
|
+
/**
|
|
89
|
+
* Path to the loaded config file (for error messages).
|
|
90
|
+
*
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
private _configFilePath;
|
|
94
|
+
/**
|
|
95
|
+
* Human-readable name for this source.
|
|
96
|
+
*/
|
|
97
|
+
get SourceName(): string;
|
|
98
|
+
/**
|
|
99
|
+
* Initializes the key source by loading the configuration file.
|
|
100
|
+
*
|
|
101
|
+
* Uses cosmiconfig to search for configuration in standard locations.
|
|
102
|
+
* Must be called before any key operations.
|
|
103
|
+
*
|
|
104
|
+
* @throws Error if cosmiconfig module cannot be loaded
|
|
105
|
+
*/
|
|
106
|
+
Initialize(): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Validates that the configuration file was loaded successfully.
|
|
109
|
+
*
|
|
110
|
+
* @returns `true` if the config file was loaded and contains encryptionKeys
|
|
111
|
+
*/
|
|
112
|
+
ValidateConfiguration(): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Checks if a key exists in the configuration file.
|
|
115
|
+
*
|
|
116
|
+
* @param lookupValue - The key name to check
|
|
117
|
+
* @returns Promise resolving to `true` if the key exists
|
|
118
|
+
*/
|
|
119
|
+
KeyExists(lookupValue: string): Promise<boolean>;
|
|
120
|
+
/**
|
|
121
|
+
* Retrieves key material from the configuration file.
|
|
122
|
+
*
|
|
123
|
+
* Keys should be stored as base64-encoded strings in the encryptionKeys
|
|
124
|
+
* section of the configuration file.
|
|
125
|
+
*
|
|
126
|
+
* For versioned keys, the version is appended with an underscore:
|
|
127
|
+
* - `key_name` for version 1 (default)
|
|
128
|
+
* - `key_name_v2` for version 2
|
|
129
|
+
*
|
|
130
|
+
* @param lookupValue - The key name in the configuration
|
|
131
|
+
* @param keyVersion - Optional version number (defaults to '1')
|
|
132
|
+
* @returns Promise resolving to the decoded key bytes
|
|
133
|
+
*
|
|
134
|
+
* @throws Error if Initialize() was not called
|
|
135
|
+
* @throws Error if the key is not found
|
|
136
|
+
* @throws Error if the value is not valid base64
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* // Config file has: encryptionKeys: { pii_master: '...' }
|
|
141
|
+
* const key = await source.GetKey('pii_master');
|
|
142
|
+
*
|
|
143
|
+
* // For versioned keys during rotation:
|
|
144
|
+
* // Config has: pii_master, pii_master_v2
|
|
145
|
+
* const newKey = await source.GetKey('pii_master', '2');
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
GetKey(lookupValue: string, keyVersion?: string): Promise<Buffer>;
|
|
149
|
+
/**
|
|
150
|
+
* Cleans up resources (no-op for config file source).
|
|
151
|
+
*/
|
|
152
|
+
Dispose(): Promise<void>;
|
|
153
|
+
/**
|
|
154
|
+
* Builds the full key name with optional version suffix.
|
|
155
|
+
*
|
|
156
|
+
* @param baseName - The base key name
|
|
157
|
+
* @param keyVersion - Optional version number
|
|
158
|
+
* @returns The full key name
|
|
159
|
+
*
|
|
160
|
+
* @private
|
|
161
|
+
*/
|
|
162
|
+
private buildKeyName;
|
|
163
|
+
/**
|
|
164
|
+
* Validates that a string is a valid configuration key name.
|
|
165
|
+
*
|
|
166
|
+
* @param name - The name to validate
|
|
167
|
+
* @returns `true` if the name is valid
|
|
168
|
+
*
|
|
169
|
+
* @private
|
|
170
|
+
*/
|
|
171
|
+
private isValidKeyName;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=ConfigFileKeySource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigFileKeySource.d.ts","sourceRoot":"","sources":["../../src/providers/ConfigFileKeySource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;;AAGH,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAYrE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBACa,mBAAoB,SAAQ,uBAAuB;IAC5D;;;;;OAKG;IACH,OAAO,CAAC,aAAa,CAAuC;IAE5D;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAAuB;IAE9C;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;;;;;OAOG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA6CjC;;;;OAIG;IACH,qBAAqB,IAAI,OAAO;IAIhC;;;;;OAKG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiBtD;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACG,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA6EvE;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IAUpB;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc;CAczB"}
|