文章目錄
RabbitMQ 為不同帳號設定不同 Queue 權限
同事在新功能的架構設計時想要讓不同 user 在 MQ 存取時可以有權限的概念,但以團隊之前使用的 Kafka 至少就我個人所知是無法達成的,不過這個需求在 RabbitMQ 上就有幾種不同的做法,今天就來紀錄一下相關的 POC 過程與設定方式
基本環境說明
- macOS Big Sur 11.2.2
- docker desktop 3.2.1 (61626)
docker images
rabbitmq:3.8.14-management
docker run -d --rm --hostname my-rabbit --name test-rabbit -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=pass.123 rabbitmq:3.8.14-management
RabbitMQ 基本設定
建立 exchange
以
yowkoex
為例rabbitmqadmin declare exchange name=yowkoex type=topic -u admin -p pass.123
建立 queue
以
topic1
,topic2
,topic3
為例rabbitmqadmin declare queue name=topic1 durable=false -u admin -p pass.123 rabbitmqadmin declare queue name=topic2 durable=false -u admin -p pass.123 rabbitmqadmin declare queue name=topic3 durable=false -u admin -p pass.123
將 queue 跟 exchange 做 binding
rabbitmqadmin declare binding source="yowkoex" destination_type="queue" destination="topic1" routing_key="topic1" -u admin -p pass.123 rabbitmqadmin declare binding source="yowkoex" destination_type="queue" destination="topic2" routing_key="topic2" -u admin -p pass.123 rabbitmqadmin declare binding source="yowkoex" destination_type="queue" destination="topic3" routing_key="topic3" -u admin -p pass.123
建立 user
yowko1
只能 access topic1;yowko23
只能 access topic2 與 topic3rabbitmqctl add_user yowko1 pass.123 rabbitmqctl add_user yowko23 pass.123
設定方式
以下三種方式擇一即可
使用 ui
- 設定 vhost 權限
- 設定 topic 權限
使用 rabbitmqctl
設定 vhost 權限
語法:
rabbitmqctl set_permissions [-p {vhost}] {user} {conf} {write} {read}s
rabbitmqctl set_permissions -p / yowko1 "" "" "topic1" rabbitmqctl set_permissions -p / yowko23 "" "" "^topic(2|3)$"
設定 topic 權限
語法:
rabbitmqctl set_topic_permissions [-p {vhost}] {user} {exchange} {write} {read}
rabbitmqctl set_topic_permissions -p / yowko1 yowkoex "" "topic1" rabbitmqctl set_topic_permissions -p / yowko23 yowkoex "" "^topic(2|3)$"
使用 http rest api
這個部份我沒有實際用過,就不特別紀錄了
實際效果
沒有 topic 權限的錯誤
錯誤訊息
Unhandled exception. RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=403, text='ACCESS_REFUSED - access to queue 'topic1' in vhost '/' refused for user 'yowko23'', classId=60, methodId=20 at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout) at RabbitMQ.Client.Impl.ModelBase.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer) at RabbitMQ.Client.Impl.AutorecoveringModel.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer) at RabbitMQ.Client.IModelExensions.BasicConsume(IModel model, String queue, Boolean autoAck, IBasicConsumer consumer)
錯誤截圖
沒有 vhost 權限的錯誤
錯誤訊息
Unhandled exception. RabbitMQ.Client.Exceptions.BrokerUnreachableException: None of the specified endpoints were reachable ---> RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=530, text='NOT_ALLOWED - access to vhost '/' refused for user 'yuser'', classId=10, methodId=40 at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout) at RabbitMQ.Client.Impl.ModelBase.ConnectionOpen(String virtualHost, String capabilities, Boolean insist) at RabbitMQ.Client.Framing.Impl.Connection.Open(Boolean insist) at RabbitMQ.Client.Framing.Impl.Connection..ctor(IConnectionFactory factory, Boolean insist, IFrameHandler frameHandler, String clientProvidedName) at RabbitMQ.Client.Framing.Impl.AutorecoveringConnection.Init(IFrameHandler fh) at RabbitMQ.Client.Framing.Impl.AutorecoveringConnection.Init(IEndpointResolver endpoints) at RabbitMQ.Client.ConnectionFactory.CreateConnection(IEndpointResolver endpointResolver, String clientProvidedName) --- End of inner exception stack trace --- at RabbitMQ.Client.ConnectionFactory.CreateConnection(IEndpointResolver endpointResolver, String clientProvidedName) at RabbitMQ.Client.ConnectionFactory.CreateConnection(String clientProvidedName) at RabbitMQ.Client.ConnectionFactory.CreateConnection()
錯誤截圖
心得
透過 user 的權限設定可以將不同 Queue 的讀寫權限分離,但這樣的做法是基於同一個 vhost 的前提下,如果想要更完整地做隔離或是需要 multiple tenants 概念就不是那麼適合,相關的做法待之後筆記再補充了
參考資訊
文章作者 Yowko Tsai
上次更新 2022-03-11
授權合約
本部落格 (Yowko's Notes) 所有的文章內容(包含圖片),任何轉載行為,必須通知並獲本部落格作者 (Yowko Tsai) 的同意始得轉載,且轉載皆須註明出處與作者。
Yowko's Notes 由 Yowko Tsai 製作,以創用CC 姓名標示-非商業性-相同方式分享 3.0 台灣 授權條款 釋出。