使用 SAM CLI 建立 nodejs 的 template,並修改 template.yaml 建立一個 lambda function 與 IoTCore 的 Authorizer,並指定 Authorizer 的 function 爲該 lambda function
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
MyIoTCoreAuthorizer:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs14.x
CodeUri: ./
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- iot:Connect
Resource: 'arn:aws:iot:<region>:<account-id>:*'
MyAuthorizerFunction:
Type: AWS::IoT::Authorizer
Properties:
AuthorizerFunctionArn: !GetAtt MyIoTCoreAuthorizer.Arn
AuthorizerName: MyAuthorizer
Status: ACTIVE
SigningDisabled: True
Outputs:
MyIoTCoreAuthorizerName:
Value: !Ref MyIoTCoreAuthorizer
Export:
Name: MyIoTCoreAuthorizerName
MyAuthorizerFunctionArn:
Value: !GetAtt MyAuthorizerFunction.Arn
Export:
Name: MyAuthorizerFunctionArn
之後 build 並 deploy
sam build
sam deploy --guided
部署成功後,會獲得 IoTCore Authorizer 的 ARN 與 lambda 的名稱,透過他們替 lambda function 加上允許 IoTCore Auth Invoke Function 的權限。
aws lambda add-permission --function-name {MyIoTCoreAuthorizerName} \
--principle "iot.amazonaws.com" --action "lambda:InvokeFunction" \
--statement-id {UniqID} --source-arn {MyAuthorizerFunctionArn}
lambda 收到 request 後傳送 IoTCore 的 Policy
export const handler = async (event, context) => {
const [, , , region, accountId] = context.invokedFunctionArn.split(':');
console.log('full event', JSON.stringify(event));
const policy = {
principalId: 'test',
isAuthenticated: true,
policyDocuments: [
{
Version: '2012-10-17',
Statement: [
{
Action: 'iot:*',
Effect: 'Allow',
Resource: '*',
},
],
},
],
};
return policy;
};
之後就可以透過 MQTT Explorer 或是 MQTT.JS 進行測試
protocol 設爲 WSS,username 代入 custom IoTCore Auth Function Name
import * as mqtt from "mqtt";
const AWS_HOST = "xxx";
const connect = mqtt.connect({
hostname: AWS_HOST,
protocol: "wss",
username: "username?x-amz-customauthorizer-name=MyAuthorizer",
clientId: "test",
port: 443
});
connect.on("connect", () => {
console.log("iotcore connected");
});
可以觀看 CloudWatch 驗證是否有成功呼叫 lambda function
2023-02-16T12:36:11.929Z 41b7b8c4-661c-4abb-9bb5-e7eaf96bda50 INFO full event {
"protocolData": {
"tls": {
"serverName": "..."
},
"mqtt": {
"username": "username?x-amz-customauthorizer-name=MyAuthorizer",
"clientId": "test"
},
"http": {
"headers": {
"accept-encoding": "gzip, deflate, br",
"sec-websocket-extensions": "permessage-deflate; client_max_window_bits",
"upgrade": "websocket",
"connection": "Upgrade",
"pragma": "no-cache",
"origin": "https://zydu3d.csb.app",
"sec-websocket-key": "PMjh6zWnZONmD/AtXQ3tKg==",
"content-length": "0",
"sec-websocket-version": "13",
"cache-control": "no-cache",
"host": "...",
"accept-language": "zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
"sec-websocket-protocol": "mqtt"
},
"queryString": ""
}
},
"protocols": [
"tls",
"http",
"mqtt"
],
"signatureVerified": false,
"connectionMetadata": {
"id": "3e0deb31-b893-3841-c54a-bfbd9c927e55"
}
}
透過 username 的 query 可以代入 token 參數之類的
username?x-amz-customauthorizer-name=MyAuthorizer&token=...&key=value
即可依照參數產生相對應的 policy