使用无服务器框架为多个IoT设备设置AWS IoT

问题描述 投票:1回答:1

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

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

在提到an example之后,我提出的修改版本发布在下面。

问题:该示例似乎只有1台设备连接到AWS IoT,我从使用的硬编码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之外设置所有的东西?这意味着只删除SensorPolicyPrincipalAttachmentCertSensorThingPrincipalAttachmentCert

另外,我们应该如何在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个回答
1
投票

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

--

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

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

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

简单的配置过程:

  1. 事情已建成
  2. 东西有一个序列号
  3. Thing通过内部服务器注册自己

在服务器上运行的注册代码看起来像这样(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
  }
}

注册 - 事物 - 模板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”Thing类型,组和策略。还要记住ThingName = SerialNumber(对于unregisterThing很重要)。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.