|
3 | 3 | import { arsenalErrorAWSKMS } from '../utils'; |
4 | 4 | import { Agent as HttpAgent } from 'http'; |
5 | 5 | import { Agent as HttpsAgent } from 'https'; |
6 | | -import { KMSClient, |
7 | | - CreateKeyCommand, |
| 6 | +import { |
| 7 | + KMSClient, |
| 8 | + CreateKeyCommand, |
8 | 9 | ScheduleKeyDeletionCommand, |
9 | | - GenerateDataKeyCommand, |
10 | | - EncryptCommand, |
11 | | - DecryptCommand, |
12 | | - ListKeysCommand, |
13 | | - NotFoundException, |
14 | | - KMSInvalidStateException } from '@aws-sdk/client-kms'; |
| 10 | + GenerateDataKeyCommand, |
| 11 | + EncryptCommand, |
| 12 | + DecryptCommand, |
| 13 | + NotFoundException, |
| 14 | + KMSInvalidStateException, |
| 15 | +} from '@aws-sdk/client-kms'; |
15 | 16 | const { NodeHttpHandler } = require('@smithy/node-http-handler'); |
16 | 17 | import * as werelogs from 'werelogs'; |
17 | 18 | import assert from 'assert'; |
@@ -60,7 +61,7 @@ export default class Client implements KMSInterface { |
60 | 61 |
|
61 | 62 | constructor(options: ClientOptions) { |
62 | 63 | this._supportsDefaultKeyPerAccount = true; |
63 | | - const { providerName,tls, ak, sk, region, endpoint, noAwsArn } = options.kmsAWS; |
| 64 | + const { providerName, tls, ak, sk, region, endpoint, noAwsArn } = options.kmsAWS; |
64 | 65 |
|
65 | 66 | const requestHandler = new NodeHttpHandler({ |
66 | 67 | httpAgent: !tls ? new HttpAgent({ |
@@ -134,9 +135,13 @@ export default class Client implements KMSInterface { |
134 | 135 | // Prefer ARN, but fall back to KeyId if ARN is missing |
135 | 136 | keyId = keyMetadata?.Arn ?? (keyMetadata?.KeyId || ''); |
136 | 137 | } |
| 138 | + // May produce double arn prefix: scality arn + aws arn |
| 139 | + // arn:scality:kms:external:aws_kms:custom:key/arn:aws:kms:region:accountId:key/cbd69d33-ba8e-4b56-8cfe |
| 140 | + // If this is a problem, a config flag should be used to hide the scality arn when returning the KMS KeyId |
| 141 | + // or aws arn when creating the KMS Key |
137 | 142 | const arn = `${this.backend.arnPrefix}${keyId}`; |
138 | 143 | cb(null, keyId, arn); |
139 | | - }).catch(err => { |
| 144 | + }).catch((err: Error) => { |
140 | 145 | const error = arsenalErrorAWSKMS(err); |
141 | 146 | logger.error('AWS KMS: failed to create master encryption key', { err }); |
142 | 147 | cb(error); |
@@ -170,9 +175,10 @@ export default class Client implements KMSInterface { |
170 | 175 | return; |
171 | 176 | } |
172 | 177 | cb(null); |
173 | | - }).catch(err => { |
| 178 | + }).catch((err: Error) => { |
174 | 179 | if (err instanceof NotFoundException || err instanceof KMSInvalidStateException) { |
175 | | - logger.info('AWS KMS: key does not exist or is already pending deletion', { masterKeyId, error: err }); |
| 180 | + // master key does not exist or is already pending deletion |
| 181 | + logger.warn('AWS KMS: key does not exist or is already pending deletion', { masterKeyId, error: err }); |
176 | 182 | return cb(null); |
177 | 183 | } |
178 | 184 | const error = arsenalErrorAWSKMS(err); |
@@ -204,7 +210,7 @@ export default class Client implements KMSInterface { |
204 | 210 | const isolatedPlaintext = this.safePlaintext(data.Plaintext as Buffer); |
205 | 211 | logger.debug('AWS KMS: data key generated'); |
206 | 212 | cb(null, isolatedPlaintext, Buffer.from(data.CiphertextBlob as Uint8Array)); |
207 | | - }).catch(err => { |
| 213 | + }).catch((err: Error) => { |
208 | 214 | const error = arsenalErrorAWSKMS(err); |
209 | 215 | logger.error('AWS KMS: failed to generate data key', { err }); |
210 | 216 | cb(error); |
@@ -238,8 +244,7 @@ export default class Client implements KMSInterface { |
238 | 244 |
|
239 | 245 | logger.debug('AWS KMS: data key ciphered'); |
240 | 246 | cb(null, Buffer.from(data.CiphertextBlob as Uint8Array)); |
241 | | - return; |
242 | | - }).catch(err => { |
| 247 | + }).catch((err: Error) => { |
243 | 248 | const error = arsenalErrorAWSKMS(err); |
244 | 249 | logger.error('AWS KMS: failed to cipher data key', { err }); |
245 | 250 | cb(error); |
@@ -274,30 +279,23 @@ export default class Client implements KMSInterface { |
274 | 279 |
|
275 | 280 | logger.debug('AWS KMS: data key deciphered'); |
276 | 281 | cb(null, isolatedPlaintext); |
277 | | - }).catch(err => { |
| 282 | + }).catch((err: Error) => { |
278 | 283 | const error = arsenalErrorAWSKMS(err); |
279 | 284 | logger.error('AWS KMS: failed to decipher data key', { err }); |
280 | 285 | cb(error); |
281 | 286 | }); |
282 | 287 | } |
283 | 288 |
|
284 | 289 | /** |
285 | | - * Healthcheck function to verify KMS connectivity |
| 290 | + * NOTE1: S3C-4833 KMS healthcheck is disabled in CloudServer. |
| 291 | + * |
| 292 | + * For the Arsenal client library we intentionally keep this as a no-op |
| 293 | + * to avoid making extra AWS KMS calls (which can incur costs and require |
| 294 | + * additional permissions). Callers should rely on higher-level health |
| 295 | + * checks provided by their services instead of this method. |
286 | 296 | */ |
287 | 297 | healthcheck(logger: werelogs.Logger, cb: (err: Error | null) => void): void { |
288 | | - logger.debug("AWS KMS: performing healthcheck"); |
289 | | - |
290 | | - const command = new ListKeysCommand({ |
291 | | - Limit: 1, |
292 | | - }); |
293 | | - |
294 | | - this.client.send(command).then(() => { |
295 | | - logger.debug("AWS KMS healthcheck: list keys succeeded"); |
296 | | - cb(null); |
297 | | - }).catch(err => { |
298 | | - const error = arsenalErrorAWSKMS(err); |
299 | | - logger.error("AWS KMS healthcheck: failed to list keys", { err }); |
300 | | - cb(error); |
301 | | - }); |
| 298 | + logger.debug("AWS KMS: healthcheck is a no-op (disabled)"); |
| 299 | + cb(null); |
302 | 300 | } |
303 | 301 | } |
0 commit comments