@memberjunction/encryption 0.0.1 → 2.130.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,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Type definitions and interfaces for the MemberJunction encryption system.
|
|
3
|
+
*
|
|
4
|
+
* This module defines the core types used throughout the encryption package:
|
|
5
|
+
* - Configuration interfaces for key sources
|
|
6
|
+
* - Parsed encrypted value structure
|
|
7
|
+
* - Key configuration for runtime operations
|
|
8
|
+
*
|
|
9
|
+
* @module @memberjunction/encryption
|
|
10
|
+
* @see {@link EncryptionEngine} for the main encryption/decryption API
|
|
11
|
+
* @see {@link EncryptionKeySourceBase} for implementing custom key sources
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Configuration passed to encryption key source providers during instantiation.
|
|
15
|
+
*
|
|
16
|
+
* Key sources use this configuration to understand how to retrieve key material.
|
|
17
|
+
* The specific properties used depend on the key source implementation.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Environment variable source config
|
|
22
|
+
* const envConfig: EncryptionKeySourceConfig = {
|
|
23
|
+
* lookupValue: 'MJ_ENCRYPTION_KEY_PII'
|
|
24
|
+
* };
|
|
25
|
+
*
|
|
26
|
+
* // Config file source config
|
|
27
|
+
* const fileConfig: EncryptionKeySourceConfig = {
|
|
28
|
+
* lookupValue: 'pii_master_key'
|
|
29
|
+
* };
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export interface EncryptionKeySourceConfig {
|
|
33
|
+
/**
|
|
34
|
+
* The identifier used to look up the key from the source.
|
|
35
|
+
* - For env vars: the environment variable name
|
|
36
|
+
* - For config files: the key name in the encryptionKeys section
|
|
37
|
+
* - For vaults: the secret path
|
|
38
|
+
*/
|
|
39
|
+
lookupValue?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Optional additional configuration specific to the key source.
|
|
42
|
+
* Providers can cast this to their specific config type.
|
|
43
|
+
*/
|
|
44
|
+
additionalConfig?: Record<string, unknown>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Represents the parsed components of an encrypted value string.
|
|
48
|
+
*
|
|
49
|
+
* Encrypted values follow the format:
|
|
50
|
+
* `$ENC$<keyId>$<algorithm>$<iv>$<ciphertext>[$<authTag>]`
|
|
51
|
+
*
|
|
52
|
+
* This structure allows the encryption engine to:
|
|
53
|
+
* 1. Identify which key was used for encryption
|
|
54
|
+
* 2. Determine the algorithm for decryption
|
|
55
|
+
* 3. Extract the IV and ciphertext for the crypto operation
|
|
56
|
+
* 4. Verify authenticity with the auth tag (for AEAD algorithms)
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const parts = engine.ParseEncryptedValue(encryptedValue);
|
|
61
|
+
* console.log(parts.keyId); // UUID of the encryption key
|
|
62
|
+
* console.log(parts.algorithm); // 'AES-256-GCM'
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export interface EncryptedValueParts {
|
|
66
|
+
/**
|
|
67
|
+
* The encryption marker prefix (always '$ENC$').
|
|
68
|
+
* Used for quick detection of encrypted values.
|
|
69
|
+
*/
|
|
70
|
+
marker: string;
|
|
71
|
+
/**
|
|
72
|
+
* The UUID of the encryption key used.
|
|
73
|
+
* References the EncryptionKey entity in the database.
|
|
74
|
+
*/
|
|
75
|
+
keyId: string;
|
|
76
|
+
/**
|
|
77
|
+
* The algorithm name used for encryption.
|
|
78
|
+
* Matches the Name field in the EncryptionAlgorithm entity.
|
|
79
|
+
* @example 'AES-256-GCM', 'AES-256-CBC'
|
|
80
|
+
*/
|
|
81
|
+
algorithm: string;
|
|
82
|
+
/**
|
|
83
|
+
* Base64-encoded initialization vector.
|
|
84
|
+
* Randomly generated for each encryption operation.
|
|
85
|
+
*/
|
|
86
|
+
iv: string;
|
|
87
|
+
/**
|
|
88
|
+
* Base64-encoded encrypted data.
|
|
89
|
+
*/
|
|
90
|
+
ciphertext: string;
|
|
91
|
+
/**
|
|
92
|
+
* Base64-encoded authentication tag for AEAD algorithms.
|
|
93
|
+
* Only present for algorithms like AES-GCM that provide authentication.
|
|
94
|
+
* Undefined for non-AEAD algorithms like AES-CBC.
|
|
95
|
+
*/
|
|
96
|
+
authTag?: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Complete key configuration loaded from the database.
|
|
100
|
+
*
|
|
101
|
+
* This structure contains everything needed to perform encryption
|
|
102
|
+
* or decryption operations, cached for performance.
|
|
103
|
+
*
|
|
104
|
+
* @internal Used by EncryptionEngine for key management
|
|
105
|
+
*/
|
|
106
|
+
export interface KeyConfiguration {
|
|
107
|
+
/** The encryption key's unique identifier (UUID) */
|
|
108
|
+
keyId: string;
|
|
109
|
+
/**
|
|
110
|
+
* Current version of the key for this configuration.
|
|
111
|
+
* Incremented during key rotation operations.
|
|
112
|
+
*/
|
|
113
|
+
keyVersion: string;
|
|
114
|
+
/**
|
|
115
|
+
* Prefix marker for encrypted values.
|
|
116
|
+
* Defaults to '$ENC$' but can be customized per key.
|
|
117
|
+
*/
|
|
118
|
+
marker: string;
|
|
119
|
+
/** Algorithm configuration */
|
|
120
|
+
algorithm: {
|
|
121
|
+
/** Display name of the algorithm (e.g., 'AES-256-GCM') */
|
|
122
|
+
name: string;
|
|
123
|
+
/** Node.js crypto module algorithm identifier (e.g., 'aes-256-gcm') */
|
|
124
|
+
nodeCryptoName: string;
|
|
125
|
+
/** Required key length in bits (e.g., 256 for AES-256) */
|
|
126
|
+
keyLengthBits: number;
|
|
127
|
+
/** Required IV length in bytes (e.g., 12 for GCM, 16 for CBC) */
|
|
128
|
+
ivLengthBytes: number;
|
|
129
|
+
/**
|
|
130
|
+
* Whether the algorithm provides Authenticated Encryption with Associated Data.
|
|
131
|
+
* AEAD algorithms (like AES-GCM) provide both confidentiality and integrity.
|
|
132
|
+
*/
|
|
133
|
+
isAEAD: boolean;
|
|
134
|
+
};
|
|
135
|
+
/** Key source configuration for retrieving key material */
|
|
136
|
+
source: {
|
|
137
|
+
/**
|
|
138
|
+
* The registered class name of the key source provider.
|
|
139
|
+
* Used with ClassFactory to instantiate the provider.
|
|
140
|
+
*/
|
|
141
|
+
driverClass: string;
|
|
142
|
+
/**
|
|
143
|
+
* The lookup value passed to the key source.
|
|
144
|
+
* Interpretation depends on the source type.
|
|
145
|
+
*/
|
|
146
|
+
lookupValue: string;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Result structure returned by key rotation operations.
|
|
151
|
+
*
|
|
152
|
+
* @see {@link RotateEncryptionKeyAction} for the rotation action
|
|
153
|
+
*/
|
|
154
|
+
export interface RotateKeyResult {
|
|
155
|
+
/** Whether the rotation completed successfully */
|
|
156
|
+
success: boolean;
|
|
157
|
+
/** Total number of records that were re-encrypted */
|
|
158
|
+
recordsProcessed: number;
|
|
159
|
+
/**
|
|
160
|
+
* List of fields that were processed.
|
|
161
|
+
* Format: 'EntityName.FieldName'
|
|
162
|
+
*/
|
|
163
|
+
fieldsProcessed: string[];
|
|
164
|
+
/** Error message if rotation failed */
|
|
165
|
+
error?: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Parameters for key rotation operations.
|
|
169
|
+
*
|
|
170
|
+
* @see {@link RotateEncryptionKeyAction} for the rotation action
|
|
171
|
+
*/
|
|
172
|
+
export interface RotateKeyParams {
|
|
173
|
+
/** UUID of the encryption key to rotate */
|
|
174
|
+
encryptionKeyId: string;
|
|
175
|
+
/**
|
|
176
|
+
* Lookup value for the new key material.
|
|
177
|
+
* The new key must be accessible via the key source before rotation.
|
|
178
|
+
*/
|
|
179
|
+
newKeyLookupValue: string;
|
|
180
|
+
/**
|
|
181
|
+
* Number of records to process per batch.
|
|
182
|
+
* Larger batches are faster but use more memory.
|
|
183
|
+
* @default 100
|
|
184
|
+
*/
|
|
185
|
+
batchSize?: number;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Result structure for field encryption operations.
|
|
189
|
+
*
|
|
190
|
+
* @see {@link EnableFieldEncryptionAction}
|
|
191
|
+
*/
|
|
192
|
+
export interface EnableFieldEncryptionResult {
|
|
193
|
+
/** Whether the operation completed successfully */
|
|
194
|
+
success: boolean;
|
|
195
|
+
/** Number of records that were encrypted */
|
|
196
|
+
recordsEncrypted: number;
|
|
197
|
+
/** Number of records that were already encrypted (skipped) */
|
|
198
|
+
recordsSkipped: number;
|
|
199
|
+
/** Error message if the operation failed */
|
|
200
|
+
error?: string;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Parameters for enabling encryption on existing data.
|
|
204
|
+
*
|
|
205
|
+
* @see {@link EnableFieldEncryptionAction}
|
|
206
|
+
*/
|
|
207
|
+
export interface EnableFieldEncryptionParams {
|
|
208
|
+
/** UUID of the EntityField to encrypt */
|
|
209
|
+
entityFieldId: string;
|
|
210
|
+
/**
|
|
211
|
+
* Number of records to process per batch.
|
|
212
|
+
* @default 100
|
|
213
|
+
*/
|
|
214
|
+
batchSize?: number;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,yBAAyB;IACtC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,mBAAmB;IAChC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC7B,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf,8BAA8B;IAC9B,SAAS,EAAE;QACP,0DAA0D;QAC1D,IAAI,EAAE,MAAM,CAAC;QAEb,uEAAuE;QACvE,cAAc,EAAE,MAAM,CAAC;QAEvB,0DAA0D;QAC1D,aAAa,EAAE,MAAM,CAAC;QAEtB,iEAAiE;QACjE,aAAa,EAAE,MAAM,CAAC;QAEtB;;;WAGG;QACH,MAAM,EAAE,OAAO,CAAC;KACnB,CAAC;IAEF,2DAA2D;IAC3D,MAAM,EAAE;QACJ;;;WAGG;QACH,WAAW,EAAE,MAAM,CAAC;QAEpB;;;WAGG;QACH,WAAW,EAAE,MAAM,CAAC;KACvB,CAAC;CACL;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC5B,kDAAkD;IAClD,OAAO,EAAE,OAAO,CAAC;IAEjB,qDAAqD;IACrD,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;IAE1B,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC5B,2CAA2C;IAC3C,eAAe,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IACxC,mDAAmD;IACnD,OAAO,EAAE,OAAO,CAAC;IAEjB,4CAA4C;IAC5C,gBAAgB,EAAE,MAAM,CAAC;IAEzB,8DAA8D;IAC9D,cAAc,EAAE,MAAM,CAAC;IAEvB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IACxC,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Type definitions and interfaces for the MemberJunction encryption system.
|
|
4
|
+
*
|
|
5
|
+
* This module defines the core types used throughout the encryption package:
|
|
6
|
+
* - Configuration interfaces for key sources
|
|
7
|
+
* - Parsed encrypted value structure
|
|
8
|
+
* - Key configuration for runtime operations
|
|
9
|
+
*
|
|
10
|
+
* @module @memberjunction/encryption
|
|
11
|
+
* @see {@link EncryptionEngine} for the main encryption/decryption API
|
|
12
|
+
* @see {@link EncryptionKeySourceBase} for implementing custom key sources
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
//# sourceMappingURL=interfaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview AWS KMS encryption key source provider.
|
|
3
|
+
*
|
|
4
|
+
* This provider retrieves encryption keys from AWS Key Management Service (KMS).
|
|
5
|
+
* It supports both symmetric keys and data key encryption using envelope encryption.
|
|
6
|
+
*
|
|
7
|
+
* ## Configuration
|
|
8
|
+
*
|
|
9
|
+
* The provider uses the standard AWS credential chain:
|
|
10
|
+
* - Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
|
|
11
|
+
* - Shared credentials file (~/.aws/credentials)
|
|
12
|
+
* - IAM role (when running on EC2, ECS, Lambda, etc.)
|
|
13
|
+
*
|
|
14
|
+
* ## Usage
|
|
15
|
+
*
|
|
16
|
+
* 1. Create a symmetric key in AWS KMS
|
|
17
|
+
* 2. Store the key ARN or alias as the KeyLookupValue in MemberJunction
|
|
18
|
+
* 3. Ensure the application has kms:Decrypt permission for the key
|
|
19
|
+
*
|
|
20
|
+
* ## Lookup Value Format
|
|
21
|
+
*
|
|
22
|
+
* The KeyLookupValue should be in one of these formats:
|
|
23
|
+
* - Full ARN: `arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012`
|
|
24
|
+
* - Alias ARN: `arn:aws:kms:us-east-1:123456789012:alias/my-key`
|
|
25
|
+
* - Alias name: `alias/my-key` (uses default region)
|
|
26
|
+
*
|
|
27
|
+
* ## Environment Variables
|
|
28
|
+
*
|
|
29
|
+
* - `AWS_REGION` or `AWS_DEFAULT_REGION`: AWS region (required if not in ARN)
|
|
30
|
+
* - `AWS_ACCESS_KEY_ID`: Access key (optional if using IAM role)
|
|
31
|
+
* - `AWS_SECRET_ACCESS_KEY`: Secret key (optional if using IAM role)
|
|
32
|
+
*
|
|
33
|
+
* @module @memberjunction/encryption
|
|
34
|
+
*/
|
|
35
|
+
/// <reference types="node" />
|
|
36
|
+
import { EncryptionKeySourceBase } from '../EncryptionKeySourceBase';
|
|
37
|
+
/**
|
|
38
|
+
* AWS KMS key source provider.
|
|
39
|
+
*
|
|
40
|
+
* Retrieves encryption keys from AWS Key Management Service.
|
|
41
|
+
* The key material is stored encrypted in KMS and decrypted on retrieval.
|
|
42
|
+
*
|
|
43
|
+
* ## Security Notes
|
|
44
|
+
*
|
|
45
|
+
* - Key material never leaves AWS in plaintext until decryption
|
|
46
|
+
* - All operations are logged in CloudTrail
|
|
47
|
+
* - IAM policies control access to keys
|
|
48
|
+
* - Supports key rotation managed by AWS
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* // In database: KeyLookupValue = 'alias/mj-encryption-key'
|
|
53
|
+
* // The provider will call KMS to decrypt the data key
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare class AWSKMSKeySource extends EncryptionKeySourceBase {
|
|
57
|
+
private _client;
|
|
58
|
+
private _initialized;
|
|
59
|
+
/**
|
|
60
|
+
* Human-readable name for this key source.
|
|
61
|
+
*/
|
|
62
|
+
get SourceName(): string;
|
|
63
|
+
/**
|
|
64
|
+
* Initializes the AWS KMS client.
|
|
65
|
+
*
|
|
66
|
+
* Lazy-loads the AWS SDK to avoid requiring it when not used.
|
|
67
|
+
* Uses the default credential chain for authentication.
|
|
68
|
+
*/
|
|
69
|
+
Initialize(): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Validates that the AWS KMS client is properly configured.
|
|
72
|
+
*
|
|
73
|
+
* @returns true if the client is initialized and region is configured
|
|
74
|
+
*/
|
|
75
|
+
ValidateConfiguration(): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Checks if a key exists in AWS KMS.
|
|
78
|
+
*
|
|
79
|
+
* Note: This only checks if the key ARN/alias format is valid.
|
|
80
|
+
* Actual key existence is verified on GetKey().
|
|
81
|
+
*
|
|
82
|
+
* @param lookupValue - The KMS key ARN or alias
|
|
83
|
+
* @returns true if the lookup value appears to be a valid KMS key reference
|
|
84
|
+
*/
|
|
85
|
+
KeyExists(lookupValue: string): Promise<boolean>;
|
|
86
|
+
/**
|
|
87
|
+
* Retrieves encryption key material from AWS KMS.
|
|
88
|
+
*
|
|
89
|
+
* This method expects the lookupValue to contain a base64-encoded
|
|
90
|
+
* encrypted data key (ciphertext blob) that was encrypted using
|
|
91
|
+
* a KMS customer master key (CMK).
|
|
92
|
+
*
|
|
93
|
+
* For envelope encryption pattern:
|
|
94
|
+
* 1. Generate a data key using KMS GenerateDataKey
|
|
95
|
+
* 2. Store the encrypted data key (CiphertextBlob) as base64 in lookupValue
|
|
96
|
+
* 3. This method decrypts it to get the plaintext key
|
|
97
|
+
*
|
|
98
|
+
* @param lookupValue - Base64-encoded encrypted data key
|
|
99
|
+
* @param _keyVersion - Not used for KMS (versioning handled by KMS)
|
|
100
|
+
* @returns Buffer containing the decrypted key material
|
|
101
|
+
*
|
|
102
|
+
* @throws Error if the key cannot be decrypted
|
|
103
|
+
*/
|
|
104
|
+
GetKey(lookupValue: string, _keyVersion?: string): Promise<Buffer>;
|
|
105
|
+
/**
|
|
106
|
+
* Cleans up the AWS KMS client.
|
|
107
|
+
*/
|
|
108
|
+
Dispose(): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=AWSKMSKeySource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AWSKMSKeySource.d.ts","sourceRoot":"","sources":["../../src/providers/AWSKMSKeySource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;;AAIH,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAMrE;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,eAAgB,SAAQ,uBAAuB;IACxD,OAAO,CAAC,OAAO,CAA6E;IAC5F,OAAO,CAAC,YAAY,CAAS;IAE7B;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;;;OAKG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BjC;;;;OAIG;IACH,qBAAqB,IAAI,OAAO;IAkBhC;;;;;;;;OAQG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAetD;;;;;;;;;;;;;;;;;OAiBG;IACG,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgExE;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAOjC"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview AWS KMS encryption key source provider.
|
|
4
|
+
*
|
|
5
|
+
* This provider retrieves encryption keys from AWS Key Management Service (KMS).
|
|
6
|
+
* It supports both symmetric keys and data key encryption using envelope encryption.
|
|
7
|
+
*
|
|
8
|
+
* ## Configuration
|
|
9
|
+
*
|
|
10
|
+
* The provider uses the standard AWS credential chain:
|
|
11
|
+
* - Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
|
|
12
|
+
* - Shared credentials file (~/.aws/credentials)
|
|
13
|
+
* - IAM role (when running on EC2, ECS, Lambda, etc.)
|
|
14
|
+
*
|
|
15
|
+
* ## Usage
|
|
16
|
+
*
|
|
17
|
+
* 1. Create a symmetric key in AWS KMS
|
|
18
|
+
* 2. Store the key ARN or alias as the KeyLookupValue in MemberJunction
|
|
19
|
+
* 3. Ensure the application has kms:Decrypt permission for the key
|
|
20
|
+
*
|
|
21
|
+
* ## Lookup Value Format
|
|
22
|
+
*
|
|
23
|
+
* The KeyLookupValue should be in one of these formats:
|
|
24
|
+
* - Full ARN: `arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012`
|
|
25
|
+
* - Alias ARN: `arn:aws:kms:us-east-1:123456789012:alias/my-key`
|
|
26
|
+
* - Alias name: `alias/my-key` (uses default region)
|
|
27
|
+
*
|
|
28
|
+
* ## Environment Variables
|
|
29
|
+
*
|
|
30
|
+
* - `AWS_REGION` or `AWS_DEFAULT_REGION`: AWS region (required if not in ARN)
|
|
31
|
+
* - `AWS_ACCESS_KEY_ID`: Access key (optional if using IAM role)
|
|
32
|
+
* - `AWS_SECRET_ACCESS_KEY`: Secret key (optional if using IAM role)
|
|
33
|
+
*
|
|
34
|
+
* @module @memberjunction/encryption
|
|
35
|
+
*/
|
|
36
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
37
|
+
if (k2 === undefined) k2 = k;
|
|
38
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
39
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
40
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
41
|
+
}
|
|
42
|
+
Object.defineProperty(o, k2, desc);
|
|
43
|
+
}) : (function(o, m, k, k2) {
|
|
44
|
+
if (k2 === undefined) k2 = k;
|
|
45
|
+
o[k2] = m[k];
|
|
46
|
+
}));
|
|
47
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
48
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
49
|
+
}) : function(o, v) {
|
|
50
|
+
o["default"] = v;
|
|
51
|
+
});
|
|
52
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
53
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
54
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
55
|
+
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;
|
|
56
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
57
|
+
};
|
|
58
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
59
|
+
if (mod && mod.__esModule) return mod;
|
|
60
|
+
var result = {};
|
|
61
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
62
|
+
__setModuleDefault(result, mod);
|
|
63
|
+
return result;
|
|
64
|
+
};
|
|
65
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
66
|
+
exports.AWSKMSKeySource = void 0;
|
|
67
|
+
const global_1 = require("@memberjunction/global");
|
|
68
|
+
const core_1 = require("@memberjunction/core");
|
|
69
|
+
const EncryptionKeySourceBase_1 = require("../EncryptionKeySourceBase");
|
|
70
|
+
// Lazy-load AWS SDK to avoid requiring it when not used
|
|
71
|
+
let KMSClient = null;
|
|
72
|
+
let DecryptCommand = null;
|
|
73
|
+
/**
|
|
74
|
+
* AWS KMS key source provider.
|
|
75
|
+
*
|
|
76
|
+
* Retrieves encryption keys from AWS Key Management Service.
|
|
77
|
+
* The key material is stored encrypted in KMS and decrypted on retrieval.
|
|
78
|
+
*
|
|
79
|
+
* ## Security Notes
|
|
80
|
+
*
|
|
81
|
+
* - Key material never leaves AWS in plaintext until decryption
|
|
82
|
+
* - All operations are logged in CloudTrail
|
|
83
|
+
* - IAM policies control access to keys
|
|
84
|
+
* - Supports key rotation managed by AWS
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* // In database: KeyLookupValue = 'alias/mj-encryption-key'
|
|
89
|
+
* // The provider will call KMS to decrypt the data key
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
let AWSKMSKeySource = class AWSKMSKeySource extends EncryptionKeySourceBase_1.EncryptionKeySourceBase {
|
|
93
|
+
_client = null;
|
|
94
|
+
_initialized = false;
|
|
95
|
+
/**
|
|
96
|
+
* Human-readable name for this key source.
|
|
97
|
+
*/
|
|
98
|
+
get SourceName() {
|
|
99
|
+
return 'AWS KMS';
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Initializes the AWS KMS client.
|
|
103
|
+
*
|
|
104
|
+
* Lazy-loads the AWS SDK to avoid requiring it when not used.
|
|
105
|
+
* Uses the default credential chain for authentication.
|
|
106
|
+
*/
|
|
107
|
+
async Initialize() {
|
|
108
|
+
if (this._initialized) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
// Lazy-load AWS SDK
|
|
113
|
+
const kmsModule = await Promise.resolve().then(() => __importStar(require('@aws-sdk/client-kms')));
|
|
114
|
+
KMSClient = kmsModule.KMSClient;
|
|
115
|
+
DecryptCommand = kmsModule.DecryptCommand;
|
|
116
|
+
// Create client with default credential chain
|
|
117
|
+
const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION;
|
|
118
|
+
this._client = new KMSClient({
|
|
119
|
+
region: region || undefined
|
|
120
|
+
});
|
|
121
|
+
this._initialized = true;
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
125
|
+
throw new Error(`Failed to initialize AWS KMS client: ${message}. ` +
|
|
126
|
+
'Ensure @aws-sdk/client-kms is installed: npm install @aws-sdk/client-kms');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Validates that the AWS KMS client is properly configured.
|
|
131
|
+
*
|
|
132
|
+
* @returns true if the client is initialized and region is configured
|
|
133
|
+
*/
|
|
134
|
+
ValidateConfiguration() {
|
|
135
|
+
if (!this._initialized || !this._client) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
// Check that we have a region configured
|
|
139
|
+
const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION;
|
|
140
|
+
if (!region) {
|
|
141
|
+
(0, core_1.LogError)('AWS KMS key source: No AWS region configured. ' +
|
|
142
|
+
'Set AWS_REGION or AWS_DEFAULT_REGION environment variable.');
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Checks if a key exists in AWS KMS.
|
|
149
|
+
*
|
|
150
|
+
* Note: This only checks if the key ARN/alias format is valid.
|
|
151
|
+
* Actual key existence is verified on GetKey().
|
|
152
|
+
*
|
|
153
|
+
* @param lookupValue - The KMS key ARN or alias
|
|
154
|
+
* @returns true if the lookup value appears to be a valid KMS key reference
|
|
155
|
+
*/
|
|
156
|
+
async KeyExists(lookupValue) {
|
|
157
|
+
if (!lookupValue) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
// Check for valid KMS key reference formats
|
|
161
|
+
// ARN: arn:aws:kms:region:account:key/key-id
|
|
162
|
+
// Alias ARN: arn:aws:kms:region:account:alias/alias-name
|
|
163
|
+
// Alias: alias/alias-name
|
|
164
|
+
const arnPattern = /^arn:aws:kms:[a-z0-9-]+:[0-9]+:(key|alias)\/.+$/;
|
|
165
|
+
const aliasPattern = /^alias\/.+$/;
|
|
166
|
+
return arnPattern.test(lookupValue) || aliasPattern.test(lookupValue);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Retrieves encryption key material from AWS KMS.
|
|
170
|
+
*
|
|
171
|
+
* This method expects the lookupValue to contain a base64-encoded
|
|
172
|
+
* encrypted data key (ciphertext blob) that was encrypted using
|
|
173
|
+
* a KMS customer master key (CMK).
|
|
174
|
+
*
|
|
175
|
+
* For envelope encryption pattern:
|
|
176
|
+
* 1. Generate a data key using KMS GenerateDataKey
|
|
177
|
+
* 2. Store the encrypted data key (CiphertextBlob) as base64 in lookupValue
|
|
178
|
+
* 3. This method decrypts it to get the plaintext key
|
|
179
|
+
*
|
|
180
|
+
* @param lookupValue - Base64-encoded encrypted data key
|
|
181
|
+
* @param _keyVersion - Not used for KMS (versioning handled by KMS)
|
|
182
|
+
* @returns Buffer containing the decrypted key material
|
|
183
|
+
*
|
|
184
|
+
* @throws Error if the key cannot be decrypted
|
|
185
|
+
*/
|
|
186
|
+
async GetKey(lookupValue, _keyVersion) {
|
|
187
|
+
if (!this._initialized || !this._client) {
|
|
188
|
+
await this.Initialize();
|
|
189
|
+
}
|
|
190
|
+
if (!this._client || !DecryptCommand) {
|
|
191
|
+
throw new Error('AWS KMS client not initialized');
|
|
192
|
+
}
|
|
193
|
+
if (!lookupValue) {
|
|
194
|
+
throw new Error('AWS KMS key source requires a lookup value. ' +
|
|
195
|
+
'Provide the base64-encoded encrypted data key (CiphertextBlob).');
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
// The lookupValue should be a base64-encoded encrypted data key
|
|
199
|
+
// This is the CiphertextBlob from GenerateDataKey
|
|
200
|
+
const ciphertextBlob = Buffer.from(lookupValue, 'base64');
|
|
201
|
+
// Decrypt the data key using KMS
|
|
202
|
+
const command = new DecryptCommand({
|
|
203
|
+
CiphertextBlob: ciphertextBlob
|
|
204
|
+
});
|
|
205
|
+
const response = await this._client.send(command);
|
|
206
|
+
if (!response.Plaintext) {
|
|
207
|
+
throw new Error('KMS returned empty plaintext');
|
|
208
|
+
}
|
|
209
|
+
// Convert Uint8Array to Buffer
|
|
210
|
+
return Buffer.from(response.Plaintext);
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
214
|
+
// Provide helpful error messages for common issues
|
|
215
|
+
if (message.includes('InvalidCiphertextException')) {
|
|
216
|
+
throw new Error(`AWS KMS decryption failed: Invalid ciphertext. ` +
|
|
217
|
+
`Ensure the lookup value contains a valid base64-encoded encrypted data key.`);
|
|
218
|
+
}
|
|
219
|
+
if (message.includes('AccessDeniedException')) {
|
|
220
|
+
throw new Error(`AWS KMS access denied. ` +
|
|
221
|
+
`Ensure the application has kms:Decrypt permission for the key.`);
|
|
222
|
+
}
|
|
223
|
+
if (message.includes('NotFoundException')) {
|
|
224
|
+
throw new Error(`AWS KMS key not found. ` +
|
|
225
|
+
`Verify the key ARN/alias exists and is in the correct region.`);
|
|
226
|
+
}
|
|
227
|
+
throw new Error(`AWS KMS key retrieval failed: ${message}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Cleans up the AWS KMS client.
|
|
232
|
+
*/
|
|
233
|
+
async Dispose() {
|
|
234
|
+
if (this._client) {
|
|
235
|
+
this._client.destroy();
|
|
236
|
+
this._client = null;
|
|
237
|
+
}
|
|
238
|
+
this._initialized = false;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
exports.AWSKMSKeySource = AWSKMSKeySource;
|
|
242
|
+
exports.AWSKMSKeySource = AWSKMSKeySource = __decorate([
|
|
243
|
+
(0, global_1.RegisterClass)(EncryptionKeySourceBase_1.EncryptionKeySourceBase, 'AWSKMSKeySource')
|
|
244
|
+
], AWSKMSKeySource);
|
|
245
|
+
//# sourceMappingURL=AWSKMSKeySource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AWSKMSKeySource.js","sourceRoot":"","sources":["../../src/providers/AWSKMSKeySource.ts"],"names":[],"mappings":"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"}
|