Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions packages/@aws-cdk/aws-cloudfront/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -542,15 +542,25 @@ Note: Don't forget to copy/paste the contents of `public_key.pem` file including
Example:

```ts
new cloudfront.KeyGroup(stack, 'MyKeyGroup', {
items: [
new cloudfront.PublicKey(stack, 'MyPublicKey', {
encodedKey: '...', // contents of public_key.pem file
// comment: 'Key is expiring on ...',
}),
],
// comment: 'Key group containing public keys ...',
});
new cloudfront.KeyGroup(stack, 'MyKeyGroup', {
items: [
new cloudfront.PublicKey(stack, 'InlinePublicKey', {
encodedKey: Key.fromInline('...'), // contents of public_key.pem file
// comment: 'Key is expiring on ...',
}),
],
// comment: 'Key group containing public keys ...',
});

new cloudfront.KeyGroup(stack, 'MyKeyGroup', {
items: [
new cloudfront.PublicKey(stack, 'FilePublicKey', {
encodedKey: Key.fromFile(path.join(__dirname, 'public_key.pem')), // path to public_key.pem file
// comment: 'Key is expiring on ...',
}),
],
// comment: 'Key group containing public keys ...',
});
```

See:
Expand Down
120 changes: 113 additions & 7 deletions packages/@aws-cdk/aws-cloudfront/lib/public-key.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as fs from 'fs';
import { IResource, Names, Resource, Token } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnPublicKey } from './cloudfront.generated';
Expand Down Expand Up @@ -31,11 +32,12 @@ export interface PublicKeyProps {

/**
* The public key that you can use with signed URLs and signed cookies, or with field-level encryption.
* The `encodedKey` parameter must include `-----BEGIN PUBLIC KEY-----` and `-----END PUBLIC KEY-----` lines.
* The `encodedKey` parameter can be either an inline key or from filesystem. If it's inline it must include
* `-----BEGIN PUBLIC KEY-----` and `-----END PUBLIC KEY-----` lines.
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html
* @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/field-level-encryption.html
*/
readonly encodedKey: string;
readonly encodedKey: Key;
}

/**
Expand All @@ -57,15 +59,13 @@ export class PublicKey extends Resource implements IPublicKey {
constructor(scope: Construct, id: string, props: PublicKeyProps) {
super(scope, id);

if (!Token.isUnresolved(props.encodedKey) && !/^-----BEGIN PUBLIC KEY-----/.test(props.encodedKey)) {
throw new Error(`Public key must be in PEM format (with the BEGIN/END PUBLIC KEY lines); got ${props.encodedKey}`);
}
const encodedKey = props.encodedKey.bind(this);

const resource = new CfnPublicKey(this, 'Resource', {
publicKeyConfig: {
name: props.publicKeyName ?? this.generateName(),
callerReference: this.node.addr,
encodedKey: props.encodedKey,
encodedKey: this.publicKeyValue(encodedKey),
comment: props.comment,
},
});
Expand All @@ -80,4 +80,110 @@ export class PublicKey extends Resource implements IPublicKey {
}
return name;
}
}

private publicKeyValue(key: KeyConfig): string {
return key.value;
}
}

/**
* Represents the Public Key handler.
*/
export abstract class Key {
/**
* Inline value for Public Key
* @returns contents of an inline public key.
* @param key Inline public key
*/
public static fromInline(key: string): InlineKey {
return new InlineKey(key);
}

/**
* Loads the public key from a local disk path.
* @returns contents of a .pem key.
* @param path Path to a .pem file
*/
public static fromFile(path: string/*, options: {}*/): FileKey {
return new FileKey(path/*,options*/);
}

/**
* Called when the public key is initialized to allow this object to bind
* to the stack, add resources and have fun.
*
* @param scope The binding scope. Don't be smart about trying to down-cast or
* assume it's initialized. You may just use it as a construct scope.
*/
public abstract bind(scope: Construct): KeyConfig;
}

/**
* Result of binding `Key` into `PublicKey`.
*/
export interface KeyConfig {
/**
* Public Key value.
* @default - contents of a public key
*/
readonly value: string;
}

/**
* Public Key from an inline string.
*/
export class InlineKey extends Key {
constructor(private key: string) {
super();

if (key.length === 0) {
throw new Error('Encoded key inline value cannot be empty');
}

if (key.length > 4096) {
throw new Error('Encoded key inline value is too large, must be <= 4096 but is ' + key.length);
}

if (!Token.isUnresolved(key) && !/^-----BEGIN PUBLIC KEY-----/.test(key)) {
throw new Error(`Public key must be in PEM format (with the BEGIN/END PUBLIC KEY lines); got ${key}`);
}
}

public bind(_scope: Construct): KeyConfig {
return {
value: this.key,
};
}

/**
* Content of a public key.
*/
public content(): string {
return this.key;
}
}

/**
* Public key from a local directory.
*/
export class FileKey extends Key {
private readonly key: string;
/**
* @param path The path to the asset file or directory.
*/
constructor(public readonly path: string) {
super();

const encodedKey = fs.readFileSync(path).toString();
if (!encodedKey) {
throw new Error('Something went wrong with loading the public key.');
}
this.key = new InlineKey(encodedKey).content();
}

public bind(_scope: Construct): KeyConfig {
return {
value: this.key,
};
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,48 @@
{
"Resources": {
"AwesomePublicKeyED3E7F55": {
"AwesomePublicKeyInline1A6EDCE6": {
"Type": "AWS::CloudFront::PublicKey",
"Properties": {
"PublicKeyConfig": {
"CallerReference": "c88e460888c5762c9c47ac0cdc669370d787fb2d9f",
"EncodedKey": "-----BEGIN PUBLIC KEY-----\n MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS\n JAyxd/kGTbJfQNg9YhInb7TSm0dGu0yx8yZ3fnpmxuRPqJIlaVr+fT4YRl71gEYa\n dlhHmnVegyPNjP9dNqZ7zwNqMEPOPnS/NOHbJj1KYKpn1f8pPNycQ5MQCntKGnSj\n 6fc+nbcC0joDvGz80xuy1W4hLV9oC9c3GT26xfZb2jy9MVtA3cppNuTwqrFi3t6e\n 0iGpraxZlT5wewjZLpQkngqYr6s3aucPAZVsGTEYPo4nD5mswmtZOm+tgcOrivtD\n /3sD/qZLQ6c5siqyS8aTraD6y+VXugujfarTU65IeZ6QAUbLMsWuZOIi5Jn8zAwx\n NQIDAQAB\n -----END PUBLIC KEY-----\n ",
"Name": "awscdkcloudfrontcustomAwesomePublicKey0E83393B"
"CallerReference": "c84ece92b360f4192c0c049980669b0afe70b5f955",
"EncodedKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS\nJAyxd/kGTbJfQNg9YhInb7TSm0dGu0yx8yZ3fnpmxuRPqJIlaVr+fT4YRl71gEYa\ndlhHmnVegyPNjP9dNqZ7zwNqMEPOPnS/NOHbJj1KYKpn1f8pPNycQ5MQCntKGnSj\n6fc+nbcC0joDvGz80xuy1W4hLV9oC9c3GT26xfZb2jy9MVtA3cppNuTwqrFi3t6e\n0iGpraxZlT5wewjZLpQkngqYr6s3aucPAZVsGTEYPo4nD5mswmtZOm+tgcOrivtD\n/3sD/qZLQ6c5siqyS8aTraD6y+VXugujfarTU65IeZ6QAUbLMsWuZOIi5Jn8zAwx\nNQIDAQAB\n-----END PUBLIC KEY-----",
"Name": "awscdkcloudfrontcustomAwesomePublicKeyInlineB6223952"
}
}
},
"AwesomeKeyGroup3EF8348B": {
"AwesomeKeyGroupInline15125FEB": {
"Type": "AWS::CloudFront::KeyGroup",
"Properties": {
"KeyGroupConfig": {
"Items": [
{
"Ref": "AwesomePublicKeyED3E7F55"
"Ref": "AwesomePublicKeyInline1A6EDCE6"
}
],
"Name": "awscdkcloudfrontcustomAwesomeKeyGroup73FD4DCA"
"Name": "awscdkcloudfrontcustomAwesomeKeyGroupInline80E48054"
}
}
},
"AwesomePublicKeyFromFile047B5107": {
"Type": "AWS::CloudFront::PublicKey",
"Properties": {
"PublicKeyConfig": {
"CallerReference": "c827b081d326a5957b0a49ee91095b8f41987fe2d6",
"EncodedKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS\nJAyxd/kGTbJfQNg9YhInb7TSm0dGu0yx8yZ3fnpmxuRPqJIlaVr+fT4YRl71gEYa\ndlhHmnVegyPNjP9dNqZ7zwNqMEPOPnS/NOHbJj1KYKpn1f8pPNycQ5MQCntKGnSj\n6fc+nbcC0joDvGz80xuy1W4hLV9oC9c3GT26xfZb2jy9MVtA3cppNuTwqrFi3t6e\n0iGpraxZlT5wewjZLpQkngqYr6s3aucPAZVsGTEYPo4nD5mswmtZOm+tgcOrivtD\n/3sD/qZLQ6c5siqyS8aTraD6y+VXugujfarTU65IeZ6QAUbLMsWuZOIi5Jn8zAwx\nNQIDAQAB\n-----END PUBLIC KEY-----",
"Name": "awscdkcloudfrontcustomAwesomePublicKeyFromFile95419BD0"
}
}
},
"AwesomeKeyGroupFromFileCF6B49D4": {
"Type": "AWS::CloudFront::KeyGroup",
"Properties": {
"KeyGroupConfig": {
"Items": [
{
"Ref": "AwesomePublicKeyFromFile047B5107"
}
],
"Name": "awscdkcloudfrontcustomAwesomeKeyGroupFromFileC5F179C4"
}
}
}
Expand Down
34 changes: 22 additions & 12 deletions packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-key-group.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import * as path from 'path';
import * as cdk from '@aws-cdk/core';
import * as cloudfront from '../lib';

const app = new cdk.App();

const stack = new cdk.Stack(app, 'aws-cdk-cloudfront-custom');

new cloudfront.KeyGroup(stack, 'AwesomeKeyGroup', {
const publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS
JAyxd/kGTbJfQNg9YhInb7TSm0dGu0yx8yZ3fnpmxuRPqJIlaVr+fT4YRl71gEYa
dlhHmnVegyPNjP9dNqZ7zwNqMEPOPnS/NOHbJj1KYKpn1f8pPNycQ5MQCntKGnSj
6fc+nbcC0joDvGz80xuy1W4hLV9oC9c3GT26xfZb2jy9MVtA3cppNuTwqrFi3t6e
0iGpraxZlT5wewjZLpQkngqYr6s3aucPAZVsGTEYPo4nD5mswmtZOm+tgcOrivtD
/3sD/qZLQ6c5siqyS8aTraD6y+VXugujfarTU65IeZ6QAUbLMsWuZOIi5Jn8zAwx
NQIDAQAB
-----END PUBLIC KEY-----`;

new cloudfront.KeyGroup(stack, 'AwesomeKeyGroupInline', {
items: [
new cloudfront.PublicKey(stack, 'AwesomePublicKeyInline', {
encodedKey: cloudfront.Key.fromInline(publicKey),
}),
],
});

new cloudfront.KeyGroup(stack, 'AwesomeKeyGroupFromFile', {
items: [
new cloudfront.PublicKey(stack, 'AwesomePublicKey', {
encodedKey: `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS
JAyxd/kGTbJfQNg9YhInb7TSm0dGu0yx8yZ3fnpmxuRPqJIlaVr+fT4YRl71gEYa
dlhHmnVegyPNjP9dNqZ7zwNqMEPOPnS/NOHbJj1KYKpn1f8pPNycQ5MQCntKGnSj
6fc+nbcC0joDvGz80xuy1W4hLV9oC9c3GT26xfZb2jy9MVtA3cppNuTwqrFi3t6e
0iGpraxZlT5wewjZLpQkngqYr6s3aucPAZVsGTEYPo4nD5mswmtZOm+tgcOrivtD
/3sD/qZLQ6c5siqyS8aTraD6y+VXugujfarTU65IeZ6QAUbLMsWuZOIi5Jn8zAwx
NQIDAQAB
-----END PUBLIC KEY-----
`,
new cloudfront.PublicKey(stack, 'AwesomePublicKeyFromFile', {
encodedKey: cloudfront.Key.fromFile(path.join(__dirname, './pem/pubkey-good.test.pem')),
}),
],
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"Resources": {
"AwesomePublicKeyInline1A6EDCE6": {
"Type": "AWS::CloudFront::PublicKey",
"Properties": {
"PublicKeyConfig": {
"CallerReference": "c84ece92b360f4192c0c049980669b0afe70b5f955",
"EncodedKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS\nJAyxd/kGTbJfQNg9YhInb7TSm0dGu0yx8yZ3fnpmxuRPqJIlaVr+fT4YRl71gEYa\ndlhHmnVegyPNjP9dNqZ7zwNqMEPOPnS/NOHbJj1KYKpn1f8pPNycQ5MQCntKGnSj\n6fc+nbcC0joDvGz80xuy1W4hLV9oC9c3GT26xfZb2jy9MVtA3cppNuTwqrFi3t6e\n0iGpraxZlT5wewjZLpQkngqYr6s3aucPAZVsGTEYPo4nD5mswmtZOm+tgcOrivtD\n/3sD/qZLQ6c5siqyS8aTraD6y+VXugujfarTU65IeZ6QAUbLMsWuZOIi5Jn8zAwx\nNQIDAQAB\n-----END PUBLIC KEY-----",
"Name": "awscdkcloudfrontcustomAwesomePublicKeyInlineB6223952"
}
}
},
"AwesomePublicKeyFromFile047B5107": {
"Type": "AWS::CloudFront::PublicKey",
"Properties": {
"PublicKeyConfig": {
"CallerReference": "c827b081d326a5957b0a49ee91095b8f41987fe2d6",
"EncodedKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS\nJAyxd/kGTbJfQNg9YhInb7TSm0dGu0yx8yZ3fnpmxuRPqJIlaVr+fT4YRl71gEYa\ndlhHmnVegyPNjP9dNqZ7zwNqMEPOPnS/NOHbJj1KYKpn1f8pPNycQ5MQCntKGnSj\n6fc+nbcC0joDvGz80xuy1W4hLV9oC9c3GT26xfZb2jy9MVtA3cppNuTwqrFi3t6e\n0iGpraxZlT5wewjZLpQkngqYr6s3aucPAZVsGTEYPo4nD5mswmtZOm+tgcOrivtD\n/3sD/qZLQ6c5siqyS8aTraD6y+VXugujfarTU65IeZ6QAUbLMsWuZOIi5Jn8zAwx\nNQIDAQAB\n-----END PUBLIC KEY-----",
"Name": "awscdkcloudfrontcustomAwesomePublicKeyFromFile95419BD0"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as path from 'path';
import * as cdk from '@aws-cdk/core';
import * as cloudfront from '../lib';

const app = new cdk.App();

const stack = new cdk.Stack(app, 'aws-cdk-cloudfront-custom');

const publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS
JAyxd/kGTbJfQNg9YhInb7TSm0dGu0yx8yZ3fnpmxuRPqJIlaVr+fT4YRl71gEYa
dlhHmnVegyPNjP9dNqZ7zwNqMEPOPnS/NOHbJj1KYKpn1f8pPNycQ5MQCntKGnSj
6fc+nbcC0joDvGz80xuy1W4hLV9oC9c3GT26xfZb2jy9MVtA3cppNuTwqrFi3t6e
0iGpraxZlT5wewjZLpQkngqYr6s3aucPAZVsGTEYPo4nD5mswmtZOm+tgcOrivtD
/3sD/qZLQ6c5siqyS8aTraD6y+VXugujfarTU65IeZ6QAUbLMsWuZOIi5Jn8zAwx
NQIDAQAB
-----END PUBLIC KEY-----`;

new cloudfront.PublicKey(stack, 'AwesomePublicKeyInline', {
encodedKey: cloudfront.Key.fromInline(publicKey),
});

new cloudfront.PublicKey(stack, 'AwesomePublicKeyFromFile', {
encodedKey: cloudfront.Key.fromFile(path.join(__dirname, './pem/pubkey-good.test.pem')),
});

app.synth();
10 changes: 5 additions & 5 deletions packages/@aws-cdk/aws-cloudfront/test/key-group.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import '@aws-cdk/assert/jest';
import { expect as expectStack } from '@aws-cdk/assert';
import { App, Stack } from '@aws-cdk/core';
import { KeyGroup, PublicKey } from '../lib';
import { Key, KeyGroup, PublicKey } from '../lib';

const publicKey1 = `-----BEGIN PUBLIC KEY-----
FIRST_KEYgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS
Expand Down Expand Up @@ -44,7 +44,7 @@ describe('KeyGroup', () => {
new KeyGroup(stack, 'MyKeyGroup', {
items: [
new PublicKey(stack, 'MyPublicKey', {
encodedKey: publicKey1,
encodedKey: Key.fromInline(publicKey1),
}),
],
});
Expand Down Expand Up @@ -85,7 +85,7 @@ describe('KeyGroup', () => {
items: [
new PublicKey(stack, 'MyPublicKey', {
publicKeyName: 'pub-key',
encodedKey: publicKey1,
encodedKey: Key.fromInline(publicKey1),
comment: 'Key expiring on 1/1/1984',
}),
],
Expand Down Expand Up @@ -129,12 +129,12 @@ describe('KeyGroup', () => {
items: [
new PublicKey(stack, 'BingoKey', {
publicKeyName: 'Bingo-Key',
encodedKey: publicKey1,
encodedKey: Key.fromInline(publicKey1),
comment: 'Key expiring on 1/1/1984',
}),
new PublicKey(stack, 'RollyKey', {
publicKeyName: 'Rolly-Key',
encodedKey: publicKey2,
encodedKey: Key.fromInline(publicKey2),
comment: 'Key expiring on 1/1/1984',
}),
],
Expand Down
7 changes: 7 additions & 0 deletions packages/@aws-cdk/aws-cloudfront/test/pem/pubkey-bad.test.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudf8/iNkQgdvjEdm6xYS
JAyxd/kGTbJfQNg9YhInb7TSm0dGu0yx8yZ3fnpmxuRPqJIlaVr+fT4YRl71gEYa
dlhHmnVegyPNjP9dNqZ7zwNqMEPOPnS/NOHbJj1KYKpn1f8pPNycQ5MQCntKGnSj
6fc+nbcC0joDvGz80xuy1W4hLV9oC9c3GT26xfZb2jy9MVtA3cppNuTwqrFi3t6e
0iGpraxZlT5wewjZLpQkngqYr6s3aucPAZVsGTEYPo4nD5mswmtZOm+tgcOrivtD
/3sD/qZLQ6c5siqyS8aTraD6y+VXugujfarTU65IeZ6QAUbLMsWuZOIi5Jn8zAwx
NQIDAQAB
Loading