如何把设备安全的接入AWS IoT(一)


原文链接:https://aws.amazon.com/cn/blogs/china/connect-your-devices-to-aws-iot-securely-1/

区域:cn-northwest-1 接收设备名称:IoTDemo/#

1. 新建ec2 选择IAM角色AWSIoTDeviceAccessWorkshop,选择开放了22端口的安全组

虚机配置:安装 sudo yum install lrzsz 

aws --version查看aws cli版本,若为1.0版本python为2.X版本,则需要重装aws cli到2.0版本

2. 卸载并重装aws cli

卸载aws cli:

pip3 uninstall awscli
sudo rm -rf /usr/local/aws
sudo rm /usr/local/bin/aws

重装aws cli:

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

重装完后新开窗查看aws cli版本

注意:只有ec2-user用户python和aws版本会升级,root用户不会升级,原因未知。若不升级aws cli版本,照原文档中步骤,会提示版本过低。

 继续使用ec2-user用户,不要使用root用户。root用户的版本还是1版本

sudo -s 切换用户后,exit进行退出

3. 配置操作环境

aws configure权限 区域为cn-northwest-1

准备操作目录。

mkdir -p ~/awsIoTAccessDemo cd ~/awsIoTAccessDemo/

下载证书

① wget https://www.amazontrust.com/repository/AmazonRootCA1.pem

②  Public-Primary-Certification-Authority-G5.pem证书到 https://docs.broadcom.com/docs/verisign-class-3-public-primary-certification-authority-g5-en 下载

安装依赖

sudo yum install python3-pip3 jq -y
pip3 install boto3 --user
pip3 install AWSIoTPythonSDK --user
pip3 install flask --user
pip3 install paho-mqtt --user

获取 Account Id

account_id=`aws sts get-caller-identity | jq .Account|sed 's/"//g'`

获取 Account 的 IoT Endpoint 前缀

endpoint_prefix=`aws iot describe-endpoint \
| jq .endpointAddress | sed 's/"//g'| awk -F . '{print $1}'`

把 Account Id 和 IoT 的 Endpoint 前缀配置到环境变量中。

echo "export account_id=$account_id" >> ~/.bashrc
echo "export endpoint_prefix=$endpoint_prefix" >> ~/.bashrc

echo $accout_id 命令查看account_id是否有值,endpoint_prefix同理。 cat ~/.bashrc 命令,查看bashrc文件是否已经新增了account_id等的值

4. 创建IAM身份及权限

若之前存在IotDeviceUser用户及对应策略,从IAM控制台,角色和策略中,删除

创建一个 IAM 用户,IoTDeviceUser

aws iam create-user --user-name IoTDeviceUser

为 IoTDeviceUser 用户创建 Access Key

aws iam create-access-key \
    --user-name IoTDeviceUser > /tmp/IoT_demo_access_key

记录下 AccessKeyId 和 SecretAccessKey

AccessKeyId=`cat /tmp/IoT_demo_access_key| jq .AccessKey.AccessKeyId| sed 's/"//g'`
SecretAccessKey=`cat /tmp/IoT_demo_access_key| jq .AccessKey.SecretAccessKey| sed 's/"//g'`

echo $ 变量名,查看AccessKeyId和SecretAccessKey的值,若值不存在,可cat /tmp/IoT_demo_access_key查看文件的值,若文件中值不存在,可在控制台删除IAM用户,重复4中的内容。

5. 设备接入HTTP协议

为设备创建 IAM Policy,代理名称:IoTDeviceIAMHttpPolicy。注意修改区域,cn-northwest-1

device_IAM_http_policy_arn=`aws iam create-policy \
--policy-name IoTDeviceIAMHttpPolicy \
--policy-document "{
    \"Version\": \"2012-10-17\",
    \"Statement\": [
        {
            \"Sid\": \"VisualEditor0\",
            \"Effect\": \"Allow\",
            \"Action\": \"iot:Publish\",
            \"Resource\": [
                \"arn:aws-cn:iot:cn-northwest-1:${account_id}:topic/IoTDemo/device_IAM_http\"
            ]
        }
    ]
}" | jq .Policy.Arn | sed 's/"//g'`

把 IAM Policy 绑定 IAM 用户

aws iam attach-user-policy --user-name IoTDeviceUser \
--policy-arn ${device_IAM_http_policy_arn}

生成设备模拟程序, 注意修改区域

python代码,parser传入参数。device_name设备名称,即使用ec2模拟设备的ec2名称。

boto3.client初始化推送,client.publish进行推送

cat < ~/awsIoTAccessDemo/device_IAM_http.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import boto3
import argparse
import json
#获取参数

parser = argparse.ArgumentParser(description='Send data to IoT Core')
parser.add_argument('--data', default="data from device_IAM_http",
            help='data to IoT core topic')
parser.add_argument('--AccessKeyId', required=True,
            help='AccessKeyId')
parser.add_argument('--SecretAccessKey', required=True,
            help='SecretAccessKey')

args = parser.parse_args()
data = args.data
access_key_id = args.AccessKeyId
secret_access_key = args.SecretAccessKey

device_name = 'device_IAM_http'
region = 'cn-northwest-1'
topic = "IoTDemo/"+device_name

iot_data_client = boto3.client('iot-data',region_name=region,aws_access_key_id=access_key_id,aws_secret_access_key=secret_access_key)

response = iot_data_client.publish(
    topic=topic,
    qos=0,
    payload=json.dumps({"source":device_name, "data":data})
)
EOF

打开aws控制台,搜索iot,测试-订阅主题- IoTDemo/# -订阅

运行设备模拟程序,注意使用python3。--data "推送内容"

python3 device_IAM_http.py --data "data from device IAM http." \
--AccessKeyId ${AccessKeyId} --SecretAccessKey ${SecretAccessKey}

aws控制台会收到消息

 6.  设备使用 MQTT OVER WEBSOCKET 接入

为设备创建IAM Policy,代理名称:IoTDeviceIAMWebsocketPolicy。注意修改区域

device_IAM_websocket_policy_arn=`aws iam create-policy \
--policy-name IoTDeviceIAMWebsocketPolicy \
--policy-document "{
    \"Version\": \"2012-10-17\",
    \"Statement\": [
        {
            \"Sid\": \"VisualEditor0\",
            \"Effect\": \"Allow\",
            \"Action\": [
                \"iot:Publish\",
                \"iot:Receive\"
            ],
            \"Resource\": \"arn:aws-cn:iot:cn-northwest-1:${account_id}:topic/IoTDemo/device_IAM_websocket\"
        },
        {
            \"Sid\": \"VisualEditor1\",
            \"Effect\": \"Allow\",
            \"Action\": \"iot:Connect\",
            \"Resource\": \"arn:aws-cn:iot:cn-northwest-1:${account_id}:client/device_IAM_websocket\"
        },
        {
            \"Sid\": \"VisualEditor2\",
            \"Effect\": \"Allow\",
            \"Action\": \"iot:Subscribe\",
            \"Resource\": \"arn:aws-cn:iot:cn-northwest-1:${account_id}:topicfilter/IoTDemo/device_IAM_websocket\"
        }
    ]
}" | jq .Policy.Arn | sed 's/"//g'`

把 IAM Policy 绑定 IAM 用户,将代理绑定到IoTDeviceUser用户

aws iam attach-user-policy --user-name IoTDeviceUser \
--policy-arn ${device_IAM_websocket_policy_arn}

生成设备模拟程序

cat < ~/awsIoTAccessDemo/device_IAM_websocket.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
import json
import time
import sys
import argparse

parser = argparse.ArgumentParser(description='Send data to IoT Core')
parser.add_argument('--endpoint_prefix', required=True,
            help='endpoint prefix')
parser.add_argument('--AccessKeyId', required=True,
            help='AccessKeyId')
parser.add_argument('--SecretAccessKey', required=True,
            help='SecretAccessKey')

args = parser.parse_args()
endpoint_prefix = args.endpoint_prefix
access_key_id = args.AccessKeyId
secret_access_key = args.SecretAccessKey

device_name = 'device_IAM_websocket'
region = 'cn-northwest-1'
private_topic = "IoTDemo/"+device_name

base_path = "."
server_root_ca_file = base_path + "/AmazonRootCA1.pem"

endpoint = "%s.iot.cn-northwest-1.amazonaws.com.cn" % endpoint_prefix
port = 443

# Custom MQTT message callback
def customCallback(client, userdata, message):
    print("Received a new message: ")
    print(message.payload)
    print("from topic: ")
    print(message.topic)
    print("--------------\n\n")

def pub_msg():
    try:
        pri_loopCount = 0
        while True:
            print ("please input:"),
            msg = raw_input()
            private_data = msg
            message = {}
            message['message'] = json.dumps({"source":device_name, "data":private_data})
            message['sequence'] = pri_loopCount
            messageJson = json.dumps(message)
            myAWSIoTMQTTClient.publish(private_topic, messageJson, 1)
            pri_loopCount += 1
            time.sleep(2)
    except:
        sys.exit()

if __name__ == '__main__':
    # Init AWSIoTMQTTClient
    myAWSIoTMQTTClient = None
    myAWSIoTMQTTClient = AWSIoTMQTTClient(device_name, useWebsocket=True)
    myAWSIoTMQTTClient.configureEndpoint(endpoint, port)
    myAWSIoTMQTTClient.configureCredentials(server_root_ca_file)
    myAWSIoTMQTTClient.configureIAMCredentials(access_key_id, secret_access_key)

    # AWSIoTMQTTClient connection configuration
    myAWSIoTMQTTClient.configureAutoReconnectBackoffTime(1, 32, 20)
    myAWSIoTMQTTClient.configureOfflinePublishQueueing(-1)  # Infinite offline Publish queueing
    myAWSIoTMQTTClient.configureDrainingFrequency(2)  # Draining: 2 Hz
    myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10)  # 10 sec
    myAWSIoTMQTTClient.configureMQTTOperationTimeout(5)  # 5 sec

    # Connect and subscribe to AWS IoT
    myAWSIoTMQTTClient.connect()
    myAWSIoTMQTTClient.subscribe(private_topic, 1, customCallback)
    time.sleep(2)

    pub_msg()
EOF

运行设备模拟程序。 注意使用python3

python3 device_IAM_websocket.py --endpoint_prefix ${endpoint_prefix} \
--AccessKeyId ${AccessKeyId} --SecretAccessKey ${SecretAccessKey}

此设备模拟程序会一直运行,接受输入的数据,发送到 AWS IoT Core,同时也订阅自己发送消息的 topic。

输入要发送到 AWS IoT 的消息,如 “data from device IAM websocket.”,设备会接收到自己发送的这个消息。同时,在4.3章节中打开的控制台中也可以看到此消息。

执行 Ctrl+C 停止程序

7. 资源清理(可选)

aws iam detach-user-policy --user-name IoTDeviceUser --policy-arn arn:aws-cn:iam::${account_id}:policy/IoTDeviceIAMHttpPolicy
aws iam detach-user-policy --user-name IoTDeviceUser --policy-arn arn:aws-cn:iam::${account_id}:policy/IoTDeviceIAMWebsocketPolicy
aws iam delete-policy --policy-arn arn:aws-cn:iam::${account_id}:policy/IoTDeviceIAMHttpPolicy
aws iam delete-policy --policy-arn arn:aws-cn:iam::${account_id}:policy/IoTDeviceIAMWebsocketPolicy
AccessKeyId=`cat /tmp/IoT_demo_access_key| jq .AccessKey.AccessKeyId| sed 's/"//g'`
aws iam delete-access-key --access-key-id $AccessKeyId --user-name IoTDeviceUser
aws iam delete-user --user-name IoTDeviceUser
rm -f /tmp/IoT_demo_access_key

照aws原文中踩坑后,自己总结备忘

AWS