如何从 CloudFormation 模板中获取 AWS IOT 端点 URL?
How to obtain AWS IOT endpoint URL from within a CloudFormation template?
我希望我的一些 Lambda 资源使用 aws-sdk
的 AWS.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
编写脚本的任何建议?
恐怕您无法配置 IoT 端点,因为与 IoT 端点相关的唯一 API 调用是 DescribeEndpoint
。
您可以做的是创建一个 Lambda 支持的 CloudFormation 自定义资源。 Lambda 函数将执行 DescribeEndpoint
调用(根据 Lambda 的运行时使用您选择的 AWS SDK)和 return 端点的 URL 以便您的其他 CloudFormation 资源可以使用它。
这是一个关于 Lambda 支持的自定义资源的好例子:http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html。
对于任何对使用 CloudFormation 自定义资源的解决方案感兴趣的人,我编写了一个简单的 Lambda 和一个 CF 模板,为其他 CF 堆栈提供 IOT 端点地址。
template.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();
}
我希望我的一些 Lambda 资源使用 aws-sdk
的 AWS.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
编写脚本的任何建议?
恐怕您无法配置 IoT 端点,因为与 IoT 端点相关的唯一 API 调用是 DescribeEndpoint
。
您可以做的是创建一个 Lambda 支持的 CloudFormation 自定义资源。 Lambda 函数将执行 DescribeEndpoint
调用(根据 Lambda 的运行时使用您选择的 AWS SDK)和 return 端点的 URL 以便您的其他 CloudFormation 资源可以使用它。
这是一个关于 Lambda 支持的自定义资源的好例子:http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html。
对于任何对使用 CloudFormation 自定义资源的解决方案感兴趣的人,我编写了一个简单的 Lambda 和一个 CF 模板,为其他 CF 堆栈提供 IOT 端点地址。
template.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();
}