低代码到底是不是行业毒瘤?一线大厂怎么做的?戳此了解>>> 了解详情
写点什么

物联网设备在 OTA 场景下利用证书方式进行 AWS 平台资源的授权访问

2019 年 9 月 19 日

为了保证物联网设备能够保持在功能上随时更新,并且在出现问题的时候及时得到修复。小到智能手环,空气净化器, 大到家用汽车,设备厂商无不是通过提供 OTA(Over-The-Air)功能来提高用户满意度。在做设备的 OTA 升级之前,设备厂商通常会提前把需要设备加载的固件保存在可以被设备访问的存储空间里(如果是 AWS,通常会保存在 S3 对象存储里),然后通知用户有新的固件可供升级。接下来用户通过 Web 或移动端去控制设备下载固件并完成升级过程。


在设备与 AWS IoT Core 之间实现消息收发之前,IoT Core 的设备网关会通过 X.509 证书的方式对设备进行相应的认证和授权,从而保证平台和数据的安全性。但是在 OTA 场景下,设备的固件下载是通过连接存储服务(AWS S3)来完成的,那么在这个过程中,我们需要赋予设备访问存储服务(AWS S3)的权限。然而,包括 S3 在内的许多服务并不提供通过证书方式验证和授权的功能。在此之前,我们更多用到的方法是另起一套认证系统,用户维护一个设备唯一标识的数据库,使用 AWS API Gateway, Lambda, DynamoDB, STS 等服务完成设备认证并赋予物联网设备一个 Token 后,通过 Request Signing 的方式获得 S3 的临时访问权限。使用这种认证在方式的好处是用户可以高度定制化。不过,由于设备证书通常是与设备唯一绑定的,已经可以唯一标识该设备,另起一套认证流程如果从成本和开发效率的角度上看就不是最佳方案了。好消息是随着 AWS 物联网平台功能的不断更新和迭代,AWS IoT Core 现在已经原生提供了直接使用证书的方式来获得 Token,本文将介绍这个功能 (IoT Credential Provider)的原理和使用方法,从而能够帮助用户节约成本,更快速的完成 OTA 功能的开发。



如图所示,该功能的流程如下:


  1. AWS IoT 设备发送一个包含 509 设备证书的 HTTPS 请求到 IoT Core 的 Credential Provider 模块对应的 Endpoint。

  2. IoT Credential Provider 将请求转发到 IoT 的认证授权模块来验证证书的有效性,并验证其是否有申请最终 Token 的权限。

  3. 验证成功后,IoT 的认证授权模块会返回成功的消息到 IoT Credential Provider。

  4. IoT Credential Provider 接下来调用 AWS Security Token Service (STS)得到拥有相应权限的 STS Token。

  5. IoT Credential Provider 将 Token 返回给 AWS IoT 设备端。

  6. AWS IoT 设备端拿到 Token 后使用 AWS Signature v4 签名方式来访问 AWS 资源


准备工作

本文中的 AWS IoT 设备会使用一台 Amazon Linux EC2 实例模拟,Amazon Linux EC2 实例上默认安装了 AWS 命令行工具 AWSCLI,如读者使用运行其他操作系统的实例或者自己的电脑,请参考此链接来安装 AWSCLI,并且请确保你已经赋予这台 EC2 具有足够权限的角色来执行后面的 AWSCLI 命令。在测试环境中,为简单起见,您可以赋予 IAM 和 IoT 服务的 Full Access 权限。在真实环境中,建议您按照最小权限原则,根据步骤中出现的操作,只赋予 IAM CreateRole, IAM CreatePolicy, IoT CreateThing 等等一些细粒度的权限。接下来的所有操作都是以 AWS 北京区为示例,您可以按照自己的需求通过 aws configure 命令配置不同的区域。


第一步:创建 IoT Thing 并下载证书到设备端

登陆到准备工作中创建的 Amazon Linux EC2 实例上,这里我先通过 AWS CLI 创建一个名为 my-iot-device 的 thing


$ aws iot create-thing --thing-name my-iot-device
{
"thingArn": "arn:aws-cn:iot:cn-north-1:<your_aws_account_id>:thing/my-iot-device",
"thingName": "my-iot-device",
"thingId": "162633c7-6ef4-492a-a8df-853b9315fb3b"
}
复制代码


为方便起见,我们在 AWS IoT Console 上为名为 my-iot-device 的 thing 创建设备证书和密钥,将设备证书,公钥和私钥以及 RootCA (https://www.amazontrust.com/repository/AmazonRootCA1.pem) 下载到本地后上传到 EC2 实例上




完成后,在设备端 EC2 上应该有如下四个文件:


$ ls
6ea896581d-certificate.pem.crt 6ea896581d-public.pem.key
6ea896581d-private.pem.key AmazonRootCA1.pem
复制代码


证书创建完成后,默认是没有被激活的,请记得到 AWS IOT console 的 Secure 选项里把创建出来的证书激活。



第二步:创建 IAM Role

在这个方案里,IoT Credential Provider 是作为一个中介代理存在的,它的作用就是代理设备端的请求,完成证书验证和获取 Token 的任务。因此,我们需要创建一个 IAM Role, 这个 Role 会包含两部分内容。


第一部分是和 IoT Credential Provider 建立一个 Trust Relationship 的关系,允许 IoT Credential Provider 代表设备去调用 AWS Security Token Service (STS)服务的 API AssumeRole。


第二部分我们会赋予这个 Role 访问 S3 桶的权限,这个权限会最终传递给设备端。


首先我们在设备端 EC2 上创建一个文件 trust_relationship.json,并保存如下内容到文件中:


{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": {"Service": "credentials.iot.amazonaws.com"},
"Action": "sts:AssumeRole"
}
}
复制代码


创建 IAM Role 并和 IoT Credential Provider 建立 Trust Relationship 的关系


$ aws iam create-role --role-name s3_access_role --assume-role-policy-document file://trust_relationship.json
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": {
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "credentials.iot.amazonaws.com"
}
}
},
"RoleId": "AROAV6C6662I4OLER263N",
"CreateDate": "2019-08-03T04:07:01Z",
"RoleName": "s3_access_role",
"Path": "/",
"Arn": "arn:aws-cn:iam::<your_aws_account_id>:role/s3_access_role"
}
}
复制代码


接着我们还需要授予这个 Role 读取 S3 桶中内容的权限,从而在设备端得到 Token 后可以下载固件。


创建文件 s3_access_policy.json,保存如下内容到文件中,其中 your_bucket 替换成要访问的 bucket 名字:


{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "S3:GetObject",
"Resource": [
"arn:aws-cn:s3:::your_bucket/",
"arn:aws-cn:s3:::your_bucket/*"
]
}
}
复制代码


创建 IAM Policy:


$ aws iam create-policy --policy-name s3_access_policy --policy-document file://s3_access_policy.json
{
"Policy": {
"PolicyName": "s3_access_policy",
"PermissionsBoundaryUsageCount": 0,
"CreateDate": "2019-08-03T04:10:59Z",
"AttachmentCount": 0,
"IsAttachable": true,
"PolicyId": "ANPAV6C6662I3YCACLOO6",
"DefaultVersionId": "v1",
"Path": "/",
"Arn": "arn:aws-cn:iam::<your_aws_account_id>:policy/s3_access_policy",
"UpdateDate": "2019-08-03T04:10:59Z"
}
}
复制代码


将 s3_access_policy 权限赋予 s3_access_role, 这里的–policy-arn 就是上一步命令输出中的 Policy Arn:


$ aws iam attach-role-policy --role-name s3_access_role --policy-arn arn:aws-cn:iam::<your_aws_account_id>:policy/s3_access_policy
复制代码


##第三步:创建 AWS IOT Role 别名


当设备连接 AWS IOT 的时候,设备需要知道它应该获取的是哪一个 Role,比如您可以把 s3_access_role 的 ARN 写在您的代码里。不过,这并不是一个最佳实践。如果对应的 Role ARN 发生了变化,您还需要在设备上修改代码才能保证连接性。因此,我们会建议创建一个 Role 的别名,设备利用别名去获得对应的 Role,而无论真实的 Role ARN 如何变化,在设备端您也不需要做任何更改。


创建 AWS IOT Role 别名:


$ aws iot create-role-alias --role-alias s3_access_role_alias --role-arn arn:aws-cn:iam::<your_aws_account_id>:role/s3_access_role --credential-duration-seconds 3600
{
"roleAlias": "s3_access_role_alias",
"roleAliasArn": "arn:aws-cn:iot:cn-north-1:<your_aws_account_id>:rolealias/s3_access_role_alias"
}
复制代码


其中您可以通过 –credential-duration-seconds 参数去设定 Token 的有效时间,最短 900 秒,最长 3600 秒。如果不设定,系统默认采用 3600 秒的最长时间。


这里需要注意的是,您在执行这个命令的时候,对应的 IAM user 应该有 iam:GetRole 和 iam:PassRole 的权限。增加这个权限的目的是能够将前面创建的 IAM Role s3_access_role 传递给 AWS IoT 服务。


第四步:为设备证书添加 AWS IoT Policy

在第一步中我们为设备创建了设备证书,为了让拥有该证书的设备能够通过 AWS IoT 平台获得 Token,我们还需要给设备证书添加利用证书来获得 Role 的权限 iot:AssumeRoleWithCertificate。


在 AWS IoT Console 中选择 Secure -> Policies, 并点击 Create 按钮:



分别填入 Policy Name, Action, Resource ARN, Effect 后点击 Create, 其中 Resource ARN 是第三步中创建的 Role 的别名 ARN:



回到 AWS IoT Console 中的 Manage -> Things 页面,选择 my-iot-device,在 Security 中点击之前创建的证书:



在 Policies 中选择 Actions -> Attach Policy



选择 aws_iot_policy 后点击 Attach 按钮:



第五步:设备获得 Token

接下来我们使用 Linux 的 curl 命令像 AWS IOT Credential Provider 发送一个 http 请求,从而获得 Token.


您账户下的 AWS IOT Credential Provider endpoint 地址可以通过如下命令获得:


$ aws iot describe-endpoint --endpoint-type iot:CredentialProvider
{
"endpointAddress": “abcdwfbjnlid3q.credentials.iot.cn-north-1.amazonaws.com.cn"
}在endpoint的路径后加上 /role-aliases/s3_access_role_alias/credentials,然后发送http请求:
$ curl --cert ./6ea896581d-certificate.pem.crt --key 6ea896581d-private.pem.key https://abcdwfbjnlid3q.credentials.iot.cn-north-1.amazonaws.com.cn/role-aliases/s3_access_role_alias/credentials
{"credentials":{"accessKeyId":"ASIAV6C6662IZFJNHJPB","secretAccessKey":"SfCRyD+4aterYJrjaVmShLJEr+KEgGV/LVa4B9BU","sessionToken":"FQoDYXdzEJ///////////wEaDG1oQHU14JeLxtYc/SLmArSqFV8iD4/Hipz6aIu5z6azBBRIQQLm/mQCGE7hmqmtHBo5yyO97HpGfUMxMbxrULQCJ1kzlchDmOoU1ZgK7uvK4MCS+a3ALpmzo7YyEVvlHdIa/AX3B+/jznnu6qizZNGtpwyVcwn9beZyLSk5/CTMyFRZM6A5vGd43++lGtEM8Fj+ug1/V+MpUqrl69pfvWEMqJiWSSBHUjGUv+QOTQeYiNq82xBL7GoKN255d8nZctB/uZdUZWtw6/nD6TtmcIQIiFesVhgw3zGPthPei0AM1O6xynDLCGCl1uOX4oNmYoTxAxMIMnnREciEPA97Ocf8dmlSGUgIN3uhYqI5dkmp9grMAxVbccOU6Ubtq4BnmbwZrApFktd+IKa1AhhV/w7zpMQoxBNkLIqLpVaMbMwbcdpza/dYyKC57x1t2fgZLNQPWOSKKns74VG1SyrrDoDkCLr1RPYvmiTt4MXtLzC5dCtghl4o4tuU6gU=","expiration":"2019-08-03T07:46:58Z"}}
复制代码


从命令行的输出中得到了我们需要的 accessKeyId, secretAccessKey 以及 sessionToken.


在获得了 STS Token 之后,设备上的程序就可以通过 Pre-signed URL 的方式去下载存储在 S3 桶中的固件了,具体方式请参见:


https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html


总结

利用上述方案,设备可以直接利用已集成的设备证书获得从 AWS S3 下载固件的权限。让客户能够以更低的成本,更加快捷的方式完成 OTA 功能的开发。并且,利用同样的手段分配不同的 AWS 资源权限,也可以实现对 AWS 平台上其他各类资源的访问能力,从而为 IoT 设备创造出更加丰富的功能。


作者介绍:


郭松


AWS 解决方案架构师,负责企业级客户的架构咨询及设计优化,同时致力于 AWS IoT 和存储服务在国内和全球企业客户的应用和推广。加入 AWS 之前在 EMC 研发中心担任系统工程师,对企业级存储应用的高可用架构,方案及性能调优有深入研究。


本文转载自 AWS 博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/preview-release-of-the-new-aws-tools-for-powershell/


2019 年 9 月 19 日 17:32503
用户头像

发布了 1249 篇内容, 共 33.1 次阅读, 收获喜欢 34 次。

关注

欲了解 AWS 的更多信息,请访问【AWS 技术专区】

评论

发布
暂无评论
发现更多内容

2020年6月7日 接口、lambda表达式与内部类

瑞克与莫迪

[ARTS打卡] week 02

Mau

ARTS 打卡计划

利其器

宋胖子

IDEA

架构师课程第一周作业

杉松壁

教你动手写UDP协议栈

Rice嵌入式开发技术分享

TCP udp 协议栈

《OKR工作法》读书笔记

大饼土博

读书笔记 管理 OKR

【ARTS打卡】Week02

Rex

架构师训练营-每周学习总结1

水边

极客大学架构师训练营

食堂就餐卡系统设计

上山砍柴

极客大学架构师训练营

优秀架构师具备的能力

阿飞

极客大学架构师训练营

如何用一台 MacBook 创造高额年化收益 | ETH2.0 Staking 教程

陈东泽 EuryChen

区块链 Ethereum

架构师训练营第一周学习总结

王鑫龙

极客大学架构师训练营

不可不知的 7 个 JDK 命令

武培轩

Java 程序员 jdk 后端 JVM

「架构师训练营」第1周作业 - 食堂就餐卡系统设计

guoguo 👻

极客大学架构师训练营

MySQL 笔记(一)基础架构

奈何花开

Java MySQL

程序员的晚餐 | 6 月 5 日 爆炒鱿鱼

清远

美食

Java 25周年:波澜壮阔的25年

北风

「Java 25周年」

软件架构第一章总结

itrickzhang

程序员的晚餐 | 6 月 4 日 最好吃的土豆

清远

架构设计文档之食堂就餐卡系统设计

itrickzhang

架构设计 架构文档 架构样例 架构分析 架构总结

ARTS 第 1 周

乌拉里

ARTS 打卡计划

架构文档

陈皮

架构 极客大学架构师训练营

repo 导出本地 git tag 给他人

zqb-all

git

【架构师训练营-作业-1】食堂就餐卡系统设计

小动物

系统设计 极客大学架构师训练营 作业

UML练习1 食堂就餐卡系统设计「架构师训练营」

Young

架构方法:运用合适的工具表达设计

WANDEFOUR

极客大学架构师训练营

食堂就餐卡系统设计-uml练习

森林

程序员摆地摊?你别痴心妄想了,还不如当「在地青年」呢

非著名程序员

程序员 提升认知 职业规划 认知提升

在 Windows WSL 2 中使用 Docker Desktop

FeiLong

Docker WSL2

因为 MongoDB 没入门,我丢了一份实习工作

沉默王二

mongodb

架构师训练营-命题作业1

水边

极客大学架构师训练营

2021 ThoughtWorks 技术雷达峰会

2021 ThoughtWorks 技术雷达峰会

物联网设备在 OTA 场景下利用证书方式进行 AWS 平台资源的授权访问-InfoQ