Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add AWS IoT provisioning template in Cloudformation template / CDK

I am using Cloudformation template to create a stack including IoT fleet provisioning template and according to the document the IoT provisioning template body should be string type.

I have the IoT fleet provisioning template like this:

{
  "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"
    }
  }
}

The Cloudformation template is like this:

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

I tried to use the JSON string of the IoT provisioning template for the template body but it didn't work. My question is how I can create an IoT provisioning template using Cloudformation template?

update It turned out I can add the IoT provisioning template as a 'literal block'

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

But as soon as I added the PreProvisioningHook as the cloudformation document says, the template fails with invalid request error.

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

I also asked question on here but no luck. Did any one have the same issue and fix it?

like image 976
Z Wang Avatar asked Mar 02 '23 03:03

Z Wang


1 Answers

I finally figured it out but want to share it in case someone is having the same question.

AWS IoT document doesn't mention this but if you want to add a PreProvisioningHook for your provisioning template, you need to give IoT access to the lambda, AKA PreProvisioningHook, so in the Cloudformation template, add something like this:

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

In the Provisioning Template resource, make sure you have this:

PreProvisioningHook:               
        PayloadVersion: '2020-04-01'
        TargetArn: {
          "Fn::GetAtt": [
            "PreProvisionHook",
            "Arn"
          ]
        }
like image 184
Z Wang Avatar answered May 12 '23 15:05

Z Wang