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]
