AWS IoT Core カスタム認証とは
AWS IoT Coreを認証局の認証/tokenをもとに、操作権限を渡す認証方式になります。詳細はこちら
ここでは認証局を省き、簡単に設定と動作検証ができるまでの流れを説明します。
ワークフローは以下のような感じになります。
設定に必要となるもの
- 認証局 (本投稿では詳細は諸略し発行されるTokenをtextで作成する)
- AWS Lambda
- 証明書(秘密鍵、公開鍵)
- この証明書セットはJITRなどのようにAWS IoTの情報を埋める必要がなく、独自の運用局で問題ないですが、公開鍵をAWS IoTへ登録できることは必要です。
設定
公開鍵の作成をLinux上で実施、Lambdaを登録し、CLI(GUI)で登録していく流れになります。
AWS IoTへの登録は公開鍵、Authorizerを関連付けします。
鍵の作成
以下のコマンドで、秘密/公開鍵の生成を行う
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
Authorizer Lambdaの作成
AWS Lambdaを以下で作成します。Sampleとして、tokenにはallow/denyが入ってくる前提、AWS IoTも固定値を作成して返信していますが、このあたりの中身は各自必要に合わせて検討してください。
responseのJSONフォーマットは規定されているので、ご確認ください。
- IsAuthenticated:要求が認証されたかどうかを示すブール(true / false)属性です。
- PrincipalId:これは英数字の文字列です。最小長は1文字、最大長は128文字です。カスタム許可要求で受信されたトークンに関連したIDとして機能します。
- PolicyDocuments:WS IoTポリシー規則に従ったJSON形式のポリシードキュメントのリストです。このリストには最大10個のポリシー文書が含まれています。各ポリシー文書は最大2,048文字です。
- DisconnectAfterInSeconds:AWS IoTゲートウェイへの接続が切断されるまでの最大接続時間(秒単位)を示します。最小値は300秒、最大値は86,400秒です。
- RefreshAfterInSeconds:これは、ポリシーの更新間隔です。期限が切れると、Lambda関数はポリシーの更新を可能にするために再度呼び出されます。最小値は300秒、最大値は86,400秒です。
詳細はこちら
from __future__ import print_function
import uuid
import json
response = {
"isAuthenticated": True,
"principalId": str(uuid.uuid1()).replace("-", ""),
"disconnectAfterInSeconds": 84000,
"refreshAfterInSeconds": 300,
"policyDocuments": [],
"context": {
}
}
policy = {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action":["iot:Publish", "iot:Connect", "iot:Subscribe"],
"Resource": ["*"]
}]
}
def auth_main(event, context):
print("your event payload:{}".format(json.dumps(event)))
print("this request token:{}".format(event["token"]))
response["policyDocuments"].append(policy)
return response
eventには、リクエストのtoken情報が入ってきます。tokenの中身をみて判断することもできます。denyならisAuthenticatedをFalseなど。
AWS LambdaをAWS IoTのAuthorizerの呼び出し
以下のコマンドで登録します。 token_key_nameはリクエスターがどのAuthorizerを使うかの識別子として使われますので、任意の1-128文字で設定します。
token-signing-public-keysはjsonでも表現可能です。また鍵情報に改行などもあるのでコマンド実行時に注意してください。
cliマニュアルはこちら
aws iot create-authorizer --authorizer-name <authorizer_name> --authorizer-function-arn <Lambda_function_arn> --token-key-name <token_key_name> --token-signing-public-keys FIRST_KEY="<public_key_pem>" --status ACTIVE
登録の確認
aws iot describe-authorizer --authorizer-name <authorizer_name>
option設定としてdefaultのAuthorizer設定
以下で指定するとauthorizer nameを省略して呼び出した場合のdefault authorizerの設定にもできる。
aws iot set-default-authorizer --authorizer-name <authorizer_name>
AWS LambdaのPermission設定
aws lambda add-permission --function-name <lambda_function_name> --principal iot.amazonaws.com --source-arn <authorizer_arn> --statement-id Id-123 --action "lambda:InvokeFunction"
ここまでで、設定完了です。
実行
AWS IoTコマンドにtest invokeが用意されています。また、ここではcurlでの実行方法を記載しておきます。
テスト実行
呼び出しには、tokenとtokenを秘密鍵で暗号化し、Base64化した情報をpayloadとする必要があります。
ここではtest invokeコマンドを使って確認してみます。tokenは認証局がallowを返却すると仮定します。
token暗号情報とBase64の作成
echo -n allow > token.txt
openssl dgst -sha256 -sign private.pem -out token.sign token.txt
base64 token.sign > token.sign.b64
testコマンド実行
tokenのb64化したファイルに改行コードが混じっているのでtrコマンド改行を抜いてファイルを開いています。
aws iot test-invoke-authorizer --authorizer-name <authorizer_name> --token allow --token-signature `tr -d "\n" < token.sign.b64`
Tokenが返却されていれば成功です。本来はAWS IoTがLambdaから受け取るものです。
test invokeの成功例
{
"isAuthenticated": true,
"refreshAfterInSeconds": 300,
"policyDocuments": [
"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"iot:Publish\",\"iot:Connect\",\"iot:Subscribe\"],\"Resource\":[\"*\"],\"Effect\":\"Allow\"}]}"
],
"disconnectAfterInSeconds": 84000,
"principalId": "78e0d676180b11e9aef91ac3a063ec3a"
}
curlでの実行例
以下のような形でpostしてhttp 200レスポンスがあれば成功です。
curl -X POST -k -i -N -H "Host: <your_aws_iot_endpoint>" -H "X-Amz-CustomAuthorizer-Name: <authorizer_name>" -H "X-Amz-CustomAuthorizer-Signature: <token_signature>" -H "<token_key_name>: allow" -H "User-Agent: aws-cli/1.10.65 Python/2.7.11 Darwin/16.1.0 botocore/1.4.55" --data 'Hello from custom auth' https://<your_aws_iot_endpoint>/topics/customauthtesting
免責
本投稿は、個人の意見で、所属する企業や団体は関係ありません。
また掲載しているsampleプログラムの動作に関しても保障いたしませんので、参考程度にしてください。