AWS IoT Coreでのセキュリティのベストプラクティス - AWS IoT Core

AWS IoT Coreでのセキュリティのベストプラクティス

このセクションでは、AWS IoT Core のセキュリティのベストプラクティスについて説明します。詳細については、「 IoT ソリューションの 10 のセキュリティゴールデンルール」を参照してください。

AWS IoT での MQTT 接続の保護

AWS IoT Core は、インターネットに接続されたデバイスがクラウドアプリケーションや他のデバイスと簡単かつ安全にやり取りできるようにするマネージド型クラウドサービスです。AWS IoT Core は、HTTP、WebSocket、および MQTT をサポートします。これらは、断続的な接続を許容するように特別に設計された軽量の通信プロトコルです。MQTT を使用して AWS IoT に接続する場合、各接続はクライアント ID と呼ばれる識別子に関連付ける必要があります。MQTT クライアント ID は、MQTT 接続を一意に識別します。別の接続に対して既に要求されているクライアント ID を使用して新しい接続が確立された場合、AWS IoT メッセージブローカーは古い接続を中断して新しい接続を許可します。クライアント ID は、各 AWS アカウント および各 AWS リージョン 内で一意である必要があります。つまり、AWS アカウント 外または AWS アカウント 内のリージョン間では、クライアント ID のグローバルな一意性を強制する必要はありません。

デバイスフリートでの MQTT 接続の中断の影響と重大度は、多くの要因によって異なります。具体的には次のとおりです。

  • ユースケース (たとえば、デバイスが AWS IoT に送信するデータ、データの量、データの送信頻度など)。

  • MQTT クライアント設定 (たとえば、自動再接続設定、関連するバックオフタイミング、MQTT 永続セッションの使用など)。

  • デバイスリソースの制約。

  • 切断の根本原因、その積極性、永続性。

クライアント ID の競合や潜在的な悪影響を回避するには、各デバイスまたはモバイルアプリケーションに、AWS IoT メッセージブローカーへの MQTT 接続に使用できるクライアント ID を制限する AWS IoT または IAM ポリシーがあることを確認します。例えば、IAM ポリシーを使用すると、既に使用中のクライアント ID を使用することによりデバイスが意図せず別のデバイスの接続を閉じないようにすることができます。詳細については、「認証」を参照してください。

フリート内のすべてのデバイスには、意図したアクションのみを承認する権限を持つ認証情報が必要です。これには、メッセージの発行や特定のスコープとコンテキストを持つトピックへのサブスクライブなどの AWS IoT MQTT アクションが含まれますが、これらに限定されません。特定のアクセス許可ポリシーは、ユースケースによって異なる場合があります。ビジネス要件とセキュリティ要件に最も合うアクセス許可ポリシーを特定します。

アクセス許可ポリシーの作成と管理を簡素化するために、AWS IoT Core ポリシー変数 および IAM ポリシー変数を使用できます。ポリシー変数はポリシーに配置でき、ポリシーが評価されると、変数はデバイスのリクエストから取得された値に置き換えられます。ポリシー変数を使用して、複数のデバイスにアクセス許可を付与する単一のポリシーを作成できます。AWS IoT アカウント設定、認証メカニズム、 AWS IoT メッセージブローカーへの接続に使用されるネットワークプロトコルに基づいて、ユースケースに関連するポリシー変数を特定できます。ただし、最良のアクセス許可ポリシーを記述するには、使用状況と脅威モデルの詳細を考慮してください。

例えば、デバイスを AWS IoT レジストリに登録した場合、AWS IoT ポリシーでモノのポリシー変数を使用して、モノの名前、モノのタイプ、モノの属性値などのモノのプロパティに基づいてアクセス許可を付与または拒否できます。モノ名は、モノが AWS IoT に接続されるときに送信される MQTT 接続メッセージのクライアント ID から取得されます。モノのポリシー変数は、モノが TLS 相互認証を使用して MQTT を介して AWS IoT に接続するとき、または、認証された Amazon Cognito ID を使用して WebSocket プロトコルを介して MQTT に接続するときに置き換えられます。AttachThingPrincipal API を使用して、証明書と認証された Amazon Cognito ID をモノにアタッチできます。iot:Connection.Thing.ThingName は、クライアント ID の制限を適用するために便利なモノのポリシー変数です。次の AWS IoT ポリシー例では、登録されたモノの名前を、AWS IoT メッセージブローカーへの MQTT 接続のクライアント ID として使用する必要があります。

{ "Version":"2012-10-17", "Statement":[ { "Effect":"Allow", "Action":"iot:Connect", "Resource":[ "arn:aws:iot:us-east-1:123456789012:client/${iot:Connection.Thing.ThingName}" ] } ] }

進行中のクライアント ID の競合を特定する場合は、AWS IoT の CloudWatch Logs を有効にして使用できます。クライアント ID の競合のために AWS IoT メッセージブローカーが切断する MQTT 接続ごとに、次のようなログレコードが生成されます。

{ "timestamp": "2019-04-28 22:05:30.105", "logLevel": "ERROR", "traceId": "02a04a93-0b3a-b608-a27c-1ae8ebdb032a", "accountId": "123456789012", "status": "Failure", "eventType": "Disconnect", "protocol": "MQTT", "clientId": "clientId01", "principalId": "1670fcf6de55adc1930169142405c4a2493d9eb5487127cd0091ca0193a3d3f6", "sourceIp": "203.0.113.1", "sourcePort": 21335, "reason": "DUPLICATE_CLIENT_ID", "details": "A new connection was established with the same client ID" }

{$.reason= "DUPLICATE_CLIENT_ID" } などの CloudWatch Logs フィルターを使用して、クライアント ID が競合するインスタンスを検索したり、CloudWatch メトリクスフィルターおよび対応する CloudWatch アラームを設定して、継続的なモニタリングとレポートを作成したりできます。

AWS IoTDevice Defender を使用して、過度に許可されている AWS IoT および AWS IoT IAM ポリシーを識別できます。Device Defender では、フリートの複数のデバイスが同じクライアント ID を使用して AWS IoT メッセージブローカーに接続している場合に通知する監査チェックも用意されています。

AWS IoT Device Advisor を使用して、デバイスが AWS IoT Core に確実に接続でき、セキュリティのベストプラクティスに従うことができることを検証できます。

以下の資料も参照してください。

デバイスのクロックを同期化させる

デバイスの時刻を正確に保つことが重要です。X.509 証明書には有効期限の日時があります。デバイスのクロックは、サーバー証明書が現在も有効であることを確認するために使用されます。商用 IoT デバイスを構築する場合は、製品が販売される前に長期間保管される可能性があることに注意してください。この間、リアルタイムクロックがドリフトし、電池が放電する可能性があるため、工場での設定時間では不十分です。

ほとんどのシステムでは、デバイスのソフトウェアに Network Time Protocol (NTP) クライアントを含める必要があります。デバイスは、AWS IoT Core への接続を試行する前に、NTP サーバーと同期するまで待機する必要があります。これが不可能な場合は、後続の接続が成功するように、ユーザーがデバイスの時刻を設定する方法を提供する必要があります。

デバイスが NTP サーバーと同期されると、AWS IoT Core との接続を開くことができます。許容されるクロックスキューの量は、接続で何をしようとしているかによって異なります。

サーバー証明書の検証

デバイスが最初に AWS IoT を操作するために行うことは、安全な接続を開くことです。デバイスを AWS IoT に接続するときは、別のサーバーが AWS IoT を偽装しておらず、実際に AWS IoT と通信していることを確認してください。各 AWS IoT サーバーには、iot.amazonaws.com ドメインに対して発行された証明書がプロビジョニングされます。この証明書は、ドメインの ID と所有権を確認した、信頼された認証局から AWS IoT に発行されました。

AWS IoT Core がデバイスを接続するときに最初に行うことの 1 つは、デバイスにサーバー証明書を送信することです。デバイスは、iot.amazonaws.com に接続する予定だったことと、その接続の最後のサーバーが、そのドメインの信頼された機関からの証明書を持っていることを確認できます。

TLS 証明書は X.509 形式で、組織の名前、場所、ドメイン名、有効期間などのさまざまな情報が含まれています。有効期間は、notBeforenotAfter と呼ばれる時間値のペアとして指定されます。AWS IoT Core のようなサービスは、サーバー証明書に限られた有効期間 (たとえば 1 年間) を使用し、古い証明書の有効期限が切れる前に新しい証明書を提供し始めます。

デバイスごとの単一の ID を使用する

クライアントごとに 1 つの ID を使用します。通常、デバイスでは X.509 クライアント証明書が使用されます。ウェブおよびモバイルアプリケーションは Amazon Cognito ID を使用します。これにより、デバイスにきめ細かなアクセス許可を適用できます。

例えば、電球とサーモスタットの 2 つの異なるスマートホームオブジェクトからステータス更新を受け取る携帯電話デバイスで構成されるアプリケーションがあるとします。電球は、バッテリーレベルのステータスを送信し、サーモスタットは温度を報告するメッセージを送信します。

AWS IoT はデバイスを個別に認証し、各接続を個別に処理します。承認ポリシーを使用してきめ細かなアクセス制御を適用できます。サーモスタットのポリシーを定義して、トピックスペースに公開することができます。電球に別のポリシーを定義して、別のトピックスペースに公開することができます。最後に、これらのデバイスからのメッセージを受信するために、サーモスタットと電球のトピックへの接続とサブスクライブのみを許可するモバイルアプリのポリシーを定義できます。

最小権限の原則を適用し、デバイスごとのアクセス許可を可能な限り絞り込みます。すべてのデバイスまたはユーザーは、既知のクライアント ID との接続、特定され、固定された一連のトピックの公開とサブスクライブのみを許可する AWS IoT ポリシーを AWS IoT に持つ必要があります。

バックアップとして 2 番目の AWS リージョン を使用する

バックアップとしてデータのコピーを 2 番目のAWS リージョン に格納することを検討してください。詳細については、「AWS IoT の災害対策」を参照してください。

ジャストインタイムプロビジョニングの使用

各デバイスの手動作成とプロビジョニングには、時間がかかる場合があります。AWS IoT は、デバイスが最初に AWS IoT に接続するときにプロビジョニングするテンプレートを定義する方法を提供します。詳細については、「ジャストインタイムプロビジョニング」を参照してください。

AWS IoT Device Advisor のテストを実行するためのアクセス許可

次のポリシーテンプレートは、AWS IoT Device Advisor テストケースを実行するために必要な最小限のアクセス許可と IAM エンティティを示しています。your-device-role-arn を、前提条件の下で作成したデバイスロール Amazon Resource Name (ARN) に置き換える必要があります。

{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "iam:PassRole", "Resource": "your-device-role-arn", "Condition": { "StringEquals": { "iam:PassedToService": "iotdeviceadvisor.amazonaws.com" } } }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": [ "execute-api:Invoke*", "iam:ListRoles", // Required to list device roles in the Device Advisor console "iot:Connect", "iot:CreateJob", "iot:DeleteJob", "iot:DescribeCertificate", "iot:DescribeEndpoint", "iot:DescribeJobExecution", "iot:DescribeJob", "iot:DescribeThing", "iot:GetPendingJobExecutions", "iot:GetPolicy", "iot:ListAttachedPolicies", "iot:ListCertificates", "iot:ListPrincipalPolicies", "iot:ListThingPrincipals", "iot:ListThings", "iot:Publish", "iot:StartNextPendingJobExecution", "iot:UpdateJobExecution", "iot:UpdateThingShadow", "logs:CreateLogGroup", "logs:CreateLogStream", "logs:DescribeLogGroups", "logs:DescribeLogStreams", "logs:PutLogEvents", "logs:PutRetentionPolicy" ], "Resource": "*" }, { "Sid": "VisualEditor2", "Effect": "Allow", "Action": "iotdeviceadvisor:*", "Resource": "*" } ] }

デバイスアドバイザーのクロスサービスでの混乱した代理の防止

混乱した副問題は、アクションを実行する許可を持たないエンティティが、より特権のあるエンティティにアクションを実行するように強制できるセキュリティの問題です。AWS では、サービス間でのなりすましが、混乱した代理問題を生じさせることがあります。サービス間でのなりすましは、1 つのサービス (呼び出し元サービス) が、別のサービス (呼び出し対象サービス) を呼び出すときに発生する可能性があります。呼び出し元サービスは、本来ならアクセスすることが許可されるべきではない方法でその許可を使用して、別の顧客のリソースに対する処理を実行するように操作される場合があります。これを防ぐため、AWS では、アカウント内のリソースへのアクセス権が付与されたサービスプリンシパルですべてのサービスのデータを保護するために役立つツールを提供しています。

リソースポリシー内のグローバル条件コンテキストキー aws:SourceArnaws:SourceAccount を使用して、リソースについてデバイスアドバイザーが別のサービスに付与する許可を制限することをお勧めします。両方のグローバル条件コンテキストキーを使用しており、それらが同じポリシーステートメントで使用されるときは、aws:SourceAccount 値と、aws:SourceArn 値のアカウントが同じアカウント ID を使用する必要があります。

aws:SourceArn の値は、スイート定義リソースの ARN である必要があります。スイート定義リソースは、デバイスアドバイザーで作成したテストスイートを指します。

混乱した代理問題から保護するための最も効果的な方法は、リソースの完全な ARN を指定しながら、aws:SourceArn グローバル条件コンテキストキーを使用することです。リソースの完全な ARN が不明な場合や、複数のリソースを指定する場合には、グローバルコンテキスト条件キー aws:SourceArn で、ARN の未知部分を示すためにワイルドカード (*) を使用します。例: arn:aws:iotdeviceadvisor:*:account-id:suitedefinition/*

次の例では、デバイスアドバイザーで aws:SourceArn および aws:SourceAccount グローバル条件コンテキストキーを使用して、混乱した代理問題を回避する方法を示します。

{ "Version": "2012-10-17", "Statement": { "Sid": "ConfusedDeputyPreventionExamplePolicy", "Effect": "Allow", "Principal": { "Service": "iotdeviceadvisor.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": { "ArnLike": { "aws:SourceArn": "arn:aws:iotdeviceadvisor:us-east-1:123456789012:suitedefinition/ygp6rxa3tzvn" }, "StringEquals": { "aws:SourceAccount": "123456789012" } } } }