如何在 Cloudformation 模板/CDK 中添加 AWS IoT 配置模板

Posted

技术标签:

【中文标题】如何在 Cloudformation 模板/CDK 中添加 AWS IoT 配置模板【英文标题】:How to add AWS IoT provisioning template in Cloudformation template / CDK 【发布时间】:2020-12-15 12:28:06 【问题描述】:

我正在使用 Cloudformation 模板创建一个堆栈,其中包括 IoT 队列配置模板,根据 the document,IoT 配置模板正文应该是字符串类型。

我有这样的 IoT 队列配置模板:


  "Parameters": 
    "SerialNumber": 
      "Type": "String"
    ,  
    "AWS::IoT::Certificate::Id": 
      "Type": "String"
    
  ,
  "Resources": 
    "certificate": 
      "Properties": 
        "CertificateId": 
          "Ref": "AWS::IoT::Certificate::Id"
        ,
        "Status": "Active"
      ,
      "Type": "AWS::IoT::Certificate"
    ,
    "policy": 
      "Properties": 
        "PolicyName": "mypolicy"
      ,
      "Type": "AWS::IoT::Policy"
    ,
    "thing": 
      "OverrideSettings": 
        "AttributePayload": "MERGE",
        "ThingGroups": "REPLACE",
        "ThingTypeName": "REPLACE"
      ,
      "Properties": 
        "AttributePayload":        
          "SerialNumber": 
            "Ref": "SerialNumber"
                    
        ,             
        "ThingName": 
          "Ref": "SerialNumber"
        
      ,
      "Type": "AWS::IoT::Thing"
    
  

Cloudformation 模板是这样的:

AWSTemplateFormatVersion: '2010-09-09'
Description: "Template to create iot"

Resources: 
  FleetProvisioningTemplate:
    Type: AWS::IoT::ProvisioningTemplate
    Properties: 
      Description: Fleet provisioning template
      Enabled: true      
      ProvisioningRoleArn: "arn:aws:iam::1234567890:role/IoT-role"      
      TemplateBody: String
      TemplateName: mytemplate

我尝试将 IoT 配置模板的 JSON 字符串用于模板正文,但没有成功。我的问题是如何使用 Cloudformation 模板创建 IoT 配置模板?

更新 事实证明,我可以将 IoT 配置模板添加为“文字块”

AWSTemplateFormatVersion: '2010-09-09'
Description: "Template to create iot"

Resources: 
  FleetProvisioningTemplate:
    Type: AWS::IoT::ProvisioningTemplate
    Properties: 
      Description: Fleet provisioning template
      Enabled: true      
      ProvisioningRoleArn: "arn:aws:iam::1234567890:role/IoT-role"      
      TemplateBody: |
        
          "Parameters": 
            "SerialNumber": 
              "Type": "String"
            ,
            "AWS::IoT::Certificate::Id": 
              "Type": "String"
            
          ,
          "Resources":             
            "certificate": 
              "Properties": 
                "CertificateId": 
                  "Ref": "AWS::IoT::Certificate::Id"
                ,
                "Status": "Active"
              ,
              "Type": "AWS::IoT::Certificate"
            ,
            "policy": 
              "Properties": 
                "PolicyName": "cto-full-function-dev"
              ,
              "Type": "AWS::IoT::Policy"
            ,
            "thing": 
              "OverrideSettings": 
                "AttributePayload": "MERGE",
                "ThingGroups": "DO_NOTHING",
                "ThingTypeName": "REPLACE"
              ,
              "Properties": 
                "AttributePayload": ,
                "ThingGroups": [],
                "ThingName": 
                  "Ref": "SerialNumber"                  
                ,
                "ThingTypeName": "cto"
              ,
              "Type": "AWS::IoT::Thing"
            
          
        

      TemplateName: mytemplate

但是,当我按照the cloudformation document 所说的那样添加 PreProvisioningHook 后,模板就会失败并出现无效请求错误。

AWSTemplateFormatVersion: '2010-09-09'
Description: "Template to create iot"

Resources: 
  LambdaHook:
    Type: AWS::Lambda::Function
    ....
  FleetProvisioningTemplate:
    Type: AWS::IoT::ProvisioningTemplate
    Properties: 
      Description: Fleet provisioning template
      Enabled: true      
      ProvisioningRoleArn: "arn:aws:iam::1234567890:role/IoT-role"  
      PreProvisioningHook:               
        TargetArn: 
          "Fn::GetAtt": [
            "LambdaHook",
            "Arn"
          ]
        
        PayloadVersion: "1.0"    
      TemplateBody: |
        
          "Parameters": 
            "SerialNumber": 
              "Type": "String"
            ,
            "AWS::IoT::Certificate::Id": 
              "Type": "String"
            
          ,
          "Resources":             
            "certificate": 
              "Properties": 
                "CertificateId": 
                  "Ref": "AWS::IoT::Certificate::Id"
                ,
                "Status": "Active"
              ,
              "Type": "AWS::IoT::Certificate"
            ,
            "policy": 
              "Properties": 
                "PolicyName": "cto-full-function-dev"
              ,
              "Type": "AWS::IoT::Policy"
            ,
            "thing": 
              "OverrideSettings": 
                "AttributePayload": "MERGE",
                "ThingGroups": "DO_NOTHING",
                "ThingTypeName": "REPLACE"
              ,
              "Properties": 
                "AttributePayload": ,
                "ThingGroups": [],
                "ThingName": 
                  "Ref": "SerialNumber"                  
                ,
                "ThingTypeName": "cto"
              ,
              "Type": "AWS::IoT::Thing"
            
          
        

      TemplateName: mytemplate

我也在here 上问过问题,但没有运气。有人遇到同样的问题并解决了吗?

【问题讨论】:

【参考方案1】:

我终于想通了,但想分享一下,以防有人有同样的问题。

AWS IoT 文档未提及这一点,但如果您想为您的配置模板添加 PreProvisioningHook,您需要授予 IoT 对 lambda(AKA PreProvisioningHook)的访问权限,因此在 Cloudformation 模板中添加如下内容:

LambdaAddPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt PreProvisionHook.Arn 
      Principal: iot.amazonaws.com 

在 Provisioning Template 资源中,确保你有这个:

PreProvisioningHook:               
        PayloadVersion: '2020-04-01'
        TargetArn: 
          "Fn::GetAtt": [
            "PreProvisionHook",
            "Arn"
          ]
        

【讨论】:

非常感谢!这修复了错误:提供的请求无效:验证配置挂钩期间访问被拒绝【参考方案2】:

根据 Z Wang 的回答,这就是您在 AWS CDK 中的做法:

myLambda.addPermission('InvokePermission', 
  principal: new ServicePrincipal('iot.amazonaws.com'),
  action: 'lambda:InvokeFunction',
);

【讨论】:

【参考方案3】:

在 CDK 中,您也可以选择使用简写:

preProvisioningHookLambda.grantInvoke(new iam.ServicePrincipal('iot.amazonaws.com')) // allow iot to invoke this function

这是我供大家参考的TS代码:

import * as cdk from '@aws-cdk/core';
import * as iam from '@aws-cdk/aws-iam';
import * as lambdaNodeJS from '@aws-cdk/aws-lambda-nodejs';
import * as iot from "@aws-cdk/aws-iot";

const props = 
  stage: 'development'



const PolicyName = "DevicePolicy";
const templateName = 'DeviceProvisioningTemplateV1';
const templateBody = 
  Parameters: 
    SerialNumber: 
      Type: "String"
    ,
    ModelType: 
      Type: "String"
    ,
    "AWS::IoT::Certificate::Id": 
      Type: "String"
    
  ,
  Resources: 
    certificate: 
      Properties: 
        CertificateId: 
          Ref: "AWS::IoT::Certificate::Id"
        ,
        Status: "Active"
      ,
      Type: "AWS::IoT::Certificate"
    ,
    policy: 
      Properties: 
        PolicyName
      ,
      Type: "AWS::IoT::Policy"
    ,
    thing: 
      OverrideSettings: 
        AttributePayload: "MERGE",
        ThingGroups: "DO_NOTHING",
        ThingTypeName: "REPLACE"
      ,
      Properties: 
        ThingGroups: [],
        ThingName: 
          Ref: "SerialNumber"
        
      ,
      Type: "AWS::IoT::Thing"
    
  
;
const preProvisioningHookLambda = new lambdaNodeJS.NodejsFunction(this, `provisioning-hook-lambda-$props?.stage`, 
  entry: './src/lambda/provisioning/hook.ts',
  handler: 'handler',
  bundling: 
    externalModules: [
    ]
  ,
  timeout: cdk.Duration.seconds(5)
);
preProvisioningHookLambda.grantInvoke(new iam.ServicePrincipal('iot.amazonaws.com')) // allow iot to invoke this function

// Give the AWS IoT service permission to create or update IoT resources such as things and certificates in your account when provisioning devices
const provisioningRole = new iam.Role(this, `provisioning-role-arn-$props?.stage`, 
  assumedBy: new iam.ServicePrincipal('iot.amazonaws.com'),
);
provisioningRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSIoTThingsRegistration'));
new cdk.CfnOutput(this, 'provisioningRoleArn ',  value: provisioningRole.roleArn || 'undefined' );

const provisioningTemplate = new iot.CfnProvisioningTemplate(this, `provisioning-hook-template-$props?.stage`, 
  provisioningRoleArn: provisioningRole.roleArn,
  templateBody: JSON.stringify(templateBody),
  enabled: true,
  templateName,
  preProvisioningHook: 
    payloadVersion: '2020-04-01',
    targetArn: preProvisioningHookLambda.functionArn,
  
);

new cdk.CfnOutput(this, 'preProvisioningLambdaFunctionName ',  value: preProvisioningHookLambda.functionName || 'undefined' );
new cdk.CfnOutput(this, 'provisioningTemplateName ',  value: provisioningTemplate.templateName || 'undefined' );

【讨论】:

以上是关于如何在 Cloudformation 模板/CDK 中添加 AWS IoT 配置模板的主要内容,如果未能解决你的问题,请参考以下文章

如何在AWS CDK Policy Statement AddAction方法中嵌套键值对?

AWS - 如何使用 CDK/CloudFormation 将服务链接角色传递给自动缩放组?

如何在 AWS CDK 中使用 CfnParameter 而无需在运行时填写值

如何在 AWS CDK 中指定源安全组 ID?

通过 cloudformation 使用 aws `cdk synth` 输出

如何使用 aws cloudformation 或 aws cdk 设置 aws aurora mysql 表?