如何通过无服务器标记和 vpc 自定义资源 lambda?

问题描述 投票:0回答:1

我正在使用

serverless
将 lambda 和 APIGateway 部署到 AWS。我发现无服务器在部署期间自动部署了一个随机名称的 lambda。就是附加一些apigateway调用lambda所需的角色策略。这个 lambda 不是我管理的。

例如,当您使用如下 http 端点部署 lambda 时:

  handler: xxx
  events:
    - http:
        path: '/v1/order'
        method: 'post'

serverless
将部署一个具有自动生成名称的 lambda,该名称在 apigateway 上附加一个角色,以便能够调用此 lambda。我在底部附上了这个 lambda 源代码。 lambda 标记
aws:cloudformation:stack-name
与同一 serverless.yml 中的其他资源位于同一堆栈中。

我正在寻找的是如何在那些自动生成的 lambda 上添加标签。以及如何在这些 lambda 上附加 VPC?

我尝试将标签和 vpc 放在

provider
下,但无服务器不接收它们。

其中一个lambda代码是:

'use strict';

const { awsRequest, wait } = require('../utils');
const { getEnvironment, handlerWrapper } = require('../utils');

async function handler(event, context) {
  if (event.RequestType === 'Create') {
    return create(event, context);
  } else if (event.RequestType === 'Update') {
    return update(event, context);
  } else if (event.RequestType === 'Delete') {
    return remove(event, context);
  }
  throw new Error(`Unhandled RequestType ${event.RequestType}`);
}

async function create(event, context) {
  const { RoleArn } = event.ResourceProperties;
  const { Partition: partition, AccountId: accountId, Region: region } = getEnvironment(context);

  const assignedRoleArn = (
    await awsRequest({ name: 'APIGateway', params: { region } }, 'getAccount')
  ).cloudwatchRoleArn;

  let roleArn = `arn:${partition}:iam::${accountId}:role/serverlessApiGatewayCloudWatchRole`;
  if (RoleArn) {
    // if there's a roleArn in the Resource Properties, just re-use it here
    roleArn = RoleArn;
  } else {
    // Create an own API Gateway role if the roleArn was not set via Resource Properties
    const apiGatewayPushToCloudWatchLogsPolicyArn = `arn:${partition}:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs`;

    const roleName = roleArn.slice(roleArn.lastIndexOf('/') + 1);

    const attachedPolicies = await (async () => {
      try {
        return (await awsRequest('IAM', 'listAttachedRolePolicies', { RoleName: roleName }))
          .AttachedPolicies;
      } catch (error) {
        if (error.code === 'NoSuchEntity') {
          // Role doesn't exist yet, create;
          await awsRequest('IAM', 'createRole', {
            AssumeRolePolicyDocument: JSON.stringify({
              Version: '2012-10-17',
              Statement: [
                {
                  Effect: 'Allow',
                  Principal: {
                    Service: ['apigateway.amazonaws.com'],
                  },
                  Action: ['sts:AssumeRole'],
                },
              ],
            }),
            Path: '/',
            RoleName: roleName,
          });
          return [];
        }
        throw error;
      }
    })();

    if (
      !attachedPolicies.some(
        (policy) => policy.PolicyArn === apiGatewayPushToCloudWatchLogsPolicyArn
      )
    ) {
      await awsRequest('IAM', 'attachRolePolicy', {
        PolicyArn: apiGatewayPushToCloudWatchLogsPolicyArn,
        RoleName: roleName,
      });
    }
  }

  // there's nothing to do if the role is the same
  if (roleArn === assignedRoleArn) return null;

  const updateAccount = async (counter = 1) => {
    try {
      await awsRequest({ name: 'APIGateway', params: { region } }, 'updateAccount', {
        patchOperations: [
          {
            op: 'replace',
            path: '/cloudwatchRoleArn',
            value: roleArn,
          },
        ],
      });
    } catch (error) {
      if (counter < 10) {
        // Observed fails with errors marked as non-retryable. Still they're outcome of
        // temporary state where just created AWS role is not being ready for use (yet)
        await wait(10000);
        return updateAccount(++counter);
      }
      throw error;
    }
    return null;
  };

  return updateAccount();
}

function update() {
  // No actions
}

function remove() {
  // No actions
}

module.exports = {
  handler: handlerWrapper(handler, 'CustomResourceApiGatewayAccountCloudWatchRole'),
};

amazon-web-services serverless-framework
1个回答
0
投票

如何在这些 lambda 上附加 VPC?

您可以在 2 个级别上应用 VPC:

  • provider.vpc
    :将 VPC 配置应用于您服务中的所有功能
  • functions.<LambdaName>.vpc
    :为特定功能添加VPC配置

文档:

伪代码:

# add VPC configuration to a specific function
functions:
  hello:
    handler: handler.hello
    vpc:
      securityGroupIds:
        - securityGroupId1
        - securityGroupId2
      subnetIds:
        - subnetId1
        - subnetId2

# apply VPC configuration to all functions in your service  
provider:
  name: aws
  vpc:
    securityGroupIds:
      - securityGroupId1
      - securityGroupId2
    subnetIds:
      - subnetId1
      - subnetId2

我正在寻找的是如何在那些自动生成的 lambda 上添加标签

Serverless Framework 中有 3 级标签,它们被传递给 CloudFormation。

  • provider.tags
    :应用于 API 和函数的 CloudFormation 标签
  • provider.stackTags
    :应用于堆栈和所有支持资源的 CloudFormation 标签。标签应用于其所有子资源,包括自动生成的资源
  • functions.<LambdaName>.tags
    :功能特定的标签

文档:

伪代码:

provider:
  name: aws
  tags: # CloudFormation tags to apply to APIs and functions
    key: value
  stackTags: # CloudFormation tags to apply to the stack and all 
    key: value

    
functions:
  hello:
    handler: handler.hello
    tags: # Function specific tags
      key: value

重要提示: 在这两种情况下,VPC 或标签配置、继承和覆盖都在起作用。您可以在更高级别定义一个值(

provider.vpc
)并在资源级别覆盖它(
functions.<LambdaName>.vpc

© www.soinside.com 2019 - 2024. All rights reserved.