diff --git a/packages/@aws-cdk/aws-lambda/README.md b/packages/@aws-cdk/aws-lambda/README.md index b3fb466ec7253..569569f526736 100644 --- a/packages/@aws-cdk/aws-lambda/README.md +++ b/packages/@aws-cdk/aws-lambda/README.md @@ -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, + // ... +}); +``` diff --git a/packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts b/packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts new file mode 100644 index 0000000000000..0472eb5d048f5 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/lib/code-signing-config.ts @@ -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'; + +/** + * 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:::code-signing-config:', 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(); + } + + 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, + }, + codeSigningPolicies: { + untrustedArtifactOnDeployment: props.untrustedArtifactOnDeployment ?? UntrustedArtifactOnDeployment.WARN, + }, + description: props.description, + }); + this.codeSigningConfigArn = resource.attrCodeSigningConfigArn; + this.codeSigningConfigId = resource.attrCodeSigningConfigId; + } +} diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index fdcf4b4e0ec24..8d487276a6176 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -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'; @@ -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 { @@ -641,6 +649,7 @@ export class Function extends FunctionBase { }), kmsKeyArn: props.environmentEncryption?.keyArn, fileSystemConfigs, + codeSigningConfigArn: props.codeSigningConfig?.codeSigningConfigArn, }); resource.node.addDependency(this.role); diff --git a/packages/@aws-cdk/aws-lambda/lib/index.ts b/packages/@aws-cdk/aws-lambda/lib/index.ts index 1ba17427c5210..2d936755d6ad1 100644 --- a/packages/@aws-cdk/aws-lambda/lib/index.ts +++ b/packages/@aws-cdk/aws-lambda/lib/index.ts @@ -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'; diff --git a/packages/@aws-cdk/aws-lambda/package.json b/packages/@aws-cdk/aws-lambda/package.json index de51f290aa4f5..6eab5cd11b870 100644 --- a/packages/@aws-cdk/aws-lambda/package.json +++ b/packages/@aws-cdk/aws-lambda/package.json @@ -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", @@ -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", @@ -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", diff --git a/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts b/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts new file mode 100644 index 0000000000000..3e123ab5d5d89 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda/test/code-signing-config.test.ts @@ -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/); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda/test/function.test.ts b/packages/@aws-cdk/aws-lambda/test/function.test.ts index 51cfe70fd878c..50cf6b0c9b72b 100644 --- a/packages/@aws-cdk/aws-lambda/test/function.test.ts +++ b/packages/@aws-cdk/aws-lambda/test/function.test.ts @@ -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'; @@ -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) { diff --git a/packages/@aws-cdk/aws-signer/README.md b/packages/@aws-cdk/aws-signer/README.md index 5482a0b23c900..925261fd4be52 100644 --- a/packages/@aws-cdk/aws-signer/README.md +++ b/packages/@aws-cdk/aws-signer/README.md @@ -9,12 +9,55 @@ > > [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + --- -This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. +AWS Signer is a fully managed code-signing service to ensure the trust and integrity of your code. Organizations validate code against +a digital signature to confirm that the code is unaltered and from a trusted publisher. For more information, see [What Is AWS +Signer?](https://docs.aws.amazon.com/signer/latest/developerguide/Welcome.html) + +## Table of Contents + +- [Signing Platform](#signing-platform) +- [Signing Profile](#signing-profile) + +## Signing Platform + +A signing platform is a predefined set of instructions that specifies the signature format and signing algorithms that AWS Signer should use +to sign a zip file. For more information go to [Signing Platforms in AWS Signer](https://docs.aws.amazon.com/signer/latest/developerguide/gs-platform.html). + +AWS Signer provides a pre-defined set of signing platforms. They are available in the CDK as - ```ts -import signer = require('@aws-cdk/aws-signer'); +Platform.AWS_IOT_DEVICE_MANAGEMENT_SHA256_ECDSA +Platform.AWS_LAMBDA_SHA384_ECDSA +Platform.AMAZON_FREE_RTOS_TI_CC3220SF +Platform.AMAZON_FREE_RTOS_DEFAULT ``` + +## Signing Profile + +A signing profile is a code-signing template that can be used to pre-define the signature specifications for a signing job. +A signing profile includes a signing platform to designate the file type to be signed, the signature format, and the signature algorithms. +For more information, visit [Signing Profiles in AWS Signer](https://docs.aws.amazon.com/signer/latest/developerguide/gs-profile.html). + +The following code sets up a signing profile for signing lambda code bundles - + +```ts +import * as signer from '@aws-cdk/aws-signer'; + +const signingProfile = new signer.SigningProfile(this, 'SigningProfile', { + platform: signer.Platform.AWS_LAMBDA_SHA384_ECDSA, +} ); +``` + +A signing profile is valid by default for 135 months. This can be modified by specifying the `signatureValidityPeriod` property. diff --git a/packages/@aws-cdk/aws-signer/lib/index.ts b/packages/@aws-cdk/aws-signer/lib/index.ts index 9c56379e86c19..090dec21fac3b 100644 --- a/packages/@aws-cdk/aws-signer/lib/index.ts +++ b/packages/@aws-cdk/aws-signer/lib/index.ts @@ -1,2 +1,3 @@ // AWS::Signer CloudFormation Resources: export * from './signer.generated'; +export * from './signing-profile'; diff --git a/packages/@aws-cdk/aws-signer/lib/signing-profile.ts b/packages/@aws-cdk/aws-signer/lib/signing-profile.ts new file mode 100644 index 0000000000000..8a0d14c3d194a --- /dev/null +++ b/packages/@aws-cdk/aws-signer/lib/signing-profile.ts @@ -0,0 +1,178 @@ +import { Duration, IResource, Resource, Stack } from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { CfnSigningProfile } from './signer.generated'; + +/** + * Platforms that are allowed with signing config. + * @see https://docs.aws.amazon.com/signer/latest/developerguide/gs-platform.html + */ +export class Platform { + /** + * Specification of signature format and signing algorithms for AWS IoT Device. + */ + public static readonly AWS_IOT_DEVICE_MANAGEMENT_SHA256_ECDSA = new Platform('AWSIoTDeviceManagement-SHA256-ECDSA'); + + /** + * Specification of signature format and signing algorithms for AWS Lambda. + */ + public static readonly AWS_LAMBDA_SHA384_ECDSA = new Platform('AWSLambda-SHA384-ECDSA'); + + /** + * Specification of signature format and signing algorithms with + * SHA1 hash and RSA encryption for Amazon FreeRTOS. + */ + public static readonly AMAZON_FREE_RTOS_TI_CC3220SF = new Platform('AmazonFreeRTOS-TI-CC3220SF'); + + /** + * Specification of signature format and signing algorithms with + * SHA256 hash and ECDSA encryption for Amazon FreeRTOS. + */ + public static readonly AMAZON_FREE_RTOS_DEFAULT = new Platform('AmazonFreeRTOS-Default'); + + /** + * The id of signing platform. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-signer-signingprofile.html#cfn-signer-signingprofile-platformid + */ + public readonly platformId: string; + + private constructor(platformId: string) { + this.platformId = platformId; + } +} + +/** + * A Signer Profile + */ +export interface ISigningProfile extends IResource { + /** + * The ARN of the signing profile. + * @attribute + */ + readonly signingProfileArn: string; + + /** + * The name of signing profile. + * @attribute ProfileName + */ + readonly signingProfileName: string; + + /** + * The version of signing profile. + * @attribute ProfileVersion + */ + readonly signingProfileVersion: string; + + /** + * The ARN of signing profile version. + * @attribute ProfileVersionArn + */ + readonly signingProfileVersionArn: string; +} + +/** + * Construction properties for a Signing Profile object + */ +export interface SigningProfileProps { + /** + * The Signing Platform available for signing profile. + * @see https://docs.aws.amazon.com/signer/latest/developerguide/gs-platform.html + */ + readonly platform: Platform; + + /** + * The validity period for signatures generated using + * this signing profile. + * + * @default - 135 months + */ + readonly signatureValidity?: Duration; + + /** + * Physical name of this Signing Profile. + * + * @default - Assigned by CloudFormation (recommended). + */ + readonly signingProfileName?: string; +} + +/** + * A reference to a Signing Profile + */ +export interface SigningProfileAttributes { + /** + * The name of signing profile. + */ + readonly signingProfileName: string; + + /** + * The version of signing profile. + */ + readonly signingProfileVersion: string; +} + +/** + * Defines a Signing Profile. + * + * @resource AWS::Signer::SigningProfile + */ +export class SigningProfile extends Resource implements ISigningProfile { + /** + * 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 attrs A `SigningProfileAttributes` object. + */ + public static fromSigningProfileAttributes( scope: Construct, id: string, attrs: SigningProfileAttributes): ISigningProfile { + class Import extends Resource implements ISigningProfile { + public readonly signingProfileArn: string; + public readonly signingProfileName = attrs.signingProfileName; + public readonly signingProfileVersion = attrs.signingProfileVersion; + public readonly signingProfileVersionArn: string; + + constructor(signingProfileArn: string, signingProfileProfileVersionArn: string) { + super(scope, id); + this.signingProfileArn = signingProfileArn; + this.signingProfileVersionArn = signingProfileProfileVersionArn; + } + } + const signingProfileArn = Stack.of(scope).formatArn({ + service: 'signer', + resource: '', + resourceName: `/signing-profiles/${attrs.signingProfileName}`, + }); + const SigningProfileVersionArn = Stack.of(scope).formatArn({ + service: 'signer', + resource: '', + resourceName: `/signing-profiles/${attrs.signingProfileName}/${attrs.signingProfileVersion}`, + }); + return new Import(signingProfileArn, SigningProfileVersionArn); + } + + public readonly signingProfileArn: string; + public readonly signingProfileName: string; + public readonly signingProfileVersion: string; + public readonly signingProfileVersionArn: string; + + constructor(scope: Construct, id: string, props: SigningProfileProps) { + super(scope, id, { + physicalName: props.signingProfileName, + }); + + const resource = new CfnSigningProfile( this, 'Resource', { + platformId: props.platform.platformId, + signatureValidityPeriod: props.signatureValidity ? { + type: 'DAYS', + value: props.signatureValidity?.toDays(), + } : { + type: 'MONTHS', + value: 135, + }, + } ); + + this.signingProfileArn = resource.attrArn; + this.signingProfileName = resource.attrProfileName; + this.signingProfileVersion = resource.attrProfileVersion; + this.signingProfileVersionArn = resource.attrProfileVersionArn; + } +} diff --git a/packages/@aws-cdk/aws-signer/package.json b/packages/@aws-cdk/aws-signer/package.json index 40a8f5872b5b1..f01a984dfdd28 100644 --- a/packages/@aws-cdk/aws-signer/package.json +++ b/packages/@aws-cdk/aws-signer/package.json @@ -79,16 +79,18 @@ "pkglint": "0.0.0" }, "dependencies": { - "@aws-cdk/core": "0.0.0" + "@aws-cdk/core": "0.0.0", + "constructs": "^3.2.0" }, "peerDependencies": { - "@aws-cdk/core": "0.0.0" + "@aws-cdk/core": "0.0.0", + "constructs": "^3.2.0" }, "engines": { "node": ">= 10.13.0 <13 || >=13.7.0" }, "stability": "experimental", - "maturity": "cfn-only", + "maturity": "experimental", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-signer/test/signer.test.ts b/packages/@aws-cdk/aws-signer/test/signer.test.ts deleted file mode 100644 index e394ef336bfb4..0000000000000 --- a/packages/@aws-cdk/aws-signer/test/signer.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import '@aws-cdk/assert/jest'; -import {} from '../lib'; - -test('No tests are specified for this package', () => { - expect(true).toBe(true); -}); diff --git a/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts b/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts new file mode 100644 index 0000000000000..6148a6be70bda --- /dev/null +++ b/packages/@aws-cdk/aws-signer/test/signing-profile.test.ts @@ -0,0 +1,115 @@ +import '@aws-cdk/assert/jest'; +import * as cdk from '@aws-cdk/core'; +import * as signer from '../lib'; + +let app: cdk.App; +let stack: cdk.Stack; +beforeEach( () => { + app = new cdk.App( {} ); + stack = new cdk.Stack( app ); +} ); + +describe('signing profile', () => { + test( 'default', () => { + const platform = signer.Platform.AWS_LAMBDA_SHA384_ECDSA; + new signer.SigningProfile( stack, 'SigningProfile', { platform } ); + + expect(stack).toHaveResource('AWS::Signer::SigningProfile', { + PlatformId: platform.platformId, + SignatureValidityPeriod: { + Type: 'MONTHS', + Value: 135, + }, + }); + }); + + test( 'default with signature validity period', () => { + const platform = signer.Platform.AWS_LAMBDA_SHA384_ECDSA; + new signer.SigningProfile( stack, 'SigningProfile', { + platform, + signatureValidity: cdk.Duration.days( 7 ), + } ); + + expect(stack).toHaveResource('AWS::Signer::SigningProfile', { + PlatformId: platform.platformId, + SignatureValidityPeriod: { + Type: 'DAYS', + Value: 7, + }, + }); + }); + + test( 'default with some tags', () => { + const platform = signer.Platform.AWS_LAMBDA_SHA384_ECDSA; + const signing = new signer.SigningProfile( stack, 'SigningProfile', { platform } ); + + cdk.Tags.of(signing).add('tag1', 'value1'); + cdk.Tags.of(signing).add('tag2', 'value2'); + cdk.Tags.of(signing).add('tag3', ''); + + expect(stack).toHaveResource('AWS::Signer::SigningProfile', { + PlatformId: platform.platformId, + SignatureValidityPeriod: { + Type: 'MONTHS', + Value: 135, + }, + Tags: [ + { + Key: 'tag1', + Value: 'value1', + }, + { + Key: 'tag2', + Value: 'value2', + }, + { + Key: 'tag3', + Value: '', + }, + ], + }); + }); + + describe('import', () => { + test('from signingProfileProfileName and signingProfileProfileVersion', () => { + const signingProfileName = 'test'; + const signingProfileVersion = 'xxxxxxxx'; + const signingProfile = signer.SigningProfile.fromSigningProfileAttributes(stack, 'Imported', { + signingProfileName, + signingProfileVersion, + }); + + expect(stack.resolve(signingProfile.signingProfileArn)).toStrictEqual( + { + 'Fn::Join': [ + '', + [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':signer:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + `://signing-profiles/${signingProfileName}`, + ], + ], + }, + ); + expect(stack.resolve(signingProfile.signingProfileVersionArn)).toStrictEqual({ + 'Fn::Join': [ + '', + [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':signer:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + `://signing-profiles/${signingProfileName}/${signingProfileVersion}`, + ], + ], + }); + expect(stack).toMatchTemplate({}); + }); + } ); +});