【问题标题】:How to obtain AWS IOT endpoint URL from within a CloudFormation template?如何从 CloudFormation 模板中获取 AWS IOT 端点 URL?
【发布时间】:2017-11-19 05:00:09
【问题描述】:

我希望我的一些 Lambda 资源使用 aws-sdkAWS.IotData({ endpoint: url }) 函数推送到 AWS IOT 终端节点 - 其中终端节点是必需参数。

现在,我通过环境变量将端点 URL 传递给我的 Lambda。但是,当放入 SAM/CF 模板时,我找不到检索 IOT 端点 URL 的方法,因此我可以简单地 !Ref 它。

浏览AWS resource type reference我没有找到任何与IOT端点对应的资源。

似乎只能通过 AWS 控制台(启用/禁用)手动配置 IOT 端点,如下面的屏幕截图所示:

关于如何控制配置 IOT 端点或至少从 SAM/CF 模板中读取 IOT URL 的任何建议,而无需使用 aws-cli 编写脚本?

【问题讨论】:

    标签: amazon-web-services aws-lambda amazon-cloudformation aws-iot


    【解决方案1】:

    对于任何对 CloudFormation 自定义资源解决方案感兴趣的人,我编写了一个简单的 Lambda 和一个 CF 模板,为其他 CF 堆栈提供 IOT 端点地址。

    模板.yaml

    AWSTemplateFormatVersion: '2010-09-09'
    Transform: 'AWS::Serverless-2016-10-31'
    Resources:
      IotEndpointProvider:
        Type: 'AWS::Serverless::Function'
        Properties:
          FunctionName: IotEndpointProvider
          Handler: iotEndpointProvider.handler
          Runtime: nodejs6.10
          CodeUri: .
          MemorySize: 128
          Timeout: 3
          Policies:
            - Version: '2012-10-17'
              Statement:
              - Effect: Allow
                Action: 
                  - iot:DescribeEndpoint
                Resource:
                  - '*'
      IotEndpoint:
        Type: 'Custom::IotEndpoint'
        Properties:
          ServiceToken: !GetAtt IotEndpointProvider.Arn
    Outputs:
      IotEndpointAddress:
        Value: !GetAtt IotEndpoint.IotEndpointAddress
        Export:
          Name: IotEndpointAddress
    

    iotEndpointProvider.js

    var aws = require("aws-sdk");
    
    exports.handler = function(event, context) {
        console.log("REQUEST RECEIVED:\n" + JSON.stringify(event));
    
        // For Delete requests, immediately send a SUCCESS response.
        if (event.RequestType == "Delete") {
            sendResponse(event, context, "SUCCESS");
            return;
        }
    
        const iot = new aws.Iot();
        iot.describeEndpoint({}, (err, data) => {
        let responseData, responseStatus;
            if (err) {
                responseStatus = "FAILED";
                responseData = { Error: "describeEndpoint call failed" };
                console.log(responseData.Error + ":\n", err);
            } else  {
                responseStatus = "SUCCESS";
                responseData = { IotEndpointAddress: data.endpointAddress };
                console.log('response data: ' + JSON.stringify(responseData));
            }
    
            sendResponse(event, context, responseStatus, responseData);
        });
    };
    
    // Send response to the pre-signed S3 URL 
    function sendResponse(event, context, responseStatus, responseData) {
    
        var responseBody = JSON.stringify({
            Status: responseStatus,
            Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName,
            PhysicalResourceId: context.logStreamName,
            StackId: event.StackId,
            RequestId: event.RequestId,
            LogicalResourceId: event.LogicalResourceId,
            Data: responseData
        });
    
        console.log("RESPONSE BODY:\n", responseBody);
    
        var https = require("https");
        var url = require("url");
    
        var parsedUrl = url.parse(event.ResponseURL);
        var options = {
            hostname: parsedUrl.hostname,
            port: 443,
            path: parsedUrl.path,
            method: "PUT",
            headers: {
                "content-type": "",
                "content-length": responseBody.length
            }
        };
    
        console.log("SENDING RESPONSE...\n");
    
        var request = https.request(options, function(response) {
            console.log("STATUS: " + response.statusCode);
            console.log("HEADERS: " + JSON.stringify(response.headers));
            // Tell AWS Lambda that the function execution is done  
            context.done();
        });
    
        request.on("error", function(error) {
            console.log("sendResponse Error:" + error);
            // Tell AWS Lambda that the function execution is done  
            context.done();
        });
    
        // write data to request body
        request.write(responseBody);
        request.end();
    }
    

    【讨论】:

    • 是否意味着每次我需要获取endPoint url时我都必须调用这个lambda函数?
    • 这取决于您的需求,但在这种情况下,lambda 将作为自定义资源在 CloudFormation 模板部署期间被触发一次,以向需要知道该 URL 的所有资源提供 URL。
    • 感谢您的回答,您能告诉我如何在同一个 repo 和其他 repos 中准确引用该 url 吗?我可以做这样的事情吗 - 环境:IOT_END_POINT: ${self: Outputs.IotEndPointAddress} ?
    • 我对 CloudFormation 还很陌生,而且还在搞清楚很多事情
    【解决方案2】:

    恐怕您无法配置 IoT 端点,因为与 IoT 端点相关的唯一 API 调用是 DescribeEndpoint

    您可以创建一个支持 Lambda 的 CloudFormation 自定义资源。 Lambda 函数将执行 DescribeEndpoint 调用(使用您选择的 AWS 开发工具包,具体取决于 Lambda 的运行时)并返回终端节点的 URL,以便您的其他 CloudFormation 资源可以使用它。

    以下是 Lambda 支持的自定义资源的一个很好的示例:http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html

    【讨论】:

      猜你喜欢
      • 2018-07-21
      • 2020-12-15
      • 2020-12-19
      • 2020-06-06
      • 2019-08-28
      • 2018-03-19
      • 2015-04-27
      • 2019-08-20
      • 1970-01-01
      相关资源
      最近更新 更多