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**)

Reply via email to