export function deployLambdaFunction()

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;
}