Skip to content

Commit 12cf209

Browse files
authored
update error mapping to catch when Lambda layer ARN regions do not match function region (#2216)
* Revert "add validation if layer arn region does not match function region (#2188)" This reverts commit 4e97389. * update error mapping to catch when Lambda layer ARN regions do not match function region * update changeset
1 parent 443e2ff commit 12cf209

File tree

6 files changed

+44
-65
lines changed

6 files changed

+44
-65
lines changed

.changeset/violet-tools-clap.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@aws-amplify/backend': patch
3+
'@aws-amplify/backend-deployer': patch
4+
'@aws-amplify/backend-function': patch
5+
---
6+
7+
update error mapping to catch when Lambda layer ARN regions do not match function region

packages/backend-deployer/src/cdk_error_mapper.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,12 @@ const testErrorMappings = [
380380
errorName: 'MissingDefineBackendError',
381381
expectedDownstreamErrorMessage: undefined,
382382
},
383+
{
384+
errorMessage: `User: <bootstrap-exec-role-arn> is not authorized to perform: lambda:GetLayerVersion on resource: <resource-arn> because no resource-based policy allows the lambda:GetLayerVersion action`,
385+
expectedTopLevelErrorMessage: 'Unable to get Lambda layer version',
386+
errorName: 'GetLambdaLayerVersionError',
387+
expectedDownstreamErrorMessage: undefined,
388+
},
383389
];
384390

385391
void describe('invokeCDKCommand', { concurrency: 1 }, () => {

packages/backend-deployer/src/cdk_error_mapper.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,15 @@ export class CdkErrorMapper {
196196
errorName: 'MultipleSandboxInstancesError',
197197
classification: 'ERROR',
198198
},
199+
{
200+
errorRegex:
201+
/User:(.*) is not authorized to perform: lambda:GetLayerVersion on resource:(.*) because no resource-based policy allows the lambda:GetLayerVersion action/,
202+
humanReadableErrorMessage: 'Unable to get Lambda layer version',
203+
resolutionMessage:
204+
'Make sure layer ARNs are correct and layer regions match function region',
205+
errorName: 'GetLambdaLayerVersionError',
206+
classification: 'ERROR',
207+
},
199208
{
200209
// Also extracts the first line in the stack where the error happened
201210
errorRegex: new RegExp(
@@ -360,4 +369,5 @@ export type CDKDeploymentError =
360369
| 'FileConventionError'
361370
| 'ModuleNotFoundError'
362371
| 'SecretNotSetError'
363-
| 'SyntaxError';
372+
| 'SyntaxError'
373+
| 'GetLambdaLayerVersionError';

packages/backend-function/src/factory.test.ts

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { NodeVersion, defineFunction } from './factory.js';
1717
import { lambdaWithDependencies } from './test-assets/lambda-with-dependencies/resource.js';
1818
import { Runtime } from 'aws-cdk-lib/aws-lambda';
1919
import { Policy, PolicyStatement } from 'aws-cdk-lib/aws-iam';
20-
import { AmplifyUserError } from '@aws-amplify/platform-core';
2120

2221
const createStackAndSetContext = (): Stack => {
2322
const app = new App();
@@ -412,38 +411,6 @@ void describe('AmplifyFunctionFactory', () => {
412411
});
413412
});
414413

415-
void describe('layers property', () => {
416-
void it('defaults to no layers', () => {
417-
const lambda = defineFunction({
418-
entry: './test-assets/default-lambda/handler.ts',
419-
}).getInstance(getInstanceProps);
420-
const template = Template.fromStack(lambda.stack);
421-
422-
template.resourceCountIs('AWS::Lambda::LayerVersion', 0);
423-
});
424-
425-
void it('throws if layer arn region is not the same as function region', () => {
426-
assert.throws(
427-
() =>
428-
defineFunction({
429-
entry: './test-assets/default-lambda/handler.ts',
430-
layers: {
431-
layer1:
432-
'arn:aws:lambda:some-region:123456789012:layer:my-layer-1:1',
433-
},
434-
}).getInstance(getInstanceProps),
435-
(error: AmplifyUserError) => {
436-
assert.strictEqual(
437-
error.message,
438-
'Region in ARN does not match function region for layer: layer1'
439-
);
440-
assert.ok(error.resolution);
441-
return true;
442-
}
443-
);
444-
});
445-
});
446-
447414
void describe('minify property', () => {
448415
void it('sets minify to false', () => {
449416
const lambda = defineFunction({

packages/backend-function/src/factory.ts

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@ import {
2323
SsmEnvironmentEntry,
2424
StackProvider,
2525
} from '@aws-amplify/plugin-types';
26-
import { Duration, Lazy, Stack, Tags, Token } from 'aws-cdk-lib';
26+
import { Duration, Stack, Tags } from 'aws-cdk-lib';
2727
import { Rule } from 'aws-cdk-lib/aws-events';
2828
import * as targets from 'aws-cdk-lib/aws-events-targets';
2929
import { Policy } from 'aws-cdk-lib/aws-iam';
30-
import { CfnFunction, LayerVersion, Runtime } from 'aws-cdk-lib/aws-lambda';
30+
import {
31+
CfnFunction,
32+
ILayerVersion,
33+
LayerVersion,
34+
Runtime,
35+
} from 'aws-cdk-lib/aws-lambda';
3136
import { NodejsFunction, OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs';
3237
import { Construct } from 'constructs';
3338
import { readFileSync } from 'fs';
@@ -345,10 +350,19 @@ class FunctionGenerator implements ConstructContainerEntryGenerator {
345350
scope,
346351
backendSecretResolver,
347352
}: GenerateContainerEntryProps) => {
353+
// resolve layers to LayerVersion objects for the NodejsFunction constructor using the scope.
354+
const resolvedLayers = Object.entries(this.props.layers).map(([key, arn]) =>
355+
LayerVersion.fromLayerVersionArn(
356+
scope,
357+
`${this.props.name}-${key}-layer`,
358+
arn
359+
)
360+
);
361+
348362
return new AmplifyFunction(
349363
scope,
350364
this.props.name,
351-
this.props,
365+
{ ...this.props, resolvedLayers },
352366
backendSecretResolver,
353367
this.outputStorageStrategy
354368
);
@@ -368,39 +382,14 @@ class AmplifyFunction
368382
constructor(
369383
scope: Construct,
370384
id: string,
371-
props: HydratedFunctionProps,
385+
props: HydratedFunctionProps & { resolvedLayers: ILayerVersion[] },
372386
backendSecretResolver: BackendSecretResolver,
373387
outputStorageStrategy: BackendOutputStorageStrategy<FunctionOutput>
374388
) {
375389
super(scope, id);
376390

377391
this.stack = Stack.of(scope);
378392

379-
// resolve layers to LayerVersion objects for the NodejsFunction constructor using the scope.
380-
const resolvedLayers = Object.entries(props.layers).map(([key, arn]) => {
381-
const layerRegion = arn.split(':')[3];
382-
// If region is an unresolved token, use lazy to get region
383-
const region = Token.isUnresolved(this.stack.region)
384-
? Lazy.string({
385-
produce: () => this.stack.region,
386-
})
387-
: this.stack.region;
388-
389-
if (layerRegion !== region) {
390-
throw new AmplifyUserError('InvalidLayerArnRegionError', {
391-
message: `Region in ARN does not match function region for layer: ${key}`,
392-
resolution:
393-
'Update the layer ARN with the same region as the function',
394-
});
395-
}
396-
397-
return LayerVersion.fromLayerVersionArn(
398-
scope,
399-
`${props.name}-${key}-layer`,
400-
arn
401-
);
402-
});
403-
404393
const runtime = nodeVersionMap[props.runtime];
405394

406395
const require = createRequire(import.meta.url);
@@ -443,7 +432,7 @@ class AmplifyFunction
443432
timeout: Duration.seconds(props.timeoutSeconds),
444433
memorySize: props.memoryMB,
445434
runtime: nodeVersionMap[props.runtime],
446-
layers: resolvedLayers,
435+
layers: props.resolvedLayers,
447436
bundling: {
448437
...props.bundling,
449438
banner: bannerCode,

packages/backend-function/src/layer_parser.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const createStackAndSetContext = (): Stack => {
2020
app.node.setContext('amplify-backend-name', 'testEnvName');
2121
app.node.setContext('amplify-backend-namespace', 'testBackendId');
2222
app.node.setContext('amplify-backend-type', 'branch');
23-
const stack = new Stack(app, 'Stack', { env: { region: 'us-east-1' } });
23+
const stack = new Stack(app);
2424
return stack;
2525
};
2626

0 commit comments

Comments
 (0)