in source/patterns/@aws-solutions-constructs/core/lib/lambda-helper.ts [64:173]
export function deployLambdaFunction(scope: Construct,
lambdaFunctionProps: lambda.FunctionProps,
functionId?: string,
vpc?: ec2.IVpc): lambda.Function {
const _functionId = functionId ? functionId : 'LambdaFunction';
const _functionRoleId = _functionId + 'ServiceRole';
if (vpc && lambdaFunctionProps.vpc) {
throw new Error(
"Cannot provide a VPC in both the lambdaFunctionProps and the function argument"
);
}
// Setup the IAM Role for Lambda Service
const lambdaServiceRole = new iam.Role(scope, _functionRoleId, {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
inlinePolicies: {
LambdaFunctionServiceRolePolicy: new iam.PolicyDocument({
statements: [new iam.PolicyStatement({
actions: [
'logs:CreateLogGroup',
'logs:CreateLogStream',
'logs:PutLogEvents'
],
resources: [`arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:/aws/lambda/*`]
})]
})
}
});
// If this Lambda function is going to access resoures in a
// VPC, then it needs privileges to access an ENI in that VPC
if (lambdaFunctionProps.vpc || vpc) {
lambdaServiceRole.addToPolicy(new iam.PolicyStatement({
actions: [
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface",
"ec2:AssignPrivateIpAddresses",
"ec2:UnassignPrivateIpAddresses"
],
resources: ["*"]
}));
}
// Override the DefaultFunctionProps with user provided lambdaFunctionProps
let finalLambdaFunctionProps: lambda.FunctionProps = overrideProps(DefaultLambdaFunctionProps(lambdaServiceRole), lambdaFunctionProps);
if (vpc) {
// This is literally setting up what would be the default SG, but
// we need to to it explicitly to disable the cfn_nag error
const lambdaSecurityGroup = buildSecurityGroup(
scope,
"ReplaceDefaultSecurityGroup",
{
vpc,
allowAllOutbound: true,
},
[],
[]
);
finalLambdaFunctionProps = overrideProps(finalLambdaFunctionProps, {
securityGroups: [ lambdaSecurityGroup ],
vpc,
});
}
const lambdafunction = new lambda.Function(scope, _functionId, finalLambdaFunctionProps);
if (lambdaFunctionProps.runtime === lambda.Runtime.NODEJS_14_X ||
lambdaFunctionProps.runtime === lambda.Runtime.NODEJS_14_X ||
lambdaFunctionProps.runtime === lambda.Runtime.NODEJS_14_X) {
lambdafunction.addEnvironment('AWS_NODEJS_CONNECTION_REUSE_ENABLED', '1', { removeInEdge: true });
}
const cfnLambdafunction: lambda.CfnFunction = lambdafunction.node.findChild('Resource') as lambda.CfnFunction;
addCfnSuppressRules(lambdafunction, [
{
id: 'W58',
reason: `Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with tighter permissions.`
},
{
id: 'W89',
reason: `This is not a rule for the general case, just for specific use cases/industries`
},
{
id: 'W92',
reason: `Impossible for us to define the correct concurrency for clients`
}
]);
if (cfnLambdafunction.tracingConfig) {
// Find the X-Ray IAM Policy
const cfnLambdafunctionDefPolicy = lambdafunction.role?.node.tryFindChild('DefaultPolicy')?.node.findChild('Resource') as iam.CfnPolicy;
// Add the CFN NAG suppress to allow for "Resource": "*" for AWS X-Ray
addCfnSuppressRules(cfnLambdafunctionDefPolicy, [
{
id: 'W12',
reason: `Lambda needs the following minimum required permissions to send trace data to X-Ray and access ENIs in a VPC.`
}
]);
}
return lambdafunction;
}