0xBradock
0xBradock

Reputation: 327

Decrypt SSM stored parameter with KMS encryption, Error: InvalidCiphertextException

I am trying to decrypt a parameter stored on SSM that is encrypted with a user managed KMS key, which I just created.

This Lambda is being executed with the correct permissions to Decrypt with the key and to Read from the SSM parameter store.

I am sure the parameter is fetched correctly, because I am able to retrieve the stored parameter if I do not encrypt it with the KMS key.

I also tryied using another library base64-js to encrypt the string to Uint8Array, but the result is the same.

This is the sample code:

import { DecryptCommand, KMSClient } from '@aws-sdk/client-kms';
import { GetParameterCommand, SSMClient } from '@aws-sdk/client-ssm';

const kmsClient = new KMSClient({ region: process.env.REGION });
const ssmClient = new SSMClient({ region: process.env.REGION });

try {
    const response = await ssmClient.send(new GetParameterCommand({
        Name: `/path/to/param`
    }));
    // Value below verified without KMS key
    const sureItIsValid = response.Parameter?.Value as string

    // Obtained the same result for buff using base64-js lib
    const buff: Uint8Array = Buffer.from(sureItIsValid, 'base64');
    const command = new DecryptCommand({
        CiphertextBlob: buff,
        // The KeyId was also verified using the alias
        KeyId: 'arn:aws:kms:<REGION>:...',
    });

    const secrets = await kmsClient.send(command);

    console.error('result');
    console.log(secrets.Plaintext?.toString());
  } catch (error) {
    console.error('error');
    console.error(JSON.stringify(error));
  }

And I get:

ERROR   error
ERROR   {"name":"InvalidCiphertextException","$fault":"client","$metadata":{"httpStatusCode":400,"requestId":"the-request-id","attempts":1,"totalRetryDelay":0},"__type":"InvalidCiphertextException","message":"UnknownError"}

Upvotes: 0

Views: 1965

Answers (1)

fedonev
fedonev

Reputation: 25639

Add WithDecryption: true to your GetParameterCommand. SSM will call KMS to decrypt* the SecretString paramter and return the plaintext to us in Parameter.Value:

const command = new GetParameterCommand({
    Name: '/path/to/param',
    WithDecryption: true,
});

* You are using the CDK to handle your Lambda permissions, so the following will work:

param.grantRead(func); // let your Lambda function read the SSM Parameter
key.grantDecrypt(func); // let your Lambda Function decrypt the SSM Parameter

Upvotes: 3

Related Questions