Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lambda): code signing config #12656

Merged
merged 51 commits into from
Feb 25, 2021
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
88b28d8
feat(lambda-code-signing): create draft code
Jan 22, 2021
747a414
create base of Signer Profile
Jan 27, 2021
b2b3263
modify lambda code signing config
Jan 27, 2021
b1b3f40
modify @Attribute => @attribute
Feb 2, 2021
4c88f71
modify README using pkglint
Feb 3, 2021
a943ba8
modify ci errors
Feb 3, 2021
665df39
add module export to aws-signer/lib/index
Feb 3, 2021
0aee381
add construct to dependancy
Feb 4, 2021
f10b46f
make signingProfiles to list
Feb 4, 2021
278c0ef
fix: build errors
Feb 5, 2021
5a799db
add test
Feb 6, 2021
54217e0
fix aws-lambda build errors
Feb 6, 2021
dbbbd21
add test of lambda code-signing-config
Feb 6, 2021
befb9dd
modify signingProfile.fromSignginProfileAttributes
Feb 6, 2021
d090353
Update packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts
Feb 8, 2021
acaf8c2
Update packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts
Feb 8, 2021
30c6479
Update packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts
Feb 8, 2021
02d57b3
Update packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts
Feb 8, 2021
7c2117e
Update packages/@aws-cdk/aws-signer/lib/signing-profile.ts
Feb 8, 2021
d254142
So physical name is not configurable, deleted codeSigningConfigName f…
Feb 8, 2021
45df283
Merge branch 'aws-lambda-code-signing' of https://github.com/hedrall/…
Feb 8, 2021
21c7383
add readme of signing profile
Feb 9, 2021
342c5fc
add readme of lambda code signing cconfig
Feb 9, 2021
ce82641
modify test of signing profile
Feb 9, 2021
b43dc02
add test of lambda with code signing config
Feb 9, 2021
b7fc4d2
t pMerge branch 'master' of https://github.com/hedrall/aws-cdk into a…
Feb 14, 2021
225c05a
Update packages/@aws-cdk/aws-lambda/README.md
Feb 16, 2021
1c3ce91
Update packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts
Feb 16, 2021
7b6202a
Update packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts
Feb 16, 2021
4fe3cbe
Update packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts
Feb 16, 2021
55e69a7
change platformId to platform enum like class
hedrall Feb 16, 2021
11aaf43
Merge branch 'master' of git://github.com/aws/aws-cdk into aws-lambda…
hedrall Feb 16, 2021
53240ee
delete code not need
hedrall Feb 22, 2021
d22f21c
Merge branch 'master' of git://github.com/aws/aws-cdk into aws-lambda…
hedrall Feb 22, 2021
b033424
Update packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts
Feb 23, 2021
7351a7e
Update packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts
Feb 23, 2021
817225d
Update packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts
Feb 23, 2021
2bf5cdc
Update packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts
Feb 23, 2021
6a90c8e
Update packages/@aws-cdk/aws-lambda/test/function.test.ts
Feb 23, 2021
afc9cdc
Update packages/@aws-cdk/aws-signer/README.md
Feb 23, 2021
fa08a95
Update packages/@aws-cdk/aws-signer/lib/signing-profile.ts
Feb 23, 2021
f646726
Update packages/@aws-cdk/aws-signer/lib/signing-profile.ts
Feb 23, 2021
fa40904
Update packages/@aws-cdk/aws-lambda/README.md
Feb 23, 2021
7573c5e
Fixed name inconsistencies of signer profile due to changes
hedrall Feb 23, 2021
a2b0e3f
Fixed name inconsistencies of code signing config due to changes
hedrall Feb 23, 2021
e7be9b8
Fixed remaining name mismatches.
hedrall Feb 23, 2021
dbac380
change name of propertiy signatureValidityPeriod to signatureValidity
hedrall Feb 23, 2021
07247d2
apply suggested readme change of signing profile
hedrall Feb 23, 2021
5fff48c
fix the linter violation
Feb 25, 2021
3427ea1
Apply suggestions from code review
Feb 25, 2021
8dbf3ca
Merge branch 'master' into aws-lambda-code-signing
mergify[bot] Feb 25, 2021
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
24 changes: 24 additions & 0 deletions packages/@aws-cdk/aws-lambda/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -489,3 +489,27 @@ Language-specific higher level constructs are provided in separate modules:

* `@aws-cdk/aws-lambda-nodejs`: [Github](https://github.com/aws/aws-cdk/tree/master/packages/%40aws-cdk/aws-lambda-nodejs) & [CDK Docs](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-lambda-nodejs-readme.html)
* `@aws-cdk/aws-lambda-python`: [Github](https://github.com/aws/aws-cdk/tree/master/packages/%40aws-cdk/aws-lambda-python) & [CDK Docs](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-lambda-python-readme.html)

## Code Signing

Code signing for AWS Lambda helps to ensure that only trusted code runs in your Lambda functions.
When enabled, AWS Lambda checks every code deployment and verifies that the code package is signed by a trusted source.
For more information, see [Configuring code signing for AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/configuration-codesigning.html).
The following code configures a function with code signing.

```typescript
import * as signer from '@aws-cdk/aws-signer';

const signerProfile = signer.SigningProfile(this, 'SigningProfile', {
platform: Platform.AWS_LAMBDA_SHA384_ECDSA
});

const codeSigningConfig = new lambda.CodeSigningConfig(stack, 'CodeSigningConfig', {
signingProfiles: [signingProfile],
});

new lambda.Function(this, 'Function', {
codeSigningConfig,
// ...
});
```
120 changes: 120 additions & 0 deletions packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { ISigningProfile } from '@aws-cdk/aws-signer';
import { IResource, Resource, Stack } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnCodeSigningConfig } from './lambda.generated';

nija-at marked this conversation as resolved.
Show resolved Hide resolved
/**
* Code signing configuration policy for deployment validation failure.
*/
export enum UntrustedArtifactOnDeployment {
/**
* Lambda blocks the deployment request if signature validation checks fail.
*/
ENFORCE = 'enforce',

/**
* Lambda allows the deployment of the code package, but issues a warning.
* Lambda issues a new Amazon CloudWatch metric, called a signature validation error and also stores the warning in CloudTrail.
*/
WARN = 'warn',
}

/**
* A Code Signing Config
*/
export interface ICodeSigningConfig extends IResource {
/**
* The ARN of Code Signing Config
* @attribute
*/
readonly codeSigningConfigArn: string;

/**
* The id of Code Signing Config
* @attribute
*/
readonly codeSigningConfigId: string;
}

/**
* Construction properties for a Code Signing Config object
*/
export interface CodeSigningConfigProps {
/**
* List of signing profiles that defines a
* trusted user who can sign a code package.
*/
readonly signingProfiles: ISigningProfile[],

/**
* Code signing configuration policy for deployment validation failure.
* If you set the policy to Enforce, Lambda blocks the deployment request
* if signature validation checks fail.
* If you set the policy to Warn, Lambda allows the deployment and
* creates a CloudWatch log.
*
* @default UntrustedArtifactOnDeployment.WARN
*/
readonly untrustedArtifactOnDeployment?: UntrustedArtifactOnDeployment,

/**
* Code signing configuration description.
*
* @default - No description.
*/
readonly description?: string,
}

/**
* Defines a Code Signing Config.
*
* @resource AWS::Lambda::CodeSigningConfig
*/
export class CodeSigningConfig extends Resource implements ICodeSigningConfig {
/**
* Creates a Signing Profile construct that represents an external Signing Profile.
*
* @param scope The parent creating construct (usually `this`).
* @param id The construct's name.
* @param codeSigningConfigArn The ARN of code signing config.
*/
public static fromCodeSigningConfigArn( scope: Construct, id: string, codeSigningConfigArn: string): ICodeSigningConfig {
const codeSigningProfileId = Stack.of(scope).parseArn(codeSigningConfigArn).resourceName;
if (!codeSigningProfileId) {
throw new Error(`Code signing config ARN must be in the format 'arn:aws:lambda:<region>:<account>:code-signing-config:<codeSigningConfigArn>', got: '${codeSigningConfigArn}'`);
}
const assertedCodeSigningProfileId = codeSigningProfileId;
class Import extends Resource implements ICodeSigningConfig {
public readonly codeSigningConfigArn = codeSigningConfigArn;
public readonly codeSigningConfigId = assertedCodeSigningProfileId;

constructor() {
super(scope, id);
}
}
return new Import();
}
nija-at marked this conversation as resolved.
Show resolved Hide resolved

public readonly codeSigningConfigArn: string;
public readonly codeSigningConfigId: string;

constructor(scope: Construct, id: string, props: CodeSigningConfigProps) {
super(scope, id);

const signingProfileVersionArns = props.signingProfiles.map(signingProfile => {
return signingProfile.signingProfileVersionArn;
});

const resource: CfnCodeSigningConfig = new CfnCodeSigningConfig(this, 'Resource', {
allowedPublishers: {
signingProfileVersionArns,
},
nija-at marked this conversation as resolved.
Show resolved Hide resolved
codeSigningPolicies: {
untrustedArtifactOnDeployment: props.untrustedArtifactOnDeployment ?? UntrustedArtifactOnDeployment.WARN,
},
description: props.description,
});
this.codeSigningConfigArn = resource.attrCodeSigningConfigArn;
this.codeSigningConfigId = resource.attrCodeSigningConfigId;
}
}
9 changes: 9 additions & 0 deletions packages/@aws-cdk/aws-lambda/lib/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as sqs from '@aws-cdk/aws-sqs';
import { Annotations, CfnResource, Duration, Fn, Lazy, Names, Stack } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { Code, CodeConfig } from './code';
import { ICodeSigningConfig } from './code-signing-config';
import { EventInvokeConfigOptions } from './event-invoke-config';
import { IEventSource } from './event-source';
import { FileSystem } from './filesystem';
Expand Down Expand Up @@ -290,6 +291,13 @@ export interface FunctionOptions extends EventInvokeConfigOptions {
* @default - AWS Lambda creates and uses an AWS managed customer master key (CMK).
*/
readonly environmentEncryption?: kms.IKey;

/**
* Code signing config associated with this function
*
* @default - Not Sign the Code
*/
readonly codeSigningConfig?: ICodeSigningConfig;
}

export interface FunctionProps extends FunctionOptions {
Expand Down Expand Up @@ -641,6 +649,7 @@ export class Function extends FunctionBase {
}),
kmsKeyArn: props.environmentEncryption?.keyArn,
fileSystemConfigs,
codeSigningConfigArn: props.codeSigningConfig?.codeSigningConfigArn,
});

resource.node.addDependency(this.role);
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-lambda/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export * from './event-source-mapping';
export * from './destination';
export * from './event-invoke-config';
export * from './scalable-attribute-api';
export * from './code-signing-config';

export * from './log-retention';

Expand Down
5 changes: 4 additions & 1 deletion packages/@aws-cdk/aws-lambda/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"@aws-cdk/aws-logs": "0.0.0",
"@aws-cdk/aws-s3": "0.0.0",
"@aws-cdk/aws-s3-assets": "0.0.0",
"@aws-cdk/aws-signer": "0.0.0",
"@aws-cdk/aws-sqs": "0.0.0",
"@aws-cdk/core": "0.0.0",
"@aws-cdk/cx-api": "0.0.0",
Expand All @@ -119,6 +120,7 @@
"@aws-cdk/aws-logs": "0.0.0",
"@aws-cdk/aws-s3": "0.0.0",
"@aws-cdk/aws-s3-assets": "0.0.0",
"@aws-cdk/aws-signer": "0.0.0",
"@aws-cdk/aws-sqs": "0.0.0",
"@aws-cdk/core": "0.0.0",
"@aws-cdk/cx-api": "0.0.0",
Expand Down Expand Up @@ -169,7 +171,8 @@
"props-default-doc:@aws-cdk/aws-lambda.Permission.sourceArn",
"docs-public-apis:@aws-cdk/aws-lambda.ResourceBindOptions",
"docs-public-apis:@aws-cdk/aws-lambda.VersionAttributes",
"props-physical-name:@aws-cdk/aws-lambda.EventInvokeConfigProps"
"props-physical-name:@aws-cdk/aws-lambda.EventInvokeConfigProps",
"props-physical-name:@aws-cdk/aws-lambda.CodeSigningConfigProps"
]
},
"stability": "stable",
Expand Down
102 changes: 102 additions & 0 deletions packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import '@aws-cdk/assert/jest';
import * as signer from '@aws-cdk/aws-signer';
import * as cdk from '@aws-cdk/core';
import * as lambda from '../lib';

let app: cdk.App;
let stack: cdk.Stack;
beforeEach( () => {
app = new cdk.App( {} );
stack = new cdk.Stack( app );
} );

describe('code signing config', () => {
test('default', () => {
const platform = signer.Platform.AWS_LAMBDA_SHA384_ECDSA;
const signingProfile = new signer.SigningProfile(stack, 'SigningProfile', { platform });
new lambda.CodeSigningConfig(stack, 'CodeSigningConfig', {
signingProfiles: [signingProfile],
});

expect(stack).toHaveResource('AWS::Lambda::CodeSigningConfig', {
AllowedPublishers: {
SigningProfileVersionArns: [{
'Fn::GetAtt': [
'SigningProfile2139A0F9',
'ProfileVersionArn',
],
}],
},
CodeSigningPolicies: {
UntrustedArtifactOnDeployment: lambda.UntrustedArtifactOnDeployment.WARN,
},
});
});

test('with multiple signing profiles', () => {
const signingProfile1 = new signer.SigningProfile(stack, 'SigningProfile1', { platform: signer.Platform.AWS_LAMBDA_SHA384_ECDSA });
const signingProfile2 = new signer.SigningProfile(stack, 'SigningProfile2', { platform: signer.Platform.AMAZON_FREE_RTOS_DEFAULT });
const signingProfile3 = new signer.SigningProfile(stack, 'SigningProfile3', { platform: signer.Platform.AWS_IOT_DEVICE_MANAGEMENT_SHA256_ECDSA });
new lambda.CodeSigningConfig(stack, 'CodeSigningConfig', {
signingProfiles: [signingProfile1, signingProfile2, signingProfile3],
});

expect(stack).toHaveResource('AWS::Lambda::CodeSigningConfig', {
AllowedPublishers: {
SigningProfileVersionArns: [
{
'Fn::GetAtt': [
'SigningProfile1D4191686',
'ProfileVersionArn',
],
},
{
'Fn::GetAtt': [
'SigningProfile2E013C934',
'ProfileVersionArn',
],
},
{
'Fn::GetAtt': [
'SigningProfile3A38DE231',
'ProfileVersionArn',
],
},
],
},
});
});

test('with description and with untrustedArtifactOnDeployment of "ENFORCE"', () => {
const platform = signer.Platform.AWS_LAMBDA_SHA384_ECDSA;
const signingProfile = new signer.SigningProfile(stack, 'SigningProfile', { platform });
new lambda.CodeSigningConfig(stack, 'CodeSigningConfig', {
signingProfiles: [signingProfile],
untrustedArtifactOnDeployment: lambda.UntrustedArtifactOnDeployment.ENFORCE,
description: 'test description',
});

expect(stack).toHaveResource('AWS::Lambda::CodeSigningConfig', {
CodeSigningPolicies: {
UntrustedArtifactOnDeployment: lambda.UntrustedArtifactOnDeployment.ENFORCE,
},
Description: 'test description',
});
});

test('import does not create any resources', () => {
const codeSigningConfigId = 'aaa-xxxxxxxxxx';
const codeSigningConfigArn = `arn:aws:lambda:::code-signing-config:${codeSigningConfigId}`;
const codeSigningConfig = lambda.CodeSigningConfig.fromCodeSigningConfigArn(stack, 'Imported', codeSigningConfigArn );

expect(codeSigningConfig.codeSigningConfigArn).toBe(codeSigningConfigArn);
expect(codeSigningConfig.codeSigningConfigId).toBe(codeSigningConfigId);
expect(stack).toCountResources('AWS::Lambda::CodeSigningConfig', 0);
});

test('fail import with malformed code signing config arn', () => {
const codeSigningConfigArn = 'arn:aws:lambda:::code-signing-config';

expect(() => lambda.CodeSigningConfig.fromCodeSigningConfigArn(stack, 'Imported', codeSigningConfigArn ) ).toThrow(/ARN must be in the format/);
});
});
31 changes: 31 additions & 0 deletions packages/@aws-cdk/aws-lambda/test/function.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as kms from '@aws-cdk/aws-kms';
import * as logs from '@aws-cdk/aws-logs';
import * as s3 from '@aws-cdk/aws-s3';
import * as sqs from '@aws-cdk/aws-sqs';
import * as signer from '@aws-cdk/aws-signer';
import * as cdk from '@aws-cdk/core';
import * as constructs from 'constructs';
import * as _ from 'lodash';
Expand Down Expand Up @@ -2003,6 +2004,36 @@ describe('function', () => {
});
});
});

describe('code signing config', () => {
test('default', () => {
const stack = new cdk.Stack();

const signingProfile = new signer.SigningProfile(stack, 'SigningProfile', {
platform: signer.Platform.AWS_LAMBDA_SHA384_ECDSA,
});

const codeSigningConfig = new lambda.CodeSigningConfig(stack, 'CodeSigningConfig', {
signingProfiles: [signingProfile],
});

new lambda.Function(stack, 'MyLambda', {
code: new lambda.InlineCode('foo'),
handler: 'index.handler',
runtime: lambda.Runtime.NODEJS_10_X,
codeSigningConfig,
});

expect(stack).toHaveResource('AWS::Lambda::Function', {
CodeSigningConfigArn: {
'Fn::GetAtt': [
'CodeSigningConfigD8D41C10',
'CodeSigningConfigArn',
],
},
});
});
});
});

function newTestLambda(scope: constructs.Construct) {
Expand Down
Loading