This is an automated email from the ASF dual-hosted git repository.
anmolnar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zookeeper.git
The following commit(s) were added to refs/heads/master by this push:
new 981a2fd4a ZOOKEEPER-5050: Disable AdminServer and enhance
documentation to highlight security considerations
981a2fd4a is described below
commit 981a2fd4acb086f0df790025771a677788925122
Author: Andor Molnár <[email protected]>
AuthorDate: Mon Jun 22 17:47:21 2026 -0500
ZOOKEEPER-5050: Disable AdminServer and enhance documentation to highlight
security considerations
Reviewers: eolivelli, phunt
Author: anmolnar
Closes #2389 from anmolnar/ZOOKEEPER-5050
---
.../zookeeper/server/admin/AdminServerFactory.java | 17 +--
.../server/admin/AdminServerFactoryTest.java | 48 +++++++
.../admin-ops/administrators-guide/commands.mdx | 144 ++++++++++++++++++---
.../configuration-parameters.mdx | 4 +-
4 files changed, 180 insertions(+), 33 deletions(-)
diff --git
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/AdminServerFactory.java
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/AdminServerFactory.java
index 555f5e427..8a6ae918c 100644
---
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/AdminServerFactory.java
+++
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/AdminServerFactory.java
@@ -28,6 +28,7 @@
public class AdminServerFactory {
private static final Logger LOG =
LoggerFactory.getLogger(AdminServerFactory.class);
+ static final String ENABLE_ADMIN_SERVER_PROPERTY =
"zookeeper.admin.enableServer";
/**
* This method encapsulates the logic for whether we should use a
@@ -38,21 +39,17 @@ public class AdminServerFactory {
* to pull in Jetty with ZooKeeper.
*/
public static AdminServer createAdminServer() {
- if
(!"false".equals(System.getProperty("zookeeper.admin.enableServer"))) {
+ if (Boolean.getBoolean(ENABLE_ADMIN_SERVER_PROPERTY)) {
try {
Class<?> jettyAdminServerC =
Class.forName("org.apache.zookeeper.server.admin.JettyAdminServer");
Object adminServer =
jettyAdminServerC.getConstructor().newInstance();
return (AdminServer) adminServer;
- } catch (ClassNotFoundException e) {
- LOG.warn("Unable to start JettyAdminServer", e);
- } catch (InstantiationException e) {
- LOG.warn("Unable to start JettyAdminServer", e);
- } catch (IllegalAccessException e) {
- LOG.warn("Unable to start JettyAdminServer", e);
- } catch (InvocationTargetException e) {
- LOG.warn("Unable to start JettyAdminServer", e);
- } catch (NoSuchMethodException e) {
+ } catch (ClassNotFoundException
+ | InstantiationException
+ | IllegalAccessException
+ | InvocationTargetException
+ | NoSuchMethodException e) {
LOG.warn("Unable to start JettyAdminServer", e);
} catch (NoClassDefFoundError e) {
LOG.warn("Unable to load jetty, not starting
JettyAdminServer", e);
diff --git
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/AdminServerFactoryTest.java
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/AdminServerFactoryTest.java
new file mode 100644
index 000000000..c0406ba91
--- /dev/null
+++
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/AdminServerFactoryTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.server.admin;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+public class AdminServerFactoryTest {
+
+ @AfterEach
+ public void tearDown() {
+ System.clearProperty(AdminServerFactory.ENABLE_ADMIN_SERVER_PROPERTY);
+ }
+
+ @Test
+ public void testAdminServerDisabledByDefault() {
+ System.clearProperty(AdminServerFactory.ENABLE_ADMIN_SERVER_PROPERTY);
+ AdminServer adminServer = AdminServerFactory.createAdminServer();
+ assertTrue(adminServer instanceof DummyAdminServer);
+ assertFalse(adminServer instanceof JettyAdminServer);
+ }
+
+ @Test
+ public void testAdminServerEnabled() {
+ System.setProperty(AdminServerFactory.ENABLE_ADMIN_SERVER_PROPERTY,
"true");
+ AdminServer adminServer = AdminServerFactory.createAdminServer();
+ assertFalse(adminServer instanceof DummyAdminServer);
+ assertTrue(adminServer instanceof JettyAdminServer);
+ }
+}
diff --git
a/zookeeper-website/app/pages/_docs/docs/_mdx/admin-ops/administrators-guide/commands.mdx
b/zookeeper-website/app/pages/_docs/docs/_mdx/admin-ops/administrators-guide/commands.mdx
index f9abfa9bf..001875aa2 100644
---
a/zookeeper-website/app/pages/_docs/docs/_mdx/admin-ops/administrators-guide/commands.mdx
+++
b/zookeeper-website/app/pages/_docs/docs/_mdx/admin-ops/administrators-guide/commands.mdx
@@ -183,29 +183,131 @@ $ echo ruok | nc 127.0.0.1 5111
## The AdminServer
-**New in 3.5.0:** The AdminServer is
-an embedded Jetty server that provides an HTTP interface to the four-letter
-word commands. By default, the server is started on port 8080,
-and commands are issued by going to the URL "/commands/\[command name]",
-e.g., http://localhost:8080/commands/stat. The command response is
-returned as JSON. Unlike the original protocol, commands are not
-restricted to four-letter names, and commands can have multiple names;
-for instance, "stmk" can also be referred to as "set_trace_mask". To
-view a list of all available commands, point a browser to the URL
-/commands (e.g., http://localhost:8080/commands). See the [AdminServer
configuration options](#configuring-adminserver-for-ssltls)
-for how to change the port and URLs.
-
-The AdminServer is enabled by default, but can be disabled by either:
-
-- Setting the zookeeper.admin.enableServer system
- property to false.
-- Removing Jetty from the classpath. (This option is
- useful if you would like to override ZooKeeper's jetty
- dependency.)
-
-Note that the TCP four-letter word interface is still available if
+**New in 3.5.0:** The AdminServer is an embedded Jetty server that provides an
HTTP interface to the four-letter word
+commands. In ZooKeeper releases 3.5.0 through 3.9.x, the AdminServer was
enabled by default. Starting with ZooKeeper
+3.10.0, the default configuration disables the AdminServer. When enabled, the
server listens on port 8080 by default,
+and commands are issued by accessing the URL `/commands/[command name]`, for
example, `http://localhost:8080/commands/stat`.
+Command responses are returned in JSON format.
+
+Unlike the original protocol, commands are not restricted to four-letter
names, and commands can have multiple aliases;
+for example, `stmk` can also be referred to as `set_trace_mask`. To view a
list of all available commands, access the
+`/commands` endpoint (for example, `http://localhost:8080/commands`). See the
AdminServer configuration options for
+information on changing the port and URL mappings.
+
+Beginning with ZooKeeper 3.10.0, the AdminServer is disabled by default and
can be enabled by setting the
+`zookeeper.admin.enableServer` system property to `true`. When enabled without
additional configuration, the AdminServer
+listens on all network interfaces (`0.0.0.0`), uses unencrypted HTTP, and does
not require client authentication.
+Administrators are strongly encouraged to restrict network access and
configure appropriate transport security and
+authentication before exposing the AdminServer in production environments.
+
+Make sure that Jetty is available on the classpath, because the AdminServer
will automatically remain disabled if Jetty
+cannot be found. This behavior can be useful when overriding ZooKeeper's Jetty
dependency.
+
+Note that the TCP four-letter word interface is still available for monitoring
purposes if
the AdminServer is disabled.
+### Security Considerations
+
+> **Important:** The AdminServer is disabled by default. When enabled without
additional configuration,
+> it listens on all network interfaces (0.0.0.0) on port 8080, uses
unencrypted HTTP, and does not
+> require client authentication. As a result, most administrative commands are
accessible to any client
+> that can reach the AdminServer. Administrators should restrict access
appropriately and enable transport
+> security and authentication when deploying the AdminServer in production.
+
+### Default Security Posture
+
+The default AdminServer configuration is intended for ease of use in trusted
environments, but it is **not secure for
+exposure to untrusted networks**.
+
+Default settings include:
+
+- `admin.enableServer=false`
+- `admin.serverAddress=0.0.0.0`
+- `admin.serverPort=8080`
+- `admin.forceHttps=false`
+- `admin.needClientAuth=false`
+
+With these defaults:
+
+- All traffic is transmitted in clear text over HTTP.
+- Administrative data, including configuration and runtime details, can be
viewed by anyone with network access.
+- Many commands (such as `stat`, `srvr`, `conf`, and `cons`) do not require
authentication.
+- Sensitive operational information may be disclosed.
+- In some environments, unrestricted administrative access can increase the
impact of vulnerabilities or misconfiguration.
+
+### Recommended Deployment Practices
+
+Administrators should ensure that the AdminServer is accessible only to
authorized users.
+
+#### Option 1: Restrict Access with Firewall Rules (Minimum Recommendation)
+
+Limit access to the AdminServer port to trusted hosts or management networks
only.
+
+Examples:
+
+- Bind the server to localhost:
+
+ ```properties
+ admin.serverAddress=127.0.0.1
+ ```
+
+- Use host-based firewall rules (such as `iptables`, `firewalld`, or cloud
security groups) to allow access only from
+- administrative systems.
+
+This is the minimum recommended protection when HTTPS and client
authentication are not enabled.
+
+#### Option 2: Enable HTTPS
+
+To encrypt all communication, configure SSL/TLS and force HTTPS:
+
+```properties
+admin.forceHttps=true
+```
+
+This prevents credentials and administrative data from being transmitted in
clear text. ZooKeeper supports configuring
+the AdminServer with TLS certificates and trust stores.
+
+#### Option 3: Require Client Authentication
+
+To restrict access to trusted clients using X.509 certificates:
+
+```properties
+admin.needClientAuth=true
+```
+
+When enabled, only clients presenting valid certificates trusted by the server
will be allowed to connect.
+
+### Recommended Secure Configuration
+
+For production environments, the following configuration is strongly
recommended:
+
+```properties
+admin.forceHttps=true
+admin.needClientAuth=true
+admin.serverAddress=<management-network-ip>
+```
+
+In addition, restrict access to the AdminServer port using firewall rules.
+
+### Leave AdminServer disabled If Not Needed
+
+If you do not use the AdminServer, disable it explicitly:
+
+```properties
+admin.enableServer=false
+```
+
+### Security Warning
+
+Exposing the AdminServer to untrusted networks with the default configuration
may allow unauthorized users to:
+
+- Retrieve server configuration and runtime information
+- Inspect connected clients and sessions
+- Reset statistics
+- Execute other administrative commands
+
+Always protect the AdminServer with **network-level controls** and,
preferably, **HTTPS with client certificate authentication**.
+
## Configuring AdminServer for SSL/TLS
- Generating the **keystore.jks** and **truststore.jks** which can be found in
the [Quorum
TLS](/admin-ops/administrators-guide/communication-using-the-netty-framework#quorum-tls).
diff --git
a/zookeeper-website/app/pages/_docs/docs/_mdx/admin-ops/administrators-guide/configuration-parameters.mdx
b/zookeeper-website/app/pages/_docs/docs/_mdx/admin-ops/administrators-guide/configuration-parameters.mdx
index 5277504a9..93fcfdf8e 100644
---
a/zookeeper-website/app/pages/_docs/docs/_mdx/admin-ops/administrators-guide/configuration-parameters.mdx
+++
b/zookeeper-website/app/pages/_docs/docs/_mdx/admin-ops/administrators-guide/configuration-parameters.mdx
@@ -1720,8 +1720,8 @@ options are used to configure the
[AdminServer](#adminserver-configuration).
- _admin.enableServer_ :
(Java system property: **zookeeper.admin.enableServer**)
- Set to "false" to disable the AdminServer. By default the
- AdminServer is enabled.
+ Set to "true" to enable the AdminServer. By default, the
+ AdminServer is disabled.
- _admin.serverAddress_ :
(Java system property: **zookeeper.admin.serverAddress**)