iloveeyjafjalla opened a new issue, #11408:
URL: https://github.com/apache/rocketmq/issues/11408

   ### Before Creating the Bug Report
   
   - [x] I found a bug, not just asking a question, which should be created in 
[GitHub Discussions](https://github.com/apache/rocketmq/discussions).
   - [x] I have searched the [GitHub 
Issues](https://github.com/apache/rocketmq/issues) and [GitHub 
Discussions](https://github.com/apache/rocketmq/discussions) of this repository 
and believe that this is not a duplicate.
   - [x] I have confirmed that this bug belongs to the current repository, not 
other repositories of RocketMQ.
   
   ### Runtime platform environment
   
   OS: any (broker container mode, started with `mqbrokercontainer`, with ACL 
2.0 enabled on the inner brokers)
   
   ### RocketMQ version
   
   branch: develop
   Git commit id: a7edeecfb
   
   ### JDK Version
   
   Compiler: Temurin 1.8.0_504 (target 1.8, same as CI)
   
   ### Describe the Bug
   
   A standalone broker derives the three identity fields of `AuthConfig` from 
the broker configuration it just loaded 
(`broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java:241-243`):
   
   ```java
   authConfig.setConfigName(brokerConfig.getBrokerName());
   authConfig.setClusterName(brokerConfig.getBrokerClusterName());
   authConfig.setAuthConfigPath(messageStoreConfig.getStorePathRootDir() + 
File.separator + "config");
   ```
   
   The proxy does the same for the first two 
(`proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java:50-51`).
 The two places that start a broker **inside a broker container** never do it: 
they build the `AuthConfig` from the per-broker properties and stop there.
   
   - 
`container/src/main/java/org/apache/rocketmq/container/BrokerContainerStartup.java:134-140`
 (`createAndInitializeBroker`)
   - 
`container/src/main/java/org/apache/rocketmq/container/BrokerContainerProcessor.java:120-123`
 (the `mqadmin addBroker` RPC path)
   
   `AuthConfig.configName`, `AuthConfig.clusterName` and 
`AuthConfig.authConfigPath` have **no defaults** 
(`auth/src/main/java/org/apache/rocketmq/auth/config/AuthConfig.java:26-30`), 
so all three stay `null`. That shows up in three concrete ways:
   
   1. **The ACL 2.0 user/ACL database is created at a relative path.** 
`LocalAuthenticationMetadataProvider.initialize` and 
`LocalAuthorizationMetadataProvider.initialize` open RocksDB at 
`authConfig.getAuthConfigPath() + File.separator + "users"` / `"acls"`. With a 
null path this is the literal relative path `null/users` / `null/acls`, created 
under the **process working directory**, instead of 
`<storePathRootDir>/config/users` next to the broker's store. Restarting the 
container from a different working directory silently comes up with an empty 
user/ACL store.
   2. **Cluster-scoped admin requests are authorized as `Cluster:null`.** 
`DefaultAuthorizationContextBuilder` builds those resources from 
`authConfig.getClusterName()` 
(`auth/.../DefaultAuthorizationContextBuilder.java:465`, `553`, `579`, `672`) 
for `UPDATE_AND_CREATE_TOPIC_LIST`, `GET_ALL_TOPIC_CONFIG`, 
`DELETE_TOPIC_IN_BROKER_LIST` and `DELETE_SUBSCRIPTION_GROUP_LIST`. With a null 
cluster name the resource key is `Cluster:null`, so a policy that grants a 
concrete cluster (`Cluster:<clusterName>`, `Resource.isMatch` compares the 
names literally) never matches: cluster-wide `mqadmin updateTopic -c ...` / 
`deleteTopic -c ...` are rejected with `NO_PERMISSION` on brokers started by a 
container.
   3. **All inner brokers share one set of auth singletons.** 
`AuthenticationFactory`/`AuthorizationFactory` cache providers/evaluators in a 
static map keyed by `PROVIDER_`/`METADATA_PROVIDER_`/`EVALUATOR_` + 
`config.getConfigName()` (`AuthenticationFactory.java:51`, `:78`, `:95`; 
`AuthorizationFactory.java:52`, `:80`, `:97`). With a null name every broker 
started by the container uses the `..._null` entry, so the second and later 
brokers reuse the instances created for the first one — including a metadata 
provider configured for only one of them — instead of each broker owning its 
own; `AuthenticationMetadataManagerImpl.shutdown()` of one broker also closes 
that shared provider for the others.
   
   The standalone broker is not affected because it always fills the three 
fields before the `BrokerController` is constructed.
   
   ### Steps to Reproduce
   
   1. Prepare two per-broker configuration files that enable ACL 2.0 (as the 
ACL 2.0 setup requires): `authenticationEnabled=true`, 
`authenticationMetadataProvider=org.apache.rocketmq.auth.authentication.provider.LocalAuthenticationMetadataProvider`,
 `authorizationEnabled=true`, 
`authorizationMetadataProvider=org.apache.rocketmq.auth.authorization.provider.LocalAuthorizationMetadataProvider`,
 plus `brokerName`, `brokerClusterName` and `storePathRootDir`.
   2. Start a container with those brokers: `mqbrokercontainer -c 
<container.conf>` (or start the container and add a broker with `mqadmin 
addBroker -b <broker.conf>`).
   3. Observe that the user/ACL data is created under `<cwd>/null/users` and 
`<cwd>/null/acls` instead of `<storePathRootDir>/config/users` and `.../acls`, 
that `getAuthConfig().getClusterName()` is null, and that a 
`Cluster:<clusterName>` grant does not authorize `mqadmin updateTopic -c 
<cluster>`.
   4. At the unit level the same state is reproduced deterministically by 
starting a broker through the container and checking the `AuthConfig` the 
container put on it: `createAndInitializeBroker(...)` → 
`brokerContainer.addBroker(...)` → `innerBrokerController.getAuthConfig()`, 
i.e. the three fields must equal the values `BrokerStartup` would have set.
   
   ### What Did You Expect to See?
   
   A broker started by the container behaves like the same broker started by 
`mqbroker`: `configName` = `brokerName`, `clusterName` = `brokerClusterName`, 
`authConfigPath` = `<storePathRootDir>/config`, so ACL data lives next to the 
broker store, cluster-scoped authorization sees the real cluster name, and each 
broker owns its own auth provider/evaluator instances.
   
   ### What Did You See Instead?
   
   All three fields stay null (and are silently accepted), so the auth database 
is written to a working-directory-relative `null/` directory, cluster-scoped 
policies are evaluated against `Cluster:null`, and the inner brokers collapse 
onto shared `*_null` factory entries. Nothing in the shipped configurations or 
documentation asks a container user to set these fields by hand (`grep -r 
authConfigPath distribution/ docs/` finds nothing), so there is no way to avoid 
it other than knowing the setter-derived key names that 
`MixAll.properties2Object` accepts.
   
   ### Additional Context
   
   Minimal fix: mirror `BrokerStartup.java:241-243` in both container entry 
points (a shared helper so the two paths cannot drift apart again). Scope note: 
a master and a slave that share one `brokerName` inside a single container 
still share the per-name factory entries, which matches the standalone 
semantics where each of them is its own JVM; the fix deliberately keeps that 
parity instead of inventing a different key.
   
   I will open a PR with the change plus a regression test that starts a broker 
through the container and asserts the three fields against the values the 
standalone startup would have derived (red before the change, green after).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to