亚马逊AWS官方博客

智能家居物联网平台之-设备状态管理

 简介

在上一篇智能家居物联网平台博文中,我们阐述了设备到家后如何配网以及如何构建设备中心与用户中心,本文作为系列文章的第二篇,将介绍如何管理设备的状态。

 

1.平台架构

平台采用serverless无服务器架构,⽆服务器架构是构建和运⾏应⽤程序和服务的⼀种⽅式,⽆需管基础设施。您的应⽤程序仍在服务器上运⾏,但所有服务器管理⼯作均由 AWS 来完成。您⽆需再预置、扩展和维护服务器即可运⾏您的应⽤程序、数据库和存储系统。

 

通过使⽤⽆服务器架构,您的开发⼈员能够专注于他们的核⼼产品,⽽⽆需担⼼在云中或本地管理和运⾏服务器或运⾏时。这减少了开销,并使开发⼈员能够将更多时间和精⼒放在开发可扩展且可靠的出⾊产品上。

 

2.设备状态管理

设备状态管理主要有两种场景,首先是手机app下发指令更改设备状态和接受设备状态更改消息,比如开启或者关闭设备。其次是设备状态上报,其中包括设备上下线,设备请求变更状态等等。下面我们一起来看看这些场景实现的细节。

2.1手机app下发和接收消息

AWS IoT 支持3种设备或者客户端的认证方式,分别是X.509证书,IAM 用户组和Cognito 身份认证。X.509证书主要用于设备端,Cognito 为您的 Web 和移动应用程序提供身份验证、授权和用户管理,天然的适合手机app授权管理IoT 设备。

核心原理是创建Cognito user pool让用户登陆系统,使用Cognito identity pool 绑定user pool 和手机端 app clientId。Cognito identity pool会自动为你创建两个IAM Role,一个是authenticated的role,另外一个是unauthenticated 的role,我们将使用authenticated 的role来给已登陆用户的用户赋予临时token 并授权监听和发送IoT 相关topic 以及授权其他必须的AWS 服务。

但是这里有个问题,我们要实现的目标是一个用户能绑定管理多个设备,用户只能发布和接受自己绑定的设备的消息。如果所有用户都是从一个Role 继承的权限将不能实现不同用户设备消息的隔离。所以除了继承authenticated的role,还需要继承IoT Core的policy做精细化的权限控制。

在上一篇智能家居物联网平台博文中已经介绍如何创建user pool 和手机端app clientId,接下来我们将介绍如何配置Cognito identity pool,介绍如何配置authenticated 的role 的IAM policy以及如何从IoT Core赋权给Cognito 的identity。

 

2.1.1 创建Cognito identity pool

2.1.2 点击创建身份池

2.1.3 配置身份池

填入一个pool 的名字,并在cognito窗口填写之前创建的user pool ID和App client ID,如果是使用第三方的idp 做身份认证,还需要在custom 窗口填写idp 的名字。

 

点击创建pool 之后,自动为你创建两个IAM 的role

 

2.1.4 配置IAM 策略赋权给authenticated role

打开IAM控制台,转到策略页面并打开JSON 窗口

创建Policy "cognito_user_connect_iot"
{
    "Version":"2012-10-17",
    "Statement":[
        {
            "Effect":"Allow",
            "Action":[
                "iot:Connect"
            ],
            "Resource":[
                "arn:aws:iot:*:*:client/${cognito-identity.amazonaws.com:sub}"
            ]
        },
        {
            "Effect":"Allow",
            "Action":[
                "iot:Subscribe"
            ],
            "Resource":[
                "arn:aws:iot:*:*:topicfilter/$aws/things/*/shadow/get/*",
                "arn:aws:iot:*:*:topicfilter/$aws/events/presence/connected/*",
                "arn:aws:iot:*:*:topicfilter/user/${cognito-identity.amazonaws.com:sub}/message"
            ]
        }
    ]
}

 

解读:第一条statement 主要限制了只允许当前cognito 登陆的用户才能连接IoT core,这样比较安全。第二条statement允许手机用户订阅一些主题。第一个主题是所有设备的shadow信息,第二个主题是所有设备的上下线消息,第三个主题是方便后台admin 平台(WEB端)给指定用户推送消息(也能用SNS做)。

第一和第二主题配置“*” 的好处在于但凡有新设备绑定,手机端cognito的策略都不用变,至于消息隔离的问题,我们还有IoT Core 的policy 做限制和保证安全。其实只有Subscribe的权限是不能接收和发布消息的,我们会在receive 的权限上做限制。所以这里就算配置了“*” , 手机端也不会收到全网设备的消息。

 

2.1.5 在IoT Core创建用户policy

User_Policy_Publish
{
    "Version":"2012-10-17",
    "Statement":[
        {
            "Effect":"Allow",
            "Action":[
                "iot:Publish"
            ],
            "Resource":[
                "arn:aws:iot:*:*:topic/$aws/things/{mac}/shadow/update",
                "arn:aws:iot:*:*:topic/$aws/things/{mac}/shadow/get"
            ]
        }
    ]
}

 

解读:该policy允许用户发布消息给特定设备的shadow主题,这样策略文档是会随着用户绑定设备的改变而改变,每绑定一个设备需要有两个主题的发布权限增加。

User_Policy_Receive
{
    "Version":"2012-10-17",
    "Statement":[
        {
            "Effect":"Allow",
            "Action":[
                "iot:Receive"
            ],
            "Resource":[
                "arn:aws:iot:*:*:topicfilter/user/${cognito-identity.amazonaws.com:sub}/message",
                "arn:aws:iot:*:*:topic/$aws/things/{mac}/shadow/get/*",
                "arn:aws:iot:*:*:topicfilter/$aws/events/presence/connected/{mac}"
            ]
        }
    ]
}

 

解读:该policy允许用户接收来自特定设备的shadow主题,上下线主题和admin 后台(WEB端)推送消息。这样策略文档是会随着用户绑定设备的改变而改变,每绑定一个设备需要有两个主题的接收权限增加。

 

2.1.6 使用CLI 或者API 给Cognito identiy 赋权上面两条policy

例子:

# 查看 identity-pools 的id
[cloudshell-user@ip-10-1-14-110 ~]$ aws cognito-identity list-identity-pools --max-results 10
{
    "IdentityPools": [
        {
            "IdentityPoolId": "ap-southeast-1:4b8c143d-729f-4280-af7a-d31c28c047b2",
            "IdentityPoolName": "iot-platform-idpool"
        }
    ]
}

 

# 查看cognito IdentityId
[cloudshell-user@ip-10-1-14-110 ~]$ aws cognito-identity list-identities --identity-pool-id "ap-southeast-1:4b8c143d-729f-4280-af7a-d31c28c047b2"  --max-results 10
{
    "IdentityPoolId": "ap-southeast-1:4b8c143d-729f-4280-af7a-d31c28c047b2",
    "Identities": [
        {
            "IdentityId": "ap-southeast-1:075c48c0-0aec-4c20-99c7-4aa63d5d3f7a",
            "Logins": [
                "granwin"
            ],
            "CreationDate": "2021-10-12T15:54:09.855000+00:00",
            "LastModifiedDate": "2021-10-12T15:54:09.868000+00:00"
        }]
}

 

控制台找到policy 名称

 

给用户添加 publish 和receive 的policy

# iot attachpolicy

 

import boto3
client=boto3.client('iot')
response = client.attach_policy(
    policyName='User_Policy_Publish',
    target='ap-southeast-1:075c48c0-0aec-4c20-99c7-4aa63d5d3f7a'
)

以上完成cognito 用户对指定设备的授权

 

2.1.7 手机app端通信小结

以上,完成手机app端管理消息的权限配置,流程如下:

1)app用户通过Cognito user pool登录成功之后获取token

2)使用token和Identity pool交互拿到Role,使其具有iot的权限

3)给用户附加策略,配置好用户的策略权限赋予其特定主题的发布,接收和订阅权限

4)用户在app端发起设备控制(通过更新设备影子实现)

5)设备接收到影子的改变订阅

6)设备获取最新影子,然后上报状态

7)app 收到设备上报的最新状态,更新app关于设备状态的显示

8)规则引擎转发主题消息存储设备日志到DynamoDB

 

2.2 设备端订阅和接收消息

设备端与IoT Core认证,通讯和权限控制主要依赖X.509证书,每台设备都会分配一个证书,设备和证书的绑定关系和证书与policy的绑定关系在IoT Core配置。

2.2.1 在云端创建设备

THING_NAME=device_mac_address
aws iot create-thing --thing-name $THING_NAME

 

2.2.2 创建证书并激活云端设备

# create key and certificate for your device and active the device
aws iot create-keys-and-certificate --set-as-active \
  --public-key-outfile $THING_NAME.public.key \
  --private-key-outfile $THING_NAME.private.key \
  --certificate-pem-outfile $THING_NAME.certificate.pem > /tmp/create_cert_and_keys_response
  
# look at the output from the previous command
cat /tmp/create_cert_and_keys_response

# output values from the previous call needed in further steps
CERTIFICATE_ARN=$(jq -r ".certificateArn" /tmp/create_cert_and_keys_response)
CERTIFICATE_ID=$(jq -r ".certificateId" /tmp/create_cert_and_keys_response)
echo $CERTIFICATE_ARN
echo $CERTIFICATE_ID

 

2.2.3 设备端证书策略

{
    "Version":"2012-10-17",
    "Statement":[
        {
            "Effect":"Allow",
            "Action":[
                "iot:Connect"
            ],
            "Resource":[
                "arn:aws:iot:*:*:client/{mac}"
            ]
        },
        {
            "Effect":"Allow",
            "Action":[
                "iot:Publish",
                "iot:Receive"
            ],
            "Resource":[
                "arn:aws:iot:*:*:topic/$aws/things/{mac}/shadow/*",
                "arn:aws:iot:*:*:topic/{productKey}/{mac}/*"
            ]
        },
        {
            "Effect":"Allow",
            "Action":[
                "iot:Subscribe"
            ],
            "Resource":[
                "arn:aws:iot:*:*:topicfilter/$aws/things/{mac}/shadow/*",
                "arn:aws:iot:*:*:topicfilter/{productKey}/{mac}/*"
            ]
        }
    ]
}

 

解读:mac 地址作为全局唯一标识(clientId),第一段statement只允许设备自己连上iot core。第二段允许设备发布和接收自己shadow的消息和{productKey} 下的自己的消息,{productKey} 用于区分不同的品类来做多品牌和多品类的推送管理。最后一段允许订阅自己shadow 的相关topic和多品牌和多品类的推送topic。

注:设备和product的绑定关系,以及用户与设备的绑定关系可以存放在DDB。

 

2.2.4 把策略赋权给证书

aws iot attach-policy --policy-name $POLICY_NAME \
  --target $CERTIFICATE_ARN

 

2.2.5 证书和云端设备做绑定

aws iot attach-thing-principal --thing-name $THING_NAME \
  --principal $CERTIFICATE_ARN

 

3.小结

本文接着上一篇博文,讨论如何使用Cognito 管理设备状态,并总结了app 和设备通信的流程,达到一个用户管理多个设备,用户之间和设备之间消息隔离的目的。

 

参考文档:

https://docs.aws.amazon.com/iot/latest/developerguide/cognito-identities.html

https://docs.aws.amazon.com/iot/latest/developerguide/iot-policies.html

https://docs.aws.amazon.com/cli/latest/reference/iot/attach-policy.html

https://iot-device-management.workshop.aws/en/provisioning-options/provisioning-with-api.html

 

本篇作者

张振威

AWS APN解决方案架构师,主要负责合作伙伴架构咨询和方案设计,同时致力于 亚马逊云科技云服务在国内的应用及推广。曾就职于互联网公司数据库团队,拥有丰富的平台化和自动化运维经验。

汪建业

亚马逊云科技解决方案架构师,负责基于亚马逊云科技云计算方案架构的咨询和设计,同时致力于 亚马逊云科技 IoT 和大数据服务在国内和全球企业客户的应用和推广。十余年分布式应用、大数据的分布式处理经验。