はじめに
Webブラウザからエッジカメラの映像・音声をリアルタイムで確認できる仕組みのPoCで設計・実装を担当したので
その時に学んだ事や設計判断について記載しようと思います。
使用した技術
エッジカメラはPoCのためRaspberry Piを採用し、クラウド側はAWSで構成しています。
具体的には下記のようなサービスを使用しました。
- ECS
- APIサーバー
- Lambda
- クラウド側MQTT通信
- IoT Core
- MQTTブローカー, 証明書管理、デバイス管理
- Kinesis Video Streams
- WebRTC通信
この記事では、このPoCにおけるネットワーク設計、特にエッジデバイスの設置先ネットワーク制約をどう解決したかに焦点を当てて解説します。
具体的には、MQTT接続におけるALPNでの443ポート集約と、WebRTC接続におけるTURN強制の設計判断について記述します。
全体構成
本PoCの映像通話開始までのフローは以下の通りです。
[Webブラウザ]
│ HTTP Request
▼
[ECS(APIサーバー)]
│ Lambda Invoke(同期)
▼
[Lambda]
│ ① AssumeRoleで一時クレデンシャル生成
│ ② MQTT over WebSocket で IoT Core に Publish
▼
[IoT Core (MQTTブローカー)]
│ MQTT メッセージ配信
▼
[Raspberry Pi(エッジカメラ)] ← 事前にトピックをSubscribe済み
│ ③ 一時クレデンシャルを受け取り
│ ④ KVS C WebRTC SDKのマスタープロセスを起動
▼
[Kinesis Video Streams シグナリングチャネル]
│ SDP・ICE candidateの交換
▼
[Webブラウザ(ビューワー)] ←→ [Raspberry Pi(マスター)]
WebRTC映像通話確立
Webブラウザから通話開始のHTTPリクエストを送信すると、ECS上のAPIサーバーがLambdaを同期実行(Invoke)します。LambdaはIoT CoreのMQTTブローカーに対してメッセージをPublishし、事前にトピックをSubscribeしているRaspberry Pi(エッジカメラ)がそのメッセージを受信します。
メッセージにはKVSシグナリングチャネルへの接続に必要な一時クレデンシャルが含まれており、Raspberry Pi側はこれを用いてKinesis Video Streams C WebRTC SDKのマスタープロセスを起動します。マスター起動後、ブラウザ側がビューワーとしてシグナリングチャネルに接続し、SDP・ICE candidateの交換を経てWebRTC通話が確立します。
MQTT接続設計:ALPNによる443ポート集約
課題:設置先ネットワークのポート制約
エッジカメラの設置先ネットワークについてヒアリングしたところ、ファイアウォールによってアウトバウンド通信が制限されており、HTTPS(443)以外のポートはブロックされる可能性があるとの事でした。
IoT CoreのMQTT接続は標準では8883番ポートを使用するため、そのままではエッジカメラからIoT Coreへの接続ができない可能性があります。
設計判断:ALPNで443に集約
この問題に対して、IoT CoreがサポートするALPNを利用し、MQTT接続を443番ポートに集約しました。
ALPNはTLSハンドシェイクの拡張で、クライアントがTLS接続時に使用したいアプリケーションプロトコルをサーバーに通知する仕組みです。IoT Coreの場合、TLSハンドシェイク時にALPN Protocol Nameとしてx-amzn-mqtt-caを指定することで、443番ポート上でMQTT通信を行うことができます。
これにより、エッジカメラからの通信はHTTPSと同じ443番ポートのみで完結し、8883番ポートが制限されている環境でもMQTT接続が可能になります。
参照元: AWS公式ドキュメント
なぜVPNを採用しなかったか
エッジデバイスのクラウド接続にはVPN(Tailscaleなど)を用いる方法もありますが、本PoCでは以下の理由からVPNを採用しませんでした。
- 設置先ネットワークのポート制約により、VPNプロトコルで使用するポート(WireGuardの51820/UDPなど)がブロックされる可能性がある
- マルチテナント環境においてVPN経由でのクロスアクセスリスクが生じる
- デバイス台数が増えた場合のVPN管理の運用負荷
IoT CoreのMQTT接続であれば、デバイス証明書によるデバイス単位の認証、IoTポリシーによる認可が可能ですし、ALPNで443に集約することでファイアウォール制約もクリアできます。
WebRTC接続設計:TURN強制による接続安定化
WebRTCの接続確立とICEの仕組み
WebRTCで通信を確立する際、ICE(Interactive Connectivity Establishment)というフレームワークが使われます。ICEは接続候補を収集し、最適な通信経路を決定します。
通信経路の候補は大きく3種類あります。
- host candidate:デバイスのローカルIPアドレスを使った直接通信
- srflx candidate(STUN):STUNサーバーを使ってNATの外側のIPアドレスを取得し、P2P通信を試みる
- relay candidate(TURN):TURNサーバーを中継して通信する
通常のICEフローでは、まずhost candidateやsrflx candidateでのP2P接続を試み、失敗した場合にTURNへフォールバックします。P2Pが成功すれば中継サーバーを経由しないため低レイテンシで通信できますが、ネットワーク環境によってはP2Pが確立できないケースがあります。
課題:エッジカメラの設置先でP2Pが確立できない
本PoCの運用中、エッジカメラの設置先ネットワーク環境によってはSTUNによるP2P接続が確立できないケースが発生しました。
原因として考えられるのは以下の点です。
- 対称NAT(Symmetric NAT):外部の宛先ごとに異なるマッピングが作られるNAT方式で、STUNで取得した外部アドレスが実際の通信相手とのやり取りでは使えない
- ファイアウォールによるUDPブロック:企業ネットワークでUDPの外向き通信が制限されている場合、STUNのバインディングリクエスト自体が到達しない
エッジカメラの設置先は顧客環境であり、ネットワーク構成を事前にコントロールすることはできません。(できたとしても調整にかなりの時間がかかります)
そのため設置先によって異なるNAT種別やファイアウォール設定に依存する形では、安定したサービス提供は難しいです。
設計判断:マスター・ビューワー双方でTURN強制
この問題に対して、通信の安定性を最優先とし、エッジカメラ(マスター)・ブラウザ(ビューワー)の双方でICE設定をTURN強制(relay only)にする設計判断を行いました。
KVS C WebRTC SDKおよびブラウザ側のWebRTC APIでは、ICEの接続ポリシーとしてTURNのみを使用するよう設定することが可能です。これにより、ICEの候補収集時にhost candidateやsrflx candidateを収集せず、relay candidate(TURN経由)のみで接続を確立します。TURNサーバーにはKVSのマネージドICEサーバーを使用しています。
双方でTURN強制とした理由は、エッジカメラの設置先ネットワークは顧客環境であり、NAT種別やファイアウォール設定を事前にコントロールできないためです。P2P接続の成否が設置先の環境に依存する状態では、安定したサービス提供は困難です。TURN強制にすることで、双方ともTURNサーバーへのアウトバウンド接続のみで通信が成立するため、設置先のネットワーク構成に関わらず確実に映像通話を確立できます。
TURN強制のトレードオフ
ただし、TURN強制にはトレードオフが存在します。
- レイテンシの増加:P2P通信と比較して、TURNサーバーを中継する分だけレイテンシが増加する
- コスト:TURN中継トラフィックに対してKVSの課金が発生する
本PoCの用途はエッジカメラの映像確認であり、接続の安定性を最優先としたため、これらのトレードオフは許容範囲と判断しました。
認証設計:最小権限の一時クレデンシャル配信
シグナリングチャネルIDに基づくAssumeRole
エッジカメラがKVSのシグナリングチャネルに接続するには、AWSの認証情報が必要です。本PoCでは、Lambda側でAssumeRoleを実行し、一時的なクレデンシャルをMQTT経由でエッジカメラに配信する設計としました。
ここでのポイントは、AssumeRoleで生成するクレデンシャルの権限をシグナリングチャネル単位で絞っている点です。シグナリングチャネルのIDはDBで管理しており、AssumeRole時のポリシーで該当チャネルのARNのみにアクセスを限定しています。
これにより、仮にクレデンシャルが漏洩したとしても、影響範囲は特定のシグナリングチャネルに限定され、他のチャネルやAWSリソースへのアクセスはできません。
なぜMQTT経由でクレデンシャルを配信したか
エッジカメラにクレデンシャルを渡す方法としては、エッジ側でIoT Core証明書とRole Aliasを用いてCredentials Provider経由で一時クレデンシャルを取得する方式が本来は望ましいです。しかし本PoCでは、エッジ側の実装をシンプルに保つことを優先し、クラウド側(Lambda)でAssumeRoleした一時クレデンシャルをMQTT経由で配信する方式を採用しました。
この方式のメリットは、エッジ側がMQTTメッセージを受信してKVSプロセスを起動するだけで済み、STS連携やRole Aliasの設定といったエッジ側の実装コストを削減できる点です。一方で、本番環境への移行時にはエッジ側でCredentials Providerを用いたクレデンシャル取得方式への切り替えも検討予定です。
まとめ
本PoCでは、エッジカメラの設置先ネットワーク制約を乗り越えるために、以下のネットワーク設計を行いました。
| 課題 | 設計判断 | 効果 |
|---|---|---|
| 8883ポートがブロックされる | ALPNで443に集約 | ファイアウォール制約下でもMQTT接続を確保 |
| 対称NATやUDPブロックでP2P不可 | マスター・ビューワー双方でTURN強制 | 設置先NWに依存しない安定した映像通話 |
| クレデンシャルの安全な配信 | AssumeRole+チャネルID単位の最小権限 | 漏洩時の影響範囲を最小化 |
いずれの設計判断も、「エッジデバイスの設置先ネットワークは制御できない」という前提に立ち、クラウド側の設計でその不確実性を吸収するというアプローチを取っています。
同様のIoT×映像通話の案件で、ネットワーク設計に悩まれている方の参考になれば幸いです。
