AWS设备自定义身份认证需要通过lambda服务实现,具体来说,首先需要创建一个lambda函数,在函数中实现具体的认证逻辑,然后Iot在调用授权方时,将触发lambda函数,返回认证结果。
1.输入参数说明
授权方在调用lambda函数时,将传递相关的参数信息,具体内容如下所示:
{
"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.
},
}
2.创建lambda函数
操作地址:函数 – Lambda (amazonaws.cn)
编写函数逻辑:
如果检测到用户密码为test,则认证通过,并附加允许策略,其他情况,则附加拒绝策略。
console.log('Loading function');
exports.handler = function(event, context, callback) {
var uname = event.protocolData.mqtt.username;
var pwd = event.protocolData.mqtt.password;
var buff = Buffer.from(pwd, 'base64');
var passwd = buff.toString('ascii');
console.log(passwd);
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) {
console.log(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:cn-northwest-1:xxxxxx:client/*"];
publishStatement.Action = ["iot:Publish"];
publishStatement.Effect = effect;
publishStatement.Resource = ["arn:aws:iot:cn-northwest-1:xxxxxx:topic/test/battery"];
policyDocument.Statement[0] = connectStatement;
policyDocument.Statement[1] = publishStatement;
authResponse.policyDocuments = [policyDocument];
authResponse.disconnectAfterInSeconds = 3600;
authResponse.refreshAfterInSeconds = 300;
return authResponse;
}
3.创建授权方
通过aws cli命令行工具创建授权方,或者在Iot Core控制台直接创建授权方,
aws iot create-authorizer --authorizer-name TestAuthorizer --authorizer-function-arn arn:aws-cn:lambda:cn-northwest-1:xxxxxx:function:AceAuthorizor --status ACTIVE --signing-disabled
4.授权方添加权限
通过aws cli命令行的方式给授权方添加调用lambda的权限,
aws lambda add-permission --function-name TestAuthorizer --principal iot.amazonaws.com --source-arn arn:aws-cn:iot:cn-northwest-1:xxxxxx:authorizer/TestAuthorizer --statement-id Id-124 --action "lambda:InvokeFunction"
5.测试授权方
通过aws cli测试授权方调用lambda是否成功
aws iot test-invoke-authorizer --authorizer-name TestAuthorizer --mqtt-context "username=xxxxx,password=dGVzdA==,clientId=demo1"
密码正确,则返回授权的策略内容,如下图所示
6.总结
这里要注意aws cli 的配置,我这里最开始用IAM Role方式配置命令行,
刚开始一直报权限问题,后来直接换成用户凭证的方式配置,
报错“An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws-cn:iam::xxxxxx:user/test is not authorized to perform: sts:AssumeRole on resource: arn:aws-cn:iam::xxxxxx:role/JITP”,后来在目录“C:\Users\用户\.aws”下config文件去掉role_arn,问题才解决。
另外,要注意给授权放添加调用lambda的权限,否则测试一直报错"An error occurred (InvalidResponseException) when calling the TestInvokeAuthorizer operation: AccessDeniedException encountered when invoking lambda; requestId: 53bc3fb4-80d2-4f89-ac98-4d529444ee48"