安全性

功能 > 安全性

ActiveMQ Classic 4.x 及更高版本透過各種不同的提供者提供可插拔的安全性。

最常見的提供者是

  • JAAS 用於身份驗證
  • 使用簡單的 XML 組態檔的預設授權機制。

身份驗證

預設的 JAAS 外掛程式依賴於標準的 JAAS 機制進行身份驗證。請參閱 文件以獲取更多詳細資訊。

通常,您會使用類似 這個的組態檔來設定 JAAS,並將 java.security.auth.login.config 系統屬性設定為指向它。如果沒有指定系統屬性,則預設情況下,ActiveMQ Classic JAAS 外掛程式將在類別路徑上尋找 login.config 並使用它。

身份驗證範例

以下是一個範例 login.config,它指向這些檔案

注意:在 5.11.1 版本之前,這些屬性檔案預設會在每次身份驗證請求時重新載入。因此,對使用者、密碼和群組的更新會立即載入。從 5.12 版本開始,只有在您的 LoginModule 組態中設定 reload=true 時才會重新載入,例如:

activemq { org.apache.activemq.jaas.PropertiesLoginModule required org.apache.activemq.jaas.properties.user="users.properties" org.apache.activemq.jaas.properties.group="groups.properties" reload=true; };

如果未設定 reload=true,這些屬性檔案僅會在 Broker 啟動時載入!請參閱 AMQ-5876 以獲取詳細資訊。

簡單身份驗證外掛程式

如果您有簡單的身份驗證需求(或只是想快速設定測試環境),您可以使用 SimpleAuthenticationPlugin。使用此外掛程式,您可以直接在 Broker 的 XML 組態中定義使用者和群組。請參考以下範例程式碼片段

<simpleAuthenticationPlugin>
  <users>
    <authenticationUser username="system" password="manager" groups="users,admins"/>
    <authenticationUser username="user" password="password" groups="users"/>
    <authenticationUser username="guest" password="password" groups="guests"/>
  </users>
</simpleAuthenticationPlugin>

以這種方式定義的使用者和群組稍後可用於適當的授權外掛程式。

匿名存取

從 5.4.0 版本開始,您可以設定簡單身份驗證外掛程式以允許對 Broker 進行匿名存取。

<simpleAuthenticationPlugin anonymousAccessAllowed="true"> <users> <authenticationUser username="system" password="manager" groups="users,admins"/> <authenticationUser username="user" password="password" groups="users"/> <authenticationUser username="guest" password="password" groups="guests"/> </users> </simpleAuthenticationPlugin>

若要允許對 Broker 進行匿名存取,請使用 anonymousAccessAllowed 屬性並將其設定為 true,如上所示。現在,當用戶端在沒有提供使用者名稱和密碼的情況下連線時,將會為其安全性內容分配預設的使用者名稱 (anonymous) 和群組 (anonymous)。您可以使用此使用者名稱和密碼來授權用戶端存取適當的 Broker 資源(請參閱下一節)。您也可以使用 anonymousUseranonymousGroup 屬性來變更將指派給匿名 使用者的使用者名稱和群組。

授權

在 ActiveMQ Classic 中,我們使用多種操作,您可以將這些操作與使用者角色以及個別佇列或主題關聯,或者您可以使用萬用字元來附加到主題和佇列的階層。

操作 說明
讀取 您可以從目的地瀏覽和使用
寫入 您可以將訊息傳送到目的地
管理 如果目的地尚不存在,您可以延遲建立目的地。這讓您可以精細控制可以在佇列/主題階層的哪個部分動態建立哪些新目的地

佇列/主題可以使用 ActiveMQ Classic 萬用字元語法指定。

授權範例

以下 範例顯示這 2 個外掛程式的運作方式。但請注意,編寫自己的外掛程式非常容易。請注意,一般而言,應將完全存取權授予 ActiveMQ.Advisory 目的地,因為預設情況下,ActiveMQConnection 會使用目的地通知來及早了解臨時目的地的建立和刪除。此外,動態網路連接器會使用通知來判斷使用者需求。
如有必要,可以透過 ActiveMQConnectionFactory 的 watchTopicAdvisories 布林屬性和網路連接器的網路連接器 staticBridge (5.6) 布林屬性來停用以這種方式使用通知。

Broker 到 Broker 的身份驗證和授權

如果您已為特定的訊息 Broker 啟用身份驗證,則其他想要連線到該 Broker 的 Broker 必須透過其元素提供適當的身份驗證憑證。例如,假設我們有一個具有以下組態的 Broker 網路

  • Broker 網路包含兩個 Broker (BrokerA 和 BrokerB)
  • 已透過範例 <simpleAuthenticationPlugin> 元素為 BrokerA 啟用身份驗證。
  • 尚未為 BrokerB 啟用身份驗證。
  • BrokerA 僅監聽連線。換句話說,BrokerA 具有 <transportConnector> 元素,但沒有 <networkConnector> 元素。

為了讓 BrokerB 連線到 BrokerA,BrokerB XML 組態檔中的相應元素必須設定如下。

<networkConnectors> 
  <networkConnector name="brokerAbridge" userName="user" password="password" uri="static://(tcp://brokerA:61616)"/> 
</networkConnectors>

請注意,BrokerB 的 <networkConnector> 元素必須提供適當的憑證才能連線到 BrokerA。如果已在 BrokerA 上啟用授權,則指派給 <networkConnector> 元素的使用者名稱也必須具有適當的授權憑證。如果 BrokerA 已啟用授權,且 BrokerB 相應的 <networkConnector> 元素的使用者名稱未獲得適當的授權憑證,則無法將訊息從 BrokerB 轉寄到 BrokerA。

此外,如果 BrokerA 獲得 <networkConnector> 元素,使其可以起始與 BrokerB 的連線,則必須為該 <networkConnector> 提供在 <simpleAuthenticationPlugin> 元素中定義的使用者名稱/密碼組合;即使 BrokerB 沒有啟用身份驗證服務,也需要這樣做。

控制對臨時目的地的存取

若要控制對臨時目的地的存取,您需要將 <tempDestinationAuthorizationEntry> 元素新增至 authorizationMap。透過這個元素,您可以控制對所有臨時目的地的存取。如果此元素不存在,則會將臨時目的地的讀取、寫入和管理權限授予所有人。在下面的範例中,臨時目的地的讀取、寫入和管理權限僅授予那些已指派給「管理員」群組的用戶端。

<broker> 
  .. 
    <plugins> 
      .. 
      <authorizationPlugin> 
        <map> 
          <authorizationMap> 
            <authorizationEntries> 
              <authorizationEntry queue="TEST.Q" read="users" write="users" admin="users" /> 
              <authorizationEntry topic="ActiveMQ.Advisory.>" read="*" write="*" admin="*"/> 
            </authorizationEntries> 
            <tempDestinationAuthorizationEntry> 
              <tempDestinationAuthorizationEntry read="admin" write="admin" admin="admin"/> 
            </tempDestinationAuthorizationEntry> 
          </authorizationMap> 
        </map> 
      </authorizationPlugin> 
      .. 
    </plugins> 
  .. 
</broker>

使用 JAAS 外掛程式進行 LDAP 身份驗證

新模組

自 5.6 版起,提供新的/更好的 ldap 授權模組。請參閱 快取 LDAP 授權模組以獲取更多資訊。

  1. 在 activemq.xml 中設定 JAAS LDAPLoginModule 和 LDAPAuthorizationMap

     <plugins> 
       <!-- use JAAS to authenticate using the login.config file on the classpath to configure JAAS --> 
       <jaasAuthenticationPlugin configuration="LdapConfiguration" /> 
       <!-- lets configure a destination based role/group authorization mechanism --> 
       <authorizationPlugin> 
         <map> 
           <bean xmlns="http://www.springframework.org/schema/beans" id="lDAPAuthorizationMap" class="org.apache.activemq.security.LDAPAuthorizationMap"> 
             <property name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/> 
             <property name="connectionURL" value="ldap://ldap.acme.com:389"/> 
             <property name="authentication" value="simple"/> 
             <property name="connectionUsername" value="cn=mqbroker,ou=Services,dc=acme,dc=com"/> 
             <property name="connectionPassword" value="password"/> 
             <property name="connectionProtocol" value="s"/> 
             <property name="topicSearchMatching" value="cn={0},ou=Topic,ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=com"/> 
             <property name="topicSearchSubtreeBool" value="true"/> 
             <property name="queueSearchMatching" value="cn={0},ou=Queue,ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=com"/> 
             <property name="queueSearchSubtreeBool" value="true"/> 
             <property name="adminBase" value="(cn=admin)"/> 
             <property name="adminAttribute" value="member"/> 
             <property name="adminAttributePrefix" value="cn="/> 
             <property name="readBase" value="(cn=read)"/> 
             <property name="readAttribute" value="member"/> 
             <property name="readAttributePrefix" value="cn="/> 
             <property name="writeBase" value="(cn=write)"/> 
             <property name="writeAttribute" value="member"/> 
             <property name="writeAttributePrefix" value="cn="/> 
           </bean> 
         </map> 
       </authorizationPlugin> 
     </plugins>
    
  2. 設定 JAAS login.config (我尚未刪除重複的組態)
     LdapConfiguration { 
        org.apache.activemq.jaas.LDAPLoginModule required 
        initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory 
        connectionURL="ldap://ldap.acme.com:389" 
        connectionUsername="cn=mqbroker,ou=Services,dc=acme,dc=com" 
        connectionPassword=password connectionProtocol=s 
        authentication=simple 
        userBase="ou=User,ou=ActiveMQ,ou=systems,dc=acme,dc=com" 
        userRoleName=dummyUserRoleName 
        userSearchMatching="(uid={0})" 
        userSearchSubtree=false 
        roleBase="ou=Group,ou=ActiveMQ,ou=systems,dc=acme,dc=com" 
        roleName=cn 
        roleSearchMatching="(member:=uid={1})" 
        roleSearchSubtree=true 
        ; 
     };
    
  3. 將以下 LDIF 檔案匯入 LDAP 伺服器
     version: 1 
     # 
     # Sample LDIF for ActiveMQ LDAP authentication and authorisation 
     # Passwords are defaulted to "password" - it is your responsibility to change them! 
     # 
     # Sets up: 
     # 1. Bind user 
     # 2. A sample queue with admin,read,write permission assignments 
     # 3. ActiveMQ Classic advisory topics 
     # 4. Two groups - admin and webapp 
     # 5. Two users - admin and webapp 
     # 6. Role assignments - admin->admin, webapp->webapp 
     # 
     # (c) Robin Bramley 2008 # Provided as is without any warranty of any kind 
     # 
     dn: dc=acme,dc=com 
     dc: acme 
     objectClass: domain 
     objectClass: top 
        
     dn: ou=Services,dc=acme,dc=com 
     ou: Services 
     objectClass: organizationalUnit 
     objectClass: top 
        
     dn: cn=mqbroker,ou=Services,dc=acme,dc=com 
     cn: mqbroker 
     objectClass: organizationalRole 
     objectClass: top 
     objectClass: simpleSecurityObject 
     userPassword: {SSHA}j0NpveEO0YD5rgI5kY8OxSRiN5KQ/kE4 
     description: Bind user for MQ broker 
        
     dn: ou=systems,dc=acme,dc=com 
     ou: systems 
     objectClass: organizationalUnit 
     objectClass: top 
        
     dn: ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: ActiveMQ 
        
     dn: ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: Destination 
        
     dn: ou=Queue,ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: Queue 
        
     dn: cn=com.acme.myfirstrealqueue,ou=Queue,ou=Destination,ou=ActiveMQ,ou=syst ems,dc=acme,dc=com 
     cn: com.acme.myfirstrealqueue 
     description: A queue 
     objectClass: applicationProcess 
     objectClass: top 
        
     dn: cn=admin,cn=com.acme.myfirstrealqueue,ou=Queue,ou=Destination,ou=ActiveM Q,ou=systems,dc=acme,dc=com 
     cn: admin 
     description: Admin privilege group, members are roles 
     member: cn=admin 
     member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=read,cn=com.acme.myfirstrealqueue,ou=Queue,ou=Destination,ou=ActiveMQ ,ou=systems,dc=acme,dc=com 
     cn: read member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=write,cn=com.acme.myfirstrealqueue,ou=Queue,ou=Destination,ou=ActiveM Q,ou=systems,dc=acme,dc=com 
     cn: write 
     objectClass: groupOfNames 
     objectClass: top member: cn=webapp 
        
     dn: ou=Topic,ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=co m 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: Topic 
        
     dn: cn=ActiveMQ.Advisory.Consumer,ou=Topic,ou=Destination,ou=ActiveMQ,ou=sys tems,dc=acme,dc=com 
     cn: ActiveMQ.Advisory.Consumer 
     objectClass: applicationProcess 
     objectClass: top description: Advisory topic about consumers 
        
     dn: cn=read,cn=ActiveMQ.Advisory.Consumer,ou=Topic,ou=Destination,ou=ActiveM Q,ou=systems,dc=acme,dc=com 
     cn: read member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=ActiveMQ.Advisory.TempQueue,ou=Topic,ou=Destination,ou=ActiveMQ,ou=sy stems,dc=acme,dc=com 
     cn: ActiveMQ.Advisory.TempQueue 
     description: Advisory topic about temporary queues 
     objectClass: applicationProcess 
     objectClass: top 
        
     dn: cn=read,cn=ActiveMQ.Advisory.TempQueue,ou=Topic,ou=Destination,ou=Active MQ,ou=systems,dc=acme,dc=com 
     cn: read member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=ActiveMQ.Advisory.TempTopic,ou=Topic,ou=Destination,ou=ActiveMQ,ou=sy stems,dc=acme,dc=com 
     cn: ActiveMQ.Advisory.TempTopic 
     objectClass: applicationProcess 
     objectClass: top 
     description: Advisory topic about temporary topics 
        
     dn: cn=read,cn=ActiveMQ.Advisory.TempTopic,ou=Topic,ou=Destination,ou=Active MQ,ou=systems,dc=acme,dc=com 
     cn: read 
     member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: ou=Group,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: Group 
        
     dn: cn=admin,ou=Group,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     cn: admin 
     member: uid=admin 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=webapp,ou=Group,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     cn: webapp 
     member: uid=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: ou=User,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: User 
        
     dn: uid=admin,ou=User,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     uid: admin 
     userPassword: {SSHA}j0NpveEO0YD5rgI5kY8OxSRiN5KQ/kE4 
     objectClass: account 
     objectClass: simpleSecurityObject 
     objectClass: top 
        
     dn: uid=webapp,ou=User,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     uid: webapp 
     userPassword: {SSHA}j0NpveEO0YD5rgI5kY8OxSRiN5KQ/kE4 
     objectClass: account 
     objectClass: simpleSecurityObject 
     objectClass: top
    
  4. 啟動 ActiveMQ Classic

  5. 測試一下

安全性與 ActiveMQ Classic 組件

除了訊息 Broker 之外,您還可以選擇性地執行幾個額外的「元件」,例如 Camel 和/或 Web 主控台。這些元件與 Broker 建立連線;因此,如果您已保護您的 Broker(即已啟用身份驗證),您必須設定這些元件,才能讓它們在連線到 Broker 時提供所需的安全性憑證(使用者名稱、密碼)。

Camel

您可能在 Broker 的 XML 組態檔中定義了以下 Camel 環境。

<!-- ** Lets deploy some Enterprise Integration Patterns inside the ActiveMQ Classic Message Broker ** For more details see ** ** https://activemq.dev.org.twFeatures/enterprise-integration-patterns.md -->
<camelContext id="camel" xmlns="https://activemq.dev.org.tw/camel/schema/spring">
  <package>org.foo.bar</package>
  <route> 
    <from uri="activemq:example.A"/>
    <to uri="activemq:example.B"/>
  </route>
</camelContext>

上述組態並未設定為在安全環境中運作。

如果應用程式在 OSGi 容器中執行,請在 CamelContext 定義之前新增以下行

<osgi:reference id="activemq" interface="org.apache.camel.Component" />

這允許容器中部署的任何預先設定的 ActiveMQComponent 實例優先於預設的 ActiveMQComponent。

也就是說,使用上述組態,Camel 會與 ActiveMQ Classic 建立連線,但不會提供使用者名稱和密碼。因此,當啟用 ActiveMQ Classic 安全性時,上述組態會導致安全性例外狀況。此例外狀況會擲回多次,因為 Camel 會繼續重試連線。如果您未使用 Camel,請註釋掉上述 XML 程式碼。如果您正在使用 Camel,請將以下 Bean 定義新增至 Broker 的 XML 組態

<!-- configure the camel activemq component to use the current broker -->
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent" >
  <property name="connectionFactory"> 
    <bean class="org.apache.activemq.ActiveMQConnectionFactory">
      <property name="brokerURL" value="vm://127.0.0.1?create=false&amp;waitForStart=10000" />
      <property name="userName" value="system"/> 
      <property name="password" value="manager"/>
    </bean>
  </property>
</bean>

使用上述 Bean 定義,Camel 會在連線到 Broker 時傳遞指定的安全性憑證。

如果 Broker 在 OSGi 容器中執行,請在 ActiveMQComponent Bean 定義之後新增以下行

<service ref="activemq" interface="org.apache.camel.Component"/>

Web 主控台

如果您想要在安全的 Broker 中使用 Web 主控台,您必須將 webapps/admin/WEB-INF/webconsole-embeded.xml 中的 connectionFactory Bean 變更為如下所示的內容

<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
  <property name="brokerURL" value="vm://127.0.0.1"/>
  <property name="userName" value="system"/>
  <property name="password" value="manager"/>
</bean>

預設憑證

從 5.3 版開始,所有上述組態詳細資訊都包含在預設的 ActiveMQ Classic 組態中。此外,還有一個集中位置,您可以在其中設定這些元件將用來連線到 Broker 的憑證。只需在 conf/credentials.properties 檔案中設定您所需的使用者名稱和密碼即可,預設情況下如下所示

activemq.username=system activemq.password=manager

加密的密碼

從 5.4.1 版開始,您也可以將 加密的密碼與您的 Broker 搭配使用

訊息層級授權

也可以使用您選擇的某些基於內容的授權原則來授權每個訊息。與之前描述的其他安全性選項相比,訊息層級授權需要的設定不僅僅是一些組態。您必須先建立一個新的 Maven 專案,並將 activemq-all Maven 相依性(與您的 ActiveMQ 安裝版本相同的版本)新增到新專案的 pom.xml 中。
下一步,您必須建立一個新的 Java 類別,並讓它實作 org.apache.activemq.security.MessageAuthorizationPolicy 介面。之後,只需將一個具有簽名的 方法新增到新的 Java 類別中

public boolean isAllowedToConsume(ConnectionContext context, Message message){...}

若要使用您自己的訊息層級授權原則,Java 類別必須打包為 jar,並新增到 ActiveMQ Classic 的 /lib 資料夾中,使其可用。最後一步,必須使用 *messageAuthorizationPolicy* 屬性直接在 Broker 上設定它,或將其新增到 XML 中,如下所示

<broker>
  ..
  <messageAuthorizationPolicy>
    <bean class="com.acme.MyMessageAuthorizationPolicy" xmlns=""/>
  </messageAuthorizationPolicy>
  ..
</broker>

實作您自己的自訂安全性外掛程式

所有各種安全性實作都以 攔截器的形式實作,因此新增您自己的自訂實作非常容易。如果您使用 JAAS,則從 簡單實作之一開始可能會更容易,但您可以從 JAAS 實作派生。

Apache、ActiveMQ、Apache ActiveMQ、Apache 羽毛標誌和 Apache ActiveMQ 專案標誌是 Apache 軟體基金會的商標。Copyright © 2024, The Apache Software Foundation。根據 Apache 授權 2.0 授權。