AWS IoT 証明書で安全にデバイス内の画像をS3にアップロード

記事タイトルとURLをコピーする

この記事は約2分で読めます。

この記事は1年以上前に書かれたものです。
内容が古い可能性がありますのでご注意ください。

こんにちは! サーバーワークスの松井です。

今回は、AWS IoT 証明書経由で安全にデバイス内にある画像をS3にアップロードする方法をご紹介します。

今回紹介する方法では、AWS Credentialをデバイスに配置しないでAWS環境に画像を送信できるので安全です。

デバイス内にある画像をS3にアップロードする方法としては、AWS IoT のロールエイリアスを使って、一時的にデバイスに権限を与え、AWS CLI経由でアップロードする方法もあります。

ロールエイリアスの使い方は、以下のブログをご参考ください。

blog.serverworks.co.jp

事前準備

・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の送信制限に依存するの小規模容量画像を送信したいシーンでご利用してください。

ありがとうございました。