

AWS IoTポリシーの`+`と`#`はワイルドカードとして機能しない
この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。
AWS IoTのポリシーで、MQTTのトピック名によく使う+とか#をそのままResourceに書いてたんだけど、これ実はワイルドカードとして機能してなかった。
何が起きたか
こういうポリシーを書いてた。
{ "Version": "2012-10-17", "Statement": [ { "Action": ["iot:Publish"], "Resource": [ "arn:aws:iot:ap-northeast-1:123456789012:topic/v1/thing/${iot:ClientId}/sensor/+" ], "Effect": "Allow" } ]}+を1階層のワイルドカードとして使うつもりだったけど、これは意図通りに動かない。
+と#はリテラル文字として扱われる
MQTTのトピックフィルタでは+が1階層、#が複数階層にマッチするワイルドカードだけど、AWS IoTポリシーのResourceの中では別扱いになる。ポリシー文書内では、MQTTのワイルドカードである+と#は特殊な意味を持たない、ただの文字として評価される。つまり上のポリシーは「sensor/+という名前の固定トピック」を意味してしまっていて、sensor/xxxのような可変なトピックにはマッチしない。
代わりに*と?を使う
AWS IoTポリシーはIAMポリシーと同じ規則でワイルドカードを解釈する。
*:任意の文字列(複数文字、かつ/をまたいでマッチする)?:任意の1文字
なので、さっきのポリシーは*に置き換える。
arn:aws:iot:ap-northeast-1:123456789012:topic/v1/thing/${iot:ClientId}/sensor/*これでsensor/以降が何であってもマッチする。ただし*は/をまたぐので、想定より広い範囲にマッチしてしまう可能性がある点は注意しておいたほうがいい。
固定長の文字列(UUIDとか)には?が向いてる
トピックの末尾がUUID形式で、桁数とハイフンの位置だけ固定したい、みたいなケースだと?が使える。
UUIDは8-4-4-4-12の32文字+ハイフン4個で、合計36文字。これに合わせて?を並べる。
arn:aws:iot:ap-northeast-1:123456789012:topic/v1/thing/${iot:ClientId}/sensor/????????-????-????-????-????????????こういう文字列(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx形式)にマッチする。
?はあくまで「任意の1文字」なので、以下は制御できない。
0-9a-fのような16進数限定- UUID v4かどうかのバージョンビット
長さとハイフン位置だけを縛りたい、くらいの用途に向いてる。
ポリシー変数も一緒に使える
${iot:ClientId}以外にも、こういう変数が使える。
${iot:ClientId}:接続中のMQTTクライアントID${iot:Connection.Thing.ThingName}:接続元のThing名${iot:Connection.Thing.Attributes[任意のキー]}:Thingに設定したAttribute値iot:Connection.Thing.IsAttached:ThingがX.509証明書に紐付いているかどうかのConditionキー${iot:Certificate.Subject.CommonName}:接続に使った証明書のSubjectの値
${iot:ClientId}だけでResourceを絞る運用は、クライアントが任意の文字列をClientIdとして名乗れてしまう前提だと想定より広い範囲を許可することがあるらしい。Thing名との紐付けをiot:Connection.Thing.IsAttachedのConditionで縛るのも合わせてやっておいたほうがよさそう。
表にまとめるとこう
| 文字 | MQTTのワイルドカード | AWS IoTポリシーのワイルドカード |
|---|---|---|
+ |
○(1階層) | ×(リテラル文字) |
# |
○(複数階層) | ×(リテラル文字) |
* |
× | ○(複数文字、/またぐ) |
? |
× | ○(任意の1文字) |
MQTTのトピック設計をそのままIoTポリシーのResourceに持ってくると、ワイルドカードの意味が変わるところで詰まりがちなので、この対応表だけ覚えておけば十分そう。