aws Lambda在删除堆栈时创建了ENI而不删除

lax*_*man 13 amazon-web-services aws-cloudformation

CloudFormation创建Lambda函数.执行该功能时,由lambda自动配置ENI.在执行函数后,ENI似乎仍然存在,以加速后续的函数执行.CloudFormation删除lambda函数.在EN后面的遗体.尝试删除时VPC CloudFormation stack,堆栈删除失败,因为ENI正在使用a security group and subnet.

lambda roledelete permission那里.

"效果":"允许","动作":["ec2:CreateNetworkInterface","ec2:DeleteNetworkInterface","ec2:DescribeNetworkInterfaces"],"资源":"*"

我正在使用自定义资源从CloudFormation模板运行lambda,因此lambda将被称为堆栈创建和删除.ENI将用于创建堆栈和删除堆栈.现在如何处理eni删除?

wjo*_*dan 24

在VPC中使用Lambda函数时存在一个已知问题,如配置Lambda函数以访问Amazon VPC中的资源中所述:

Lambda函数执行和删除ENI之间存在延迟.如果您在执行功能后立即删除了该角色,则您有责任删除ENI.

文档没有详细说明这个"延迟"的确切时间,但Richard @ AWS的一篇论坛帖子表明它可以持续长达6个小时(!).(在我使用AWS CloudTrail的观察中,Lambda执行和ENI删除之间的延迟大约是一小时.)

在AWS进一步解决此问题之前,您可以通过在删除Lambda函数和删除关联的安全组和子网之间分离和删除剩余的ENI来解决此问题.这就是Terraform目前在其框架中处理问题的方式.

您可以通过将VPC/Subnet/SG层和Lambda函数层分离为两个不同的CloudFormation堆栈来手动执行此操作,也可以通过使用AWS SDK实现自定义资源来删除ENI来自动执行此操作.

这是一个完整的工作示例,它创建了一个VPC-Lambda自定义资源,在使用VPCDestroyENI自定义资源删除时清理其ENI :

启动堆栈

Description: Creates a VPC-Lambda Custom Resource, cleaning up ENIs when deleted.
Parameters:
  VPCId:
    Description: VPC Id
    Type: AWS::EC2::VPC::Id
  SubnetId:
    Description: Private Subnet Id
    Type: AWS::EC2::Subnet::Id
Resources:
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Lambda VPC security group
      VpcId: !Ref VPCId
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal: {Service: [lambda.amazonaws.com]}
          Action: ['sts:AssumeRole']
      Path: "/"
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
      Policies:
      - PolicyName: DetachNetworkInterface
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Action: ['ec2:DetachNetworkInterface']
            Resource: '*'
  AppendTest:
    Type: Custom::Split
    DependsOn: VPCDestroyENI
    Properties:
      ServiceToken: !GetAtt AppendItemToListFunction.Arn
      List: [1, 2, 3]
      AppendedItem: 4
  AppendItemToListFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var response = require('cfn-response');
          exports.handler = function(event, context) {
             var responseData = {Value: event.ResourceProperties.List};
             responseData.Value.push(event.ResourceProperties.AppendedItem);
             response.send(event, context, response.SUCCESS, responseData);
          };
      Timeout: 30
      Runtime: nodejs4.3
      VpcConfig:
        SecurityGroupIds: [!Ref SecurityGroup]
        SubnetIds: [!Ref SubnetId]
  VPCDestroyENIFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          var response = require('cfn-response');
          var AWS = require('aws-sdk');
          exports.handler = function(event, context) {
            console.log("REQUEST RECEIVED:\n", JSON.stringify(event));
            if (event.RequestType != 'Delete') {
              response.send(event, context, response.SUCCESS, {});
              return;
            }
            var ec2 = new AWS.EC2();
            var params = {
              Filters: [
                {
                  Name: 'group-id',
                  Values: event.ResourceProperties.SecurityGroups
                },
                {
                  Name: 'description',
                  Values: ['AWS Lambda VPC ENI: *']
                }
              ]
            };
            console.log("Deleting attachments!");
            // Detach all network-interface attachments
            ec2.describeNetworkInterfaces(params).promise().then(function(data) {
              console.log("Got Interfaces:\n", JSON.stringify(data));
              return Promise.all(data.NetworkInterfaces.map(function(networkInterface) {
                var networkInterfaceId = networkInterface.NetworkInterfaceId;
                var attachmentId = networkInterface.Attachment.AttachmentId;
                return ec2.detachNetworkInterface({AttachmentId: attachmentId}).promise().then(function(data) {
                  return ec2.waitFor('networkInterfaceAvailable', {NetworkInterfaceIds: [networkInterfaceId]}).promise();
                }).then(function(data) {
                  console.log("Detached Interface, deleting:\n", networkInterfaceId);
                  return ec2.deleteNetworkInterface({NetworkInterfaceId: networkInterfaceId}).promise();
                });
              }));
            }).then(function(data) {
              console.log("Success!");
              response.send(event, context, response.SUCCESS, {});
            }).catch(function(err) {
              console.log("Failure:\n", JSON.stringify(err));
              response.send(event, context, response.FAILED, {});
            });
          };
      Timeout: 300
      Runtime: nodejs4.3
  VPCDestroyENI:
    Type: Custom::VPCDestroyENI
    Properties:
      ServiceToken: !GetAtt VPCDestroyENIFunction.Arn
      SecurityGroups: [!Ref SecurityGroup]
Outputs:
  Output:
    Description: output
    Value: !Join [",", !GetAtt AppendTest.Value]
Run Code Online (Sandbox Code Playgroud)

注意:要创建上例中所需的VPC和专用子网,您可以使用AWS Quick Start Amazon VPC Architecture 模板.