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

5
我将使用Cloudformation模板创建一个堆栈,其中包括物联网设备批量配置模板。根据文档,物联网批量配置模板的主体应为字符串类型。
我的物联网设备批量配置模板如下:
{
  "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"
    }
  }
}

云形成模板如下:
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


我尝试使用物联网配置模板的JSON字符串作为模板主体,但它没有起作用。我的问题是如何使用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: |
        {
          "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


但是,一旦我按照cloudformation文档中所说添加了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

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

3个回答

7

我终于想通了,但考虑到可能有人也有同样的问题,我想分享一下。

AWS IoT 文档没有提到这一点,但如果你想为你的预配模板添加 PreProvisioningHook,需要给 IoT 访问 Lambda(即 PreProvisioningHook)的权限。因此,在 Cloudformation 模板中,添加以下内容:

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

在“配置模板”资源中,请确保您有以下内容:
PreProvisioningHook:               
        PayloadVersion: '2020-04-01'
        TargetArn: {
          "Fn::GetAtt": [
            "PreProvisionHook",
            "Arn"
          ]
        }

非常感谢!这解决了错误:提供的请求无效:在验证配置挂钩期间拒绝访问。 - Johnny90

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' });

2

根据Z Wang的答案,以下是您在AWS CDK中实现它的方式:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接