创建和管理自定义授权方 - Amazon IoT Core
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

创建和管理自定义授权方

Amazon IoT Core 使用授权方资源实现自定义身份验证和授权方案。各授权方均包括以下组件:

  • 名称:用户定义的唯一字符串,用于标识授权方。

  • Lambda 函数 ARN:Lambda 函数的 Amazon Resource Name (ARN),用于实现授权和身份验证逻辑。 

  • 令牌密钥名称:用于从 HTTP 标头、查询参数或 MQTT CONNECT 用户名中提取令牌以执行签名验证的键名称。如果在授权方中启用了签名,则需要此值。

  • 签名禁用标志(可选):指定是否禁用凭证签名要求的布尔值。这对于签名凭证没有意义的情况非常有用,例如使用 MQTT 用户名和密码的身份验证方案。默认值为 false,因此默认情况下签名将处于启用状态。

  • 令牌签名公有密钥: Amazon IoT Core 用于验证令牌签名的公有密钥。其最小长度为 2048 位。如果在授权方中启用了签名,则需要此值。 

Lambda 将根据 Lambda 函数的运行次数以及函数中代码执行所需的时间向您收取费用。有关 Lambda 定价的更多信息,请参阅 Lambda 定价。有关创建 Lambda 函数的更多信息,请参阅 Lambda 开发人员指南

注意

如果启用签名,则可以防止无法识别的客户端过度触发 Lambda。在禁用授权方的签名之前,请考虑这一点。

注意

自定义授权方的 Lambda 函数超时限制为 5 秒。

定义您的 Lambda 函数

当 Amazon IoT Core 调用您的授权方时,它会使用包含以下 JSON 对象的事件触发与授权方关联的 Lambda。示例 JSON 对象包含所有可能的字段。不包括与连接请求无关的任何字段。

{     "token" :"aToken",     "signatureVerified": Boolean, // Indicates whether the device gateway has validated the signature.     "protocols": ["tls", "http", "mqtt"], // Indicates which protocols to expect for the request.     "protocolData": {         "tls" : {             "serverName": "serverName" // The server name indication (SNI) host_name string.         },         "http": {             "headers": {                 "#{name}": "#{value}"             },             "queryString": "?#{name}=#{value}"         },         "mqtt": {             "username": "myUserName",             "password": "myPassword", // A base64-encoded string.             "clientId": "myClientId" // Included in the event only when the device sends the value.         }     },     "connectionMetadata": {         "id": UUID // The connection ID. You can use this for logging.     }, }

Lambda 函数应使用此信息对传入连接进行身份验证,并决定允许在连接中执行哪些操作。函数应发送包含以下值的响应。

  • isAuthenticated:一个布尔值,指示是否已对请求进行身份验证。

  • principalId:字母数字字符串,它充当自定义授权请求发送的令牌的标识符。该值必须是包含至少一个字符且不超过 128 个字符的字母数字字符串,并与此正则表达式(正则表达式)模式匹配:([a-zA-Z0-9]){1,128}。不允许在 in principalId 中 Amazon IoT Core使用非字母数字的特殊字符。如果允许使用非字母数字特殊字符,请参阅其他 Amazon 服务的文档。principalId

  • policyDocuments:JSON 格式的 Amazon IoT Core 策略文档列表有关创建 Amazon IoT Core 策略的更多信息,请参阅。Amazon IoT Core 政策策略文档的数量最多为 10 个。每个策略文档最多可以包含 2048 个字符。

  • disconnectAfterInSeconds:指定与 Amazon IoT Core 网关的连接的最大持续时间(以秒为单位)的整数。最小值为 300 秒,最大值为 86400 秒。

  • refreshAfterInSeconds:指定策略刷新之间间隔的整数。当此时间间隔过去时, Amazon IoT Core 将调用 Lambda 函数以允许策略刷新。最小值为 300 秒,最大值为 86400 秒。

 以下 JSON 对象包含 Lambda 函数可以发送的响应示例。

{ "isAuthenticated":true, //A Boolean that determines whether client can connect. "principalId": "xxxxxxxx",  //A string that identifies the connection in logs. "disconnectAfterInSeconds": 86400,  "refreshAfterInSeconds": 300,   "policyDocuments": [       {         "Version": "2012-10-17",         "Statement": [            {               "Action": "iot:Publish",               "Effect": "Allow",               "Resource": "arn:aws:iot:us-east-1:<your_aws_account_id>:topic/customauthtesting"             }          ]        }     ] }

policyDocument值必须包含有效的 Amazon IoT Core 策略文档。有关 Amazon IoT Core 策略的更多信息,请参阅Amazon IoT Core 政策。 在 TLS 上的 MQTT 和通过 WebSockets连接的 MQ Amazon IoT Core TT 中,在字段值中指定的间隔内缓存此策略。refreshAfterInSeconds在 HTTP 连接的情况下,每个授权请求都会调用 Lambda 函数,除非您的设备使用 HTTP 持久连接(也称为 HTTP 保持活动状态或 HTTP 连接重用),否则您可以在配置授权方时选择启用缓存。在此间隔内, Amazon IoT Core 授权在已建立的连接中针对此缓存策略执行操作,而无需再次触发您的 Lambda 函数。如果在自定义身份验证期间出现故障,则 Amazon IoT Core 终止连接。 Amazon IoT Core 如果连接的打开时间超过disconnectAfterInSeconds参数中指定的值,也会终止该连接。

以下内容 JavaScript 包含一个 Node.js Lambda 函数示例,该函数在 MQTT Connect 消息中查找值为test的密码,并返回一个策略,该策略授予使用myClientName名为的客户端连接 Amazon IoT Core 并发布到包含相同客户端名称的主题的权限。如果未找到预期密码,则返回拒绝这两个操作的策略。

// A simple Lambda function for an authorizer. It demonstrates // how to parse an MQTT password and generate a response. exports.handler = function(event, context, callback) {     var uname = event.protocolData.mqtt.username;     var pwd = event.protocolData.mqtt.password;     var buff = new Buffer(pwd, 'base64');     var passwd = buff.toString('ascii');     switch (passwd) {         case 'test':             callback(null, generateAuthResponse(passwd, 'Allow'));         default:             callback(null, generateAuthResponse(passwd, 'Deny'));       } }; // Helper function to generate the authorization response. var generateAuthResponse = function(token, effect) { var authResponse = {}; authResponse.isAuthenticated = true; authResponse.principalId = 'TEST123'; var policyDocument = {}; policyDocument.Version = '2012-10-17'; policyDocument.Statement = []; var publishStatement = {}; var connectStatement = {}; connectStatement.Action = ["iot:Connect"]; connectStatement.Effect = effect; connectStatement.Resource = ["arn:aws:iot:us-east-1:123456789012:client/myClientName"]; publishStatement.Action = ["iot:Publish"]; publishStatement.Effect = effect; publishStatement.Resource = ["arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"]; policyDocument.Statement[0] = connectStatement; policyDocument.Statement[1] = publishStatement; authResponse.policyDocuments = [policyDocument]; authResponse.disconnectAfterInSeconds = 3600; authResponse.refreshAfterInSeconds = 300; return authResponse; }

上述 Lambda 函数在收到 MQTT Connect 消息中的预期密码 test 时返回以下 JSON。passwordprincipalId 属性的值将是来自 MQTT Connect 消息的值。

{ "password": "password", "isAuthenticated": true, "principalId": "principalId", "policyDocuments": [ { "Version": "2012-10-17", "Statement": [ { "Action": "iot:Connect", "Effect": "Allow", "Resource": "*" }, { "Action": "iot:Publish", "Effect": "Allow", "Resource": "arn:aws:iot:region:accountId:topic/telemetry/${iot:ClientId}" }, { "Action": "iot:Subscribe", "Effect": "Allow", "Resource": "arn:aws:iot:region:accountId:topicfilter/telemetry/${iot:ClientId}" }, { "Action": "iot:Receive", "Effect": "Allow", "Resource": "arn:aws:iot:region:accountId:topic/telemetry/${iot:ClientId}" } ] } ], "disconnectAfterInSeconds": 3600, "refreshAfterInSeconds": 300 }

创建授权方

您可以使用 CreateAuthorizerAP I 创建授权方。 以下示例描述了该命令。

aws iot create-authorizer --authorizer-name MyAuthorizer --authorizer-function-arn arn:aws:lambda:us-west-2:<account_id>:function:MyAuthorizerFunction  //The ARN of the Lambda function. [--token-key-name MyAuthorizerToken //The key used to extract the token from headers. [--token-signing-public-keys FirstKey= "-----BEGIN PUBLIC KEY-----   [...insert your public key here...]   -----END PUBLIC KEY-----" [--status ACTIVE] [--tags <value>] [--signing-disabled | --no-signing-disabled]

您可以使用 signing-disabled 参数选择退出适用于授权方的每次调用的签名验证。除有必要,否则我们强烈建议您不要禁用签名。签名验证可防止来自未知设备的 Lambda 函数过多调用。您无法在创建授权方后更新其 signing-disabled 状态。要更改此行为,您必须创建 signing-disabled 参数具有不同值的其它自定义授权方。

如果您已禁用签名,则 tokenKeyNametokenSigningPublicKeys 参数的值是可选的。如果启用了签名,则它们是必需的值。

创建 Lambda 函数和自定义授权方后,必须明确授予 Amazon IoT Core 服务权限才能代表您调用该函数。 您可以使用以下命令执行此操作。

aws lambda add-permission --function-name <lambda_function_name> --principal iot.amazonaws.com --source-arn <authorizer_arn> --statement-id Id-123 --action "lambda:InvokeFunction"

测试授权方

您可以使用 TestInvokeAuthorizerAPI 来测试授权方的调用和返回值。 此 API 使您能够在授权方中指定协议元数据并测试签名验证。  

以下选项卡显示了如何使用 Amazon CLI 来测试您的授权者。

Unix-like
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER \ --token TOKEN_VALUE --token-signature TOKEN_SIGNATURE
Windows CMD
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER ^ --token TOKEN_VALUE --token-signature TOKEN_SIGNATURE
Windows PowerShell
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER ` --token TOKEN_VALUE --token-signature TOKEN_SIGNATURE

token-signature 参数的值是签名令牌。要了解如何获取此值,请参阅 签名令牌

如果您的授权方使用了用户名和密码,您可以使用 --mqtt-context 参数传递此信息。以下选项卡显示如何使用 TestInvokeAuthorizer API 将包含用户名、密码和客户端名称的 JSON 对象发送到您的自定义授权方。

Unix-like
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER \ --mqtt-context '{"username": "USER_NAME", "password": "dGVzdA==", "clientId":"CLIENT_NAME"}'
Windows CMD
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER ^ --mqtt-context '{"username": "USER_NAME", "password": "dGVzdA==", "clientId":"CLIENT_NAME"}'
Windows PowerShell
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER ` --mqtt-context '{"username": "USER_NAME", "password": "dGVzdA==", "clientId":"CLIENT_NAME"}'

密码必须采用 base64 编码。以下示例说明如何在类 Unix 的环境中对密码进行编码。

echo -n PASSWORD | base64

管理自定义授权方

您可以使用以下 API 管理授权方。

  • ListAuthorizers: 显示您账户中的所有授权人。

  • DescribeAuthorizer:显示指定授权者的属性。这些值包括创建日期、上次修改日期和其它属性。

  • SetDefaultAuthorizer:为您的 Amazon IoT Core 数据端点指定默认授权方。 Amazon IoT Core 如果设备未通过 Amazon IoT Core 凭据且未指定授权方,则使用此授权方。有关使用 Amazon IoT Core 凭证的更多信息,请参阅客户端身份验证

  • UpdateAuthorizer:更改指定授权方的状态、令牌密钥名称或公钥。

  • DeleteAuthorizer:删除指定的授权者。

注意

您无法更新授权方的签名要求。这意味着您无法禁用需要签名的现有授权方的中签名。您也不能在不需要签名的现有授权方中要求签名。