AWS IoT Topic订阅失败:特定IAM策略不生效问题咨询
问题:AWS IoT订阅失败的IAM策略排查
我使用Python的Paho MQTT客户端订阅AWS IoT Topic,所用脚本如下:
import paho.mqtt.client as mqtt import ssl MQTT_BROKER = '<endpoint>' # Public broker for testing MQTT_TOPIC = 'dcw813/livetracking' # Topic to subscribe to MQTT_PORT = 8883 # Secure port for MQTT CLIENT_ID = "webapp" # Unique client ID # MQTT settings mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, CLIENT_ID) mqttc.tls_set(ca_certs="AmazonRootCA1.pem", certfile="certificates/webapp/device-cert.pem.crt", keyfile="certificates/webapp/private.pem.key", tls_version=ssl.PROTOCOL_TLSv1_2) # Callback when a message is received def on_message(client, userdata, message): print(f"Received message: {message.payload.decode()} on topic: {message.topic}") mqttc.on_message = on_message mqttc.connect(MQTT_BROKER, MQTT_PORT) # Subscribe to the topic with QoS level 1 mqttc.subscribe(MQTT_TOPIC, qos=1) print(f"Subscribed to {MQTT_TOPIC}. Waiting for messages...") # Loop forever to process incoming messages mqttc.loop_forever()
当我使用以下IAM策略时,无法成功订阅Topic:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "iot:Subscribe", "Resource": [ "arn:aws:iot:<REGION>:<ACCOUNT>:topic/+/livetracking", "arn:aws:iot:<REGION>:<ACCOUNT>:topic/+/attendance" ] }, { "Effect": "Allow", "Action": "iot:Receive", "Resource": [ "arn:aws:iot:<REGION>:<ACCOUNT>:topic/+/livetracking", "arn:aws:iot:<REGION>:<ACCOUNT>:topic/+/attendance" ] }, { "Effect": "Allow", "Action": "iot:Connect", "Resource": "arn:aws:iot:<REGION>:<ACCOUNT>:client/${iot:ClientId}" } ] }
但将策略修改为以下内容后,订阅即可正常工作,我无法理解问题所在:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "iot:Subscribe", "Resource": "arn:aws:iot:<REGION>:<ACCOUNT>:*" }, { "Effect": "Allow", "Action": "iot:Receive", "Resource": "arn:aws:iot:<REGION>:<ACCOUNT>:*" }, { "Effect": "Allow", "Action": "iot:Connect", "Resource": "arn:aws:iot:<REGION>:<ACCOUNT>:client/${iot:ClientId}" } ] }
我还尝试了以下调试策略,但仍然无法成功订阅:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Connect", "iot:Publish", "iot:Subscribe", "iot:Receive", "iot:GetShadow", "iot:UpdateShadow", "iot:DeleteShadow", "iot:CreateKeysAndCertificate", "iot:CreateKeysAndCertificate", "iot:DescribeEndpoint", "iot:ListThings" ], "Resource": [ "arn:aws:iot:<REGION>:<ACCOUNT>:client/*", "arn:aws:iot:<REGION>:<ACCOUNT>:thing/*", "arn:aws:iot:<REGION>:<ACCOUNT>:policy/*", "arn:aws:iot:<REGION>:<ACCOUNT>:cert/*", "arn:aws:iot:<REGION>:<ACCOUNT>:rule/*", "arn:aws:iot:<REGION>:<ACCOUNT>:topic/*", "arn:aws:iot:<REGION>:<ACCOUNT>:thing/*/shadow", "arn:aws:iot:<REGION>:<ACCOUNT>:job/*" ] } ] }
问题原因与解决方案
核心问题在于AWS IoT的iot:Subscribe动作对应的资源是topicfilter类型的ARN,而非topic类型:
- 当客户端发起订阅请求时,AWS会验证订阅过滤器对应的ARN,格式为
arn:aws:iot:<REGION>:<ACCOUNT>:topicfilter/[你的订阅路径]。比如你订阅的dcw813/livetracking,对应的权限校验资源是arn:aws:iot:<REGION>:<ACCOUNT>:topicfilter/dcw813/livetracking。 - 你最初的策略中,
iot:Subscribe的资源用的是topic/+/livetracking,这匹配的是消息发布时的实际Topic资源(对应iot:Receive动作),但不匹配订阅时的topicfilter资源,因此权限校验失败,导致订阅被拒绝。 - 第二个策略用
:*通配符覆盖了所有资源类型,自然包含了topicfilter,所以能通过权限校验。 - 第三个调试策略的资源列表里只有
topic/*,同样没有包含topicfilter类型的资源,因此还是无法通过iot:Subscribe的权限校验。
修正后的正确策略
将iot:Subscribe的资源改为topicfilter类型的ARN即可:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "iot:Subscribe", "Resource": [ "arn:aws:iot:<REGION>:<ACCOUNT>:topicfilter/+/livetracking", "arn:aws:iot:<REGION>:<ACCOUNT>:topicfilter/+/attendance" ] }, { "Effect": "Allow", "Action": "iot:Receive", "Resource": [ "arn:aws:iot:<REGION>:<ACCOUNT>:topic/+/livetracking", "arn:aws:iot:<REGION>:<ACCOUNT>:topic/+/attendance" ] }, { "Effect": "Allow", "Action": "iot:Connect", "Resource": "arn:aws:iot:<REGION>:<ACCOUNT>:client/${iot:ClientId}" } ] }
这样iot:Subscribe会匹配订阅过滤器的ARN,iot:Receive匹配实际接收消息的Topic ARN,既能满足权限最小化要求,又能正常完成订阅和消息接收。
内容的提问来源于stack exchange,提问作者Hammad Majeed
相关产品推荐
相关产品推荐

