こんにちは! サーバーワークスの松井です。
今回は、AWS IoT 証明書経由で安全にデバイス内にある画像をS3にアップロードする方法をご紹介します。
今回紹介する方法では、AWS Credentialをデバイスに配置しないでAWS環境に画像を送信できるので安全です。
デバイス内にある画像をS3にアップロードする方法としては、AWS IoT のロールエイリアスを使って、一時的にデバイスに権限を与え、AWS CLI経由でアップロードする方法もあります。
ロールエイリアスの使い方は、以下のブログをご参考ください。
事前準備
・IoT Coreでのモノの作成
・デバイスへの証明書の配置
・デバイスに画像を配置
・python3.9が実行できる環境
・画像のアップロード先のS3バケットの作成
・S3へのPUT権限がついているpython環境のLambdaの作成
・Cloud9を作成
1. 画像送信プログラムを作成
Cloud9に画像送信プログラムを配置します。
以下のディレクトリ階層にてプログラムを作成していきます。
・ ├── conf │ └── setting.conf ├── main.py ├── settings.py ├── test.jpg
main.py
import requests import json import boto3 import settings from boto3.session import Session cert_filepath = settings.CERT_PATH pri_key_filepath = settings.PRIVATE_KEY_PATH ca_filepath = settings.CA_FILE_PATH endpoint = settings.IOT_CREDENTIAL_ENDPOINT device_id = settings.DEVICE_ID def main(): # mqtt クライアント初期化 mqtt_connection = init_mqtt() img_file = open("./test.jpg", 'rb').read() bin = base64.b64encode(img_file).decode("utf-8") data = { "img": bin, } send_to_iot_core(mqtt_connection, data) def init_mqtt() -> mqtt.Connection: # mqtt クライアントを初期化する try: event_loop_group = io.EventLoopGroup(1) host_resolver = io.DefaultHostResolver(event_loop_group) client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver) mqtt_connection = mqtt_connection_builder.mtls_from_path( endpoint=settings.IOT_CREDENTIAL_ENDPOINT, cert_filepath=settings.CERT_PATH, pri_key_filepath=settings.PRIVATE_KEY_PATH, client_bootstrap=client_bootstrap, ca_filepath=settings.ROOT_CA_PATH, client_id=settings.DEVICE_ID, clean_session=False, keep_alive_secs=settings.KEEP_ALIVE, ) # 接続開始 connected_future = mqtt_connection.connect() # 利用可能になるまで待機 connected_future.result() logger.info("mqtt connenction Successed") return mqtt_connection except Exception: logger.exception("Error") raise if __name__ == "__main__": main()
settings.py
import os import configparser from logging import config # 環境変数設定 conf = configparser.ConfigParser() conf.read(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf/setting.conf'), encoding='UTF-8') # DEVICE DEVICE_ID = conf['DEVICE']['DEVICE_ID'] CERT_PATH = conf['DEVICE']['CERT_PATH'] PRIVATE_KEY_PATH = conf['DEVICE']['PRIVATE_KEY_PATH'] ROOT_CA_PATH = conf['DEVICE']['ROOT_CA_PATH'] # AWS IOT_CREDENTIAL_ENDPOINT = conf['AWS']['IOT_CREDENTIAL_ENDPOINT']
setting.conf
[DEVICE] DEVICE_ID = xxx # デバイス名 CERT_PATH = xxx # 証明書配置パス PRIVATE_KEY_PATH = xxx # 秘密鍵配置パス ROOT_CA_PATH = xxx # amazon CA1パス [AWS] IOT_CREDENTIAL_ENDPOINT = https://xxx.credentials.iot.ap-northeast-1.amazonaws.com
2 画像アップロード用Lambdaプログラムを作成
作成済みのLambdaを以下のコードに書き換えてデプロイし直します。
import json import boto3 import base64 from base64 import b64decode from decimal import Decimal from io import BytesIO bucket = "test-image-upload-bucket-1111" key = "test.jpg" def lambda_handler(event, context): for data in event["Records"]: # eventデータをデコード decoded_data = base64.b64decode(data["kinesis"]["data"]).decode() if decoded_data: json_payload = json.loads(decoded_data, parse_float=Decimal) # eventデータをデコード photo = json_payload["bin"] decode_photo = b64decode(photo) s3 = boto3.resource('s3') obj = s3.Object(bucket, key) obj.put(Body=BytesIO(decode_picture),ContentType="image/jpg")
3. プログラム実行
Cloud9でプログラムを実行します。
$ python main.py
メッセージのペイロードが128KBを超える画像は送信できないのでご注意ください。
IoT Core ログ
{ "timestamp": "2022-xxxxxxxx", "logLevel": "ERROR", "traceId": "xxxxxxxx", "accountId": "xxxxxxxx", "status": "Failure", "eventType": "Publish-In", "protocol": "MQTT", "topicName": "xxxxxxxx", "clientId": "xxxxxxxx", "principalId": "xxxxxxxx", "sourceIp": "xxxxxxxx", "sourcePort": xxxxxxxx, "reason": "PAYLOAD_LIMIT_EXCEEDED", "details": "Message payload exceeds size limit for message type" }
4. 画像を確認
S3に画像がアップロードされているかを確認してください。
S3からダウンロードした画像が、cloud9に配置していた画像と同じ用に表示されていたら成功です。
5. まとめ
すでにAWS IoT CoreにてAWS環境にデータを送信している方は、ほとんど同じ方法で画像もアップロードが可能なので画像も送信したいという方は是非試してください。
ただし、データ送信の制限は、AWS IoT Coreの送信制限に依存するの小規模容量画像を送信したいシーンでご利用してください。
ありがとうございました。