【问题标题】:Setting up AWS IoT using Serverless Framework for Multiple IoT Devices使用无服务器框架为多个 IoT 设备设置 AWS IoT
【发布时间】:2019-02-08 23:55:01
【问题描述】:

我的目标是在 AWS 上创建一个系统,使用 serverless framework 让多个 IoT 设备将 JSON 有效负载发送到 AWS IoT,然后将其保存到 DynamoDB。

我对在创建 EC2 服务器之外使用 AWS 非常陌生,这是我使用 serverless framework 的第一个项目。

参考an example后,我想出的修改版贴在下面。

问题:看来该示例仅适用于连接到 AWS IoT 的 1 台设备,这是我从正在使用的硬编码 IoT Thing 证书得出的结论,例如

SensorPolicyPrincipalAttachmentCert:
  Type: AWS::IoT::PolicyPrincipalAttachment
  Properties:
    PolicyName: { Ref: SensorThingPolicy }
    Principal: ${{custom.iotCertificateArn}}

SensorThingPrincipalAttachmentCert:
  Type: "AWS::IoT::ThingPrincipalAttachment"
  Properties:
    ThingName: { Ref: SensorThing }
    Principal: ${self:custom.iotCertificateArn}

如果serverless.yml 仅配置用于 1 个事物这一结论是正确的,那么我们可以进行哪些修改以便可以使用超过 1 个事物?

也许设置serverless.yaml 之外的所有事物?这意味着只删除SensorPolicyPrincipalAttachmentCert 和SensorThingPrincipalAttachmentCert?

另外,我们应该如何将Resource 属性设置为SensorThingPolicy 中的?他们目前设置为"*",这是否过于宽泛?或者有没有办法限制事物。

serverless.yml

service: garden-iot

provider:
name: aws
runtime: nodejs6.10
region: us-east-1

# load custom variables from a file
custom: ${file(./vars-dev.yml)}

resources:
Resources:
    LocationData:
    Type: AWS::DynamoDB::Table
    Properties:
        TableName: location-data-${opt:stage}
        AttributeDefinitions:
        - 
            AttributeName: ClientId
            AttributeType: S
        - 
            AttributeName: Timestamp
            AttributeType: S
        KeySchema:
        - 
            AttributeName: ClientId
            KeyType: HASH
        - 
            AttributeName: Timestamp
            KeyType: RANGE
        ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1

    SensorThing:
    Type: AWS::IoT::Thing
    Properties:
        AttributePayload:
        Attributes:
            SensorType: soil

    SensorThingPolicy:
    Type: AWS::IoT::Policy
    Properties:
        PolicyDocument:
        Version: "2012-10-17"
        Statement:
            - Effect: Allow
            Action: ["iot:Connect"]
            Resource: ["${self:custom.sensorThingClientResource}"]
            - Effect: "Allow"
            Action: ["iot:Publish"]
            Resource: ["${self:custom.sensorThingSoilTopicResource}"]

    SensorPolicyPrincipalAttachmentCert:
    Type: AWS::IoT::PolicyPrincipalAttachment
    Properties:
        PolicyName: { Ref: SensorThingPolicy }
        Principal: ${{custom.iotCertificateArn}}

    SensorThingPrincipalAttachmentCert:
    Type: "AWS::IoT::ThingPrincipalAttachment"
    Properties:
        ThingName: { Ref: SensorThing }
        Principal: ${self:custom.iotCertificateArn}

IoTRole:
Type: AWS::IAM::Role
Properties:
    AssumeRolePolicyDocument:
    Version: "2012-10-17"
    Statement:
        -
        Effect: Allow
        Principal:
            Service:
            - iot.amazonaws.com
        Action:
            - sts:AssumeRole

IoTRolePolicies:
Type: AWS::IAM::Policy
Properties:
    PolicyName: IoTRole_Policy
    PolicyDocument:
    Version: "2012-10-17"
    Statement:
        -
        Effect: Allow
        Action:
            - dynamodb:PutItem
        Resource: "*"
        -
        Effect: Allow
        Action:
            - lambda:InvokeFunction
        Resource: "*"
    Roles: [{ Ref: IoTRole }]

【问题讨论】:

    标签: amazon-cloudformation iot serverless-framework serverless aws-iot


    【解决方案1】:

    EDIT 05/09/2018:我发现这篇博文很好地描述了我的方法:Ensure Secure Communication with AWS IoT Core Using the Certificate Vending Machine Reference Application

    --

    您可以查看Just-in-Time Provisioning 或基于Programmatic Provisioning 构建您自己的解决方案。

    我已经多次处理过这个话题,并且不得不意识到它在很大程度上取决于用例,这更有意义。安全性也是需要关注的一个方面。您不希望有一个公共 API 负责 JIT 设备注册,整个 Internet 都可以访问。

    一个简单的基于编程预置的场景可能如下所示:您构建一个东西(可能是一个传感器),它应该能够连接到 AWS IoT 并具有一个内部预置过程。

    简单的配置过程:

    1. 构建的东西
    2. 事物有序列号
    3. 事物通过内部服务器自行注册

    在服务器上运行的注册码可能看起来像这样(JS + AWS JS SDK):

    // Modules
    const AWS = require('aws-sdk')
    
    // AWS
    const iot = new AWS.Iot({ region: process.env.region })
    
    // Config
    const templateBodyJson = require('./register-thing-template-body.json')
    
    // registerThing
    const registerThing = async ({ serialNumber = null } = {}) => {
      if (!serialNumber) throw new Error('`serialNumber` required!')
    
      const {
        certificateArn = null,
        certificateId = null,
        certificatePem = null,
        keyPair: {
          PrivateKey: privateKey = null,
          PublicKey: publicKey = null
        } = {}
      } = await iot.createKeysAndCertificate({ setAsActive: true }).promise()
      const registerThingParams = {
        templateBody: JSON.stringify(templateBodyJson),
        parameters: {
          ThingName: serialNumber,
          SerialNumber: serialNumber,
          CertificateId: certificateId
        }
      }
      const { resourceArns = null } = await iot.registerThing(registerThingParams).promise()
    
      return {
        certificateArn,
        certificateId,
        certificatePem,
        privateKey,
        publicKey,
        resourceArns
      }
    }
    
    const unregisterThing = async ({ serialNumber = null } = {}) => {
      if (!serialNumber) throw new Error('`serialNumber` required!')
    
      try {
        const thingName = serialNumber
        const { principals: thingPrincipals } = await iot.listThingPrincipals({ thingName }).promise()
        const certificates = thingPrincipals.map((tp) => ({ certificateId: tp.split('/').pop(), certificateArn: tp }))
    
        for (const { certificateId, certificateArn } of certificates) {
          await iot.detachThingPrincipal({ thingName, principal: certificateArn }).promise()
          await iot.updateCertificate({ certificateId, newStatus: 'INACTIVE' }).promise()
          await iot.deleteCertificate({ certificateId, forceDelete: true }).promise()
        }
    
        await iot.deleteThing({ thingName }).promise()
    
        return {
          deleted: true,
          thingPrincipals
        }
      } catch (err) {
        // Already deleted!
        if (err.code && err.code === 'ResourceNotFoundException') {
          return {
            deleted: true,
            thingPrincipals: []
          }
        }
    
        throw err
      }
    }
    

    register-thing-template-body.json:

    {
      "Parameters": {
         "ThingName": {
           "Type": "String"
         },
         "SerialNumber": {
           "Type": "String"
         },
         "CertificateId": {
           "Type": "String"
         }
      },
      "Resources": {
        "thing": {
          "Type": "AWS::IoT::Thing",
          "Properties": {
            "ThingName": {
              "Ref": "ThingName"
            },
            "AttributePayload": {
              "serialNumber": {
                "Ref": "SerialNumber"
              }
            },
            "ThingTypeName": "NewDevice",
            "ThingGroups": ["NewDevices"]
          }
        },
        "certificate": {
          "Type": "AWS::IoT::Certificate",
          "Properties": {
            "CertificateId": {
              "Ref": "CertificateId"
            }
          }
        },
        "policy": {
          "Type": "AWS::IoT::Policy",
          "Properties": {
            "PolicyName": "DefaultNewDevicePolicy"
          }
        }
      }
    }
    

    确保您已准备好所有“NewDevice”事物类型、组和策略。还要记住 ThingName = SerialNumber(对于 unregisterThing 很重要)。

    【讨论】:

      猜你喜欢
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2019-01-24
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 2022-09-23
      • 1970-01-01
      相关资源
      最近更新 更多