aws-cdk icon indicating copy to clipboard operation
aws-cdk copied to clipboard

(custom resources): Can not get public key for a KMS key

Open sashee opened this issue 2 years ago • 12 comments

What is the problem?

I tried to extract the public key for an asymmetric KMS key but I get a Response is not valid JSON error.

Reproduction Steps

const key = new aws_kms.Key(
  this,
  "key",
  {
    keySpec: aws_kms.KeySpec.ECC_NIST_P384,
    keyUsage: aws_kms.KeyUsage.SIGN_VERIFY,
  }
);
const publicKey = new custom_resources.AwsCustomResource(
  this,
  "publicKey",
  {
    onCreate: {
      service: "KMS",
      action: "getPublicKey",
      parameters: {
        KeyId: key.keyArn,
      },
      physicalResourceId: custom_resources.PhysicalResourceId.of(key.keyArn),
      outputPaths: ['PublicKey'],
    },
    policy: custom_resources.AwsCustomResourcePolicy.fromSdkCalls({
      resources: custom_resources.AwsCustomResourcePolicy.ANY_RESOURCE
    }),
  }
);

What did you expect to happen?

I expected that the stack deploys and I can extract the public key.

What actually happened?

Response is not valid JSON

In the CloudWatch Logs, I see that the PublicKey is retrieved, but it seems in a unusable format:

image

CDK CLI Version

2.12.0

Framework Version

No response

Node.js Version

v16.14.0

OS

Ubuntu

Language

Typescript

Language Version

No response

Other information

No response

sashee avatar Feb 21 '22 11:02 sashee

The same issue with CDK 2.20.0. Tried to create our own custom resource backed by custom lambda to get public key using boto3 but faced the problem described in https://github.com/aws-samples/aws-cdk-examples/discussions/641

lacteolus avatar Apr 08 '22 13:04 lacteolus

I wonder if this is because the response is a blob?

peterwoodworth avatar Apr 20 '22 00:04 peterwoodworth

Unfortunately, I'm not sure CDK can do much here - we don't really control wha the response from the services is.

skinny85 avatar May 05 '22 17:05 skinny85

This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.

github-actions[bot] avatar May 07 '22 20:05 github-actions[bot]

Unfortunately, I'm not sure CDK can do much here - we don't really control wha the response from the services is.

Maybe it's a matter of reformatting (I'm sorry if the word is not the proper one) the command output to a sort of human readable?

After all, the aws kms get-public-key cli command output has the expected format:

image

The fact that you get that error message might also suggest that the response was an "Access Denied", which is not a JSON object.

Can you try temporarly giving the Custom Resource admin permissions, and see if that changes anything? (I guess also allow all principals from the account "kms:*" on the Key, just in case)

skinny85 avatar May 09 '22 21:05 skinny85

@skinny85 thanks for the answer. I've tried what you asked for, but still receiving Response is not valid JSON

Hmm, I'm kind of lost then.

Maybe I would try to do a call using the JavaScript AWS SDK, and see what response it gives me there perhaps...?

skinny85 avatar May 10 '22 16:05 skinny85

The SDK returns this object. Of particular interest is PublicKey, which is a Uint8Array (i.e. it's not a base64-encoded string).

johannes-sscrc avatar May 13 '22 07:05 johannes-sscrc

Interesting! That's probably the source of the Response is not valid JSON error.

skinny85 avatar May 13 '22 17:05 skinny85

Edit: This comment is in response to a now-deleted comment pointing out this line as a potential cause for the error:

const childKey = Buffer.isBuffer(child[key]) ? child[key].toString('utf8') : child[key];

I don't think this is what's causing the "not valid JSON" error, but I'd like to point out that decoding an arbitrary buffer with .toString('utf8') is potentially a lossy conversion. The code will try to decode the buffer as UTF-8, and any part of it that is not valid UTF-8 will be replaced by the Unicode replacement character � (U+FFFD), making it impossible to get the original buffer.

johannes-sscrc avatar May 13 '22 21:05 johannes-sscrc

Had the same issue as everyone here.

The line @johannes-sscrc linked does seem to be related to the error. Indeed, Publickey seems to be in a binary format: DER, and the proper way to encode it appears to be base64 and not utf8.

Thus, a quick fix for me was to replace the above line with:

const childKey = Buffer.isBuffer(child[key]) ? child[key].toString('base64') : child[key];

Then the PublicKey is returned in base64, and there's no error anymore. Generally, it would be good to have a hook/param here to allow the caller to specify how to encode the buffer for specific keys, in order to unblock such issues in the general case.

dmitridr avatar Aug 11 '22 00:08 dmitridr

@sashee did you end up finding a work-around for getting the public key of a KMS key using a custom resource? I'm getting the same invalid JSON error.

synthetic-luis avatar Nov 29 '22 20:11 synthetic-luis

@synthetic-luis , yeah, a custom resource can fetch the public key and output it for other resources. Unfortunately, I can't provide code example as it was done for a client, but the implementation was straightforward.

sashee avatar Nov 29 '22 20:11 sashee

@sashee thanks for the response. Can you please elaborate on how you then overcame the invalid JSON issue (in general terms) as it relates to the code you posted above? For example, did you have to change your code above (e.g. add a new parameter to the getPublicKey call?)

synthetic-luis avatar Nov 29 '22 20:11 synthetic-luis

@synthetic-luis , I just checked the code and I remember wrongly. So I needed a keypair for IVS playback key and I thought to use KMS for that. It did not work (partly because of the issue here) so I implemented a lambda function that generates the key. Not the ideal solution, but it works reliably so far.

sashee avatar Nov 29 '22 20:11 sashee

@sashee this helps a lot. Thank you!

synthetic-luis avatar Nov 29 '22 20:11 synthetic-luis

Would love to have a fix or workaround for this.

DanielLaberge avatar Mar 24 '23 19:03 DanielLaberge

@DanielLaberge if it helps, what worked for me was creating a post deploy script that uses the KMS SDK to do what I needed to do

synthetic-luis avatar Mar 24 '23 19:03 synthetic-luis