提问者:小点点

Cloudformation Elasticbeanstalk指定共享负载平衡器的目标组


我有两个Cloudformation模板

  • 创建VPC、ALB和任何其他共享资源等的一个。
  • 使用导入的共享负载均衡器(调用此模板环境)创建弹性beanstek环境和相关侦听器规则来切流量到该环境的程序

我面临的问题是环境模板创建了一个AWS::ElasticBeanstalk::Environment,随后创建了一个新的CFN堆栈,其中包含ASG和目标组(或弹性豆茎所熟知的进程)等内容。这些资源不是用于创建环境的 AWS 拥有的 CFN 模板的输出。

设置时

- Namespace: aws:elasticbeanstalk:environment
  OptionName: LoadBalancerIsShared
  Value: true

在我的elastic beanstalk环境的optionsettings中,没有创建负载平衡器,这很好。然后,我尝试将一个侦听器规则附加到我的负载平衡器侦听器上。

  ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Priority: 1
      ListenerArn:
        Fn::ImportValue: !Sub '${NetworkStackName}-HTTPS-Listener'
      Actions:
        - Type: forward
          TargetGroupArn: WHAT_GOES_HERE
      Conditions:
        - Field: host-header
          HostHeaderConfig:
            Values:
              - mywebsite.com
    DependsOn:
      - Environment

这里的问题是,据我所知,我没有访问由elastic beanstalk环境资源创建的目标组的ARN的权限。如果我创建一个目标组,那么它不会链接到elastic beanstalk,也不会出现任何实例。

我找到了这个页面,上面写着

Elastic Beanstalk 为您的环境创建的资源具有名称。可以使用这些名称通过函数获取有关资源的信息,或修改资源的属性以自定义其行为。

但是因为它们在不同的堆栈中(我事先不知道其中的名称),而不是模板的输出,我不知道如何掌握它们。

--

编辑:

Marcin在他们的回答中向我指出了自定义资源的方向。我已经稍微扩展了它并使其正常工作。实现在几个方面略有不同

  1. 它在Node而不是Python中
  2. 提供的示例中的api调用describeenvironment_resources返回资源列表,但似乎不是所有资源。在我的实现中,我获取了自动缩放组,并使用Physical Resource ID使用Cloudformation API查找堆栈中它所属的其他资源
const AWS = require('aws-sdk');
const cfnResponse = require('cfn-response');
const eb = new AWS.ElasticBeanstalk();
const cfn = new AWS.CloudFormation();

exports.handler = (event, context) => {
    if (event['RequestType'] !== 'Create') {
        console.log(event[RequestType], 'is not Create');
        return cfnResponse.send(event, context, cfnResponse.SUCCESS, {
            Message: `${event['RequestType']} completed.`,
        });
    }

    eb.describeEnvironmentResources(
        { EnvironmentName: event['ResourceProperties']['EBEnvName'] },
        function (err, { EnvironmentResources }) {
            if (err) {
                console.log('Exception', e);
                return cfnResponse.send(event, context, cfnResponse.FAILED, {});
            }

            const PhysicalResourceId = EnvironmentResources['AutoScalingGroups'].find(
                (group) => group.Name
            )['Name'];

            const { StackResources } = cfn.describeStackResources(
                { PhysicalResourceId },
                function (err, { StackResources }) {
                    if (err) {
                        console.log('Exception', e);
                        return cfnResponse.send(event, context, cfnResponse.FAILED, {});
                    }
                    const TargetGroup = StackResources.find(
                        (resource) =>
                            resource.LogicalResourceId === 'AWSEBV2LoadBalancerTargetGroup'
                    );

                    cfnResponse.send(event, context, cfnResponse.SUCCESS, {
                        TargetGroupArn: TargetGroup.PhysicalResourceId,
                    });
                }
            );
        }
    );
};

云形成模板

  LambdaBasicExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSCloudFormationReadOnlyAccess
        - arn:aws:iam::aws:policy/AWSElasticBeanstalkReadOnly
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  GetEBLBTargetGroupLambda:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Description: 'Get ARN of EB Load balancer'
      Timeout: 30
      Role: !GetAtt 'LambdaBasicExecutionRole.Arn'
      Runtime: nodejs12.x
      Code:
        ZipFile: |
          ... code ...
  ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Priority: 1
      ListenerArn:
        Fn::ImportValue: !Sub '${NetworkStackName}-HTTPS-Listener'
      Actions:
        - Type: forward
          TargetGroupArn:
            Fn::GetAtt: ['GetEBLBTargetGroupResource', 'TargetGroupArn']
      Conditions:
        - Field: host-header
          HostHeaderConfig:
            Values:
              - mydomain.com

我在做这件事时学到的东西,希望能帮助其他人

    < li >在Node中使用< code>async处理程序对于非异步的默认cfn-response库来说很困难,并且会导致云形成创建(和删除)过程在回滚之前挂起许多小时。 < li >如果您使用< code>ZipFile,cloudformation会自动包含< code>cfn-response库。如果你想手工包含代码,可以在AWS文档中找到(你也可以把它包装在promise中,然后使用异步lambda处理程序)。npm上也有包可以达到同样的效果。 < li>Node 14.x无法运行,Cloudformation出现错误。不幸的是,我没有记下那是什么。 < li >在提供的示例中使用的策略< code > AWSElasticBeanstalkFullAccess 不再存在,已被< code > administrator access-AWSElasticBeanstalk 取代。 < li >我上面的例子需要附加不太宽松的策略,但是我还没有在测试中解决这个问题。如果它能读取特定的弹性豆茎环境等就更好了。

共1个答案

匿名用户

据我所知,我无权访问由弹性 beanstalk 环境资源创建的目标组的 ARN

没错。克服这个问题的方法是通过自定义资源。事实上,我为我之前的一个答案开发了完全工作的、非常相似的资源,因此您可以查看它并采用您的模板。该资源返回EB负载均衡器的ARN,但您可以修改它以获取EB目标组的ARN。