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

阅读数:325 2019 年 9 月 19 日 17:32

为了保证物联网设备能够保持在功能上随时更新,并且在出现问题的时候及时得到修复。小到智能手环,空气净化器, 大到家用汽车,设备厂商无不是通过提供 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 功能的开发。

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

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

  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 实例上

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

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

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

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

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

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

第二步:创建 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 按钮:
物联网设备在 OTA 场景下利用证书方式进行 AWS 平台资源的授权访问

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

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

回到 AWS IoT Console 中的 Manage -> Things 页面,选择 my-iot-device,在 Security 中点击之前创建的证书:
物联网设备在 OTA 场景下利用证书方式进行 AWS 平台资源的授权访问

在 Policies 中选择 Actions -> Attach Policy
物联网设备在 OTA 场景下利用证书方式进行 AWS 平台资源的授权访问

选择 aws_iot_policy 后点击 Attach 按钮:

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

第五步:设备获得 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/

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

评论

发布