[AWS IoT] ポリシー変数で複数のモノをセキュアに管理してみた

2020.04.09

AWS IoT Coreのポリシー変数は、単一のポリシーで複数のモノを管理する場合に有用です。ポリシー変数はポリシーが評価される際、実際の値に置き換わります。例えば、ポリシー変数iot:ClientIdは、IoTデバイスがAWS IoT Coreに接続するために指定したクライアントIDに置き換わります。

AWS IoT Core ポリシーについて

AWS IoT Core ポリシーは、IAMポリシーと同じルールで定義するJSONドキュメントです。AWS IoT Coreへの接続やデバイスのシャドウへのアクセスを制限することができます。

例えば、次のようなポリシーを定義します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["iot:Connect"],
      "Resource": ["arn:aws:iot:ap-northeast-1:<AWSアカウントID>:client/*"]
    },
    {
      "Effect": "Allow",
      "Action": ["iot:Publish", "iot:Receive"],
      "Resource": [
        "arn:aws:iot:ap-northeast-1:<AWSアカウントID>:topic/$aws/things/*/shadow/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": ["iot:Subscribe"],
      "Resource": [
        "arn:aws:iot:ap-northeast-1:<AWSアカウントID>:topicfilter/$aws/things/*/shadow/update"
      ]
    }
  ]
}

このポリシーではモノの名前(ThingName)にワイルドカードを使用しています。そのため、このポリシーがアタッチされたクライアント証明書でAWS IoT Coreに接続すると、どのデバイスのシャドウへもアクセスが可能となってしまいます。

AWS IoT Core 攻撃

デバイスとIoTのモノを1対1にして、シャドウへのアクセスを制限する場合には、デバイスごとに1つのポリシーを作成する方法があります。しかし、デバイスの数に比例してポリシーも増えるので、ポリシーの管理が煩雑になります。

そこで、ポリシー変数の利用を検討することになります。

ポリシー変数を使う

ポリシー変数を使用してポリシードキュメントを定義してみます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["iot:Connect"],
      "Resource": ["*"],
      "Condition": {
        "Bool": {
          "iot:Connection.Thing.IsAttached": ["true"]
        }
      }
    },
    {
      "Effect": "Allow",
      "Action": ["iot:Publish", "iot:Receive"],
      "Resource": [
        "arn:aws:iot:ap-northeast-1:<AWSアカウントID>:topic/$aws/things/${iot:Connection.Thing.ThingName}/shadow/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": ["iot:Subscribe"],
      "Resource": [
        "arn:aws:iot:ap-northeast-1:<AWSアカウントID>:topicfilter/$aws/things/${iot:Connection.Thing.ThingName}/shadow/update"
      ]
    }
  ]
}

iot:Connection.Thing.IsAttachedは証明書やAmazon Cognito IDがIoTのモノにアタッチされている場合にtrueを返します。この変数を使用して、IoTのモノにアタッチされていない証明書が提示された際に、AWS IoT Coreへの接続を拒否することができます。

iot:Connection.Thing.ThingNameはIoTのモノの名前を返します。モノの名前はAWS IoT Coreへ接続する際のクライアントIDから取得されます。AWS IoTではモノの名前=クライアントIDが推奨されています。

このようにポリシー変数を使用することで、単一のポリシーで複数のモノをセキュアに管理することができます。

AWS IoT Core ブロック

自前のデバイス証明書を使用する場合には、X.509証明書のポリシー変数でアクセスを制限することもできます。

動作確認

AWS IoT Coreでポリシーとモノと証明書を作成して、MQTT接続した際の動作を確認します。

ポリシーを作成

AWS IoT Coreのマネジメントコーンソールからポリシーを作成します。

AWS IoT Core ポリシー

先ほどのポリシー変数を利用したJSONドキュメントを貼り付けます。AWSアカウントIDは差し替えてください。

AWS IoT Core ポリシー作成

モノを作成

AWS IoT Coreのマネジメントコーンソールから単一のモノを作成します。

AWS IoT Core モノ

モノの名前を入力して次に進みます。

AWS IoT Core モノ作成

証明書を作成

モノに証明書を追加します。次の画面が表示されるので「1-Click 証明書作成 (推奨)」で証明書を作成します。

AWS IoT Core 証明書作成

証明書の作成が完了したら、次の画面で証明書や秘密鍵などをダウンロードします。また、証明書を有効化して最初に作成したポリシーをアタッチしておきます。

AWS IoT Core 証明書ダウンロード

MQTTで接続

MosquittoというMQTT Brokerを使用して、実際にAWS IoT Coreへ接続をしてみます。

brew install mosquitto

AWS IoT CoreのマネジメントコンソールからAWS IoT Coreへ接続するためのエンドポイントを取得します。

AWS IoT Core エンドポイント

ダウンロードしておいた証明書や秘密鍵の保存先パスとメッセージを入力、AWS IoTに接続してメッセージを送信します。thing-sampleはモノを作成した際の名前に変更してください。

mosquitto_pub \
  --cafile amazon-root-ca1.pem \
  --cert xxxxxxxxxx-certificate.pem.crt \
  --key xxxxxxxxxx-private.pem.key \
  -h zzzzzzzzzzzzzz-ats.iot.ap-northeast-1.amazonaws.com \
  -p 8883 \
  -q 1 \
  -t '$aws/things/thing-sample/shadow/update' \
  -i thing-sample \
  -m '{ "state": { "reported": { "color": "red", "power": "on" } } }' \
  -d

メッセージの送信に成功すると次のようなログが出力されます。

Client thing-sample sending CONNECT
Client thing-sample received CONNACK (0)
Client thing-sample sending PUBLISH (d0, q1, r0, m1, '$aws/things/thing-sample/shadow/update', ... (62 bytes))
Client thing-sample received PUBACK (Mid: 1, RC:0)
Client thing-sample sending DISCONNECT

マネジメントコンソールでモノのシャドウを表示すると、送信したメッセージを確認できます。

AWS IoT Core シャドウ

まとめ

AWS IoTのポリシーでポリシー変数を活用して、アクセス権限の管理を効率化することができました。AWS IoTのドキュメントには他にもポリシー変数を使用したポリシーの例が紹介されているので参考にしてみてください。

参考資料