This is an automated email from the ASF dual-hosted git repository.

young pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new b9d916b65 fix:  deployment data plane with read-only etcd (#12375)
b9d916b65 is described below

commit b9d916b6520005337b33fccaf7b817cc16993df4
Author: YYYoung <isk...@outlook.com>
AuthorDate: Thu Jun 26 17:29:41 2025 +0800

    fix:  deployment data plane with read-only etcd (#12375)
---
 apisix/cli/etcd.lua                                |   9 ++
 ...est_deployment_data_plane_with_readonly_etcd.sh | 178 +++++++++++++++++++++
 2 files changed, 187 insertions(+)

diff --git a/apisix/cli/etcd.lua b/apisix/cli/etcd.lua
index b67248095..548a5d241 100644
--- a/apisix/cli/etcd.lua
+++ b/apisix/cli/etcd.lua
@@ -379,6 +379,15 @@ function _M.init(env, args)
         util.die("the etcd cluster needs at least 50% and above healthy 
nodes\n")
     end
 
+    -- access from the data plane to etcd should be read-only.
+    -- data plane writes to etcd may cause security issues.
+    if yaml_conf.deployment.role == "data_plane" then
+        print("access from the data plane to etcd should be read-only, "
+              .."skip initializing the data of etcd")
+        return true
+    end
+
+    print("trying to initialize the data of etcd")
     local etcd_ok = false
     for index, host in ipairs(etcd_healthy_hosts) do
         if prepare_dirs(yaml_conf, args, index, host, host_count) then
diff --git a/t/cli/test_deployment_data_plane_with_readonly_etcd.sh 
b/t/cli/test_deployment_data_plane_with_readonly_etcd.sh
new file mode 100755
index 000000000..c6f164b67
--- /dev/null
+++ b/t/cli/test_deployment_data_plane_with_readonly_etcd.sh
@@ -0,0 +1,178 @@
+#!/usr/bin/env bash
+
+#
+# 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.
+#
+
+. ./t/cli/common.sh
+
+# clean etcd data
+etcdctl del / --prefix
+
+# non data_plane can prepare dirs when init etcd
+echo '
+deployment:
+    role: traditional
+    role_traditional:
+        config_provider: etcd
+    etcd:
+        host:
+            - http://127.0.0.1:2379
+        prefix: /apisix
+        timeout: 30
+' >conf/config.yaml
+
+out=$(make init 2>&1 || true)
+if ! echo "$out" | grep 'trying to initialize the data of etcd'; then
+    echo "failed: non data_plane should init the data of etcd"
+    exit 1
+fi
+echo "passed: non data_plane can init the data of etcd"
+
+# start apisix to test non data_plane can work with etcd
+make run
+sleep 3
+
+admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 
's/"//g')
+curl -o /dev/null -s -w %{http_code} -i 
http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X PUT 
-d '
+{
+    "upstream": {
+        "nodes": {
+            "127.0.0.1:1980": 1
+        },
+        "type": "roundrobin"
+    },
+    "uri": "/hello",
+    "plugins": {
+        "serverless-pre-function": {
+            "phase": "rewrite",
+            "functions": ["
+                return function(conf, ctx)
+                    local core = require(\"apisix.core\")
+                    return core.response.exit(200)
+                end
+            "]
+        }
+    }
+}'
+
+# check can access the route
+code=$(curl -o /dev/null -s -w %{http_code} http://127.0.0.1:9080/hello)
+if [ ! "$code" -eq 200 ]; then
+    echo "failed: non data_plane should be able to access the route"
+    exit 1
+fi
+echo "passed: non data_plane can work with etcd"
+
+# prepare for data_plane with etcd
+# stop apisix
+make stop
+sleep 3
+
+# data_plane can skip initializing the data of etcd
+echo '
+deployment:
+    role: data_plane
+    role_data_plane:
+        config_provider: etcd
+    etcd:
+        host:
+            - http://127.0.0.1:2379
+        prefix: /apisix
+        timeout: 30
+' >conf/config.yaml
+
+out=$(make init 2>&1 || true)
+if echo "$out" | grep 'trying to initialize the data of etcd'; then
+    echo "failed: data_plane should not init the data of etcd"
+    exit 1
+fi
+if ! echo "$out" | grep 'access from the data plane to etcd should be 
read-only, skip initializing the data of etcd'; then
+    echo "failed: data_plane should skip initializing the data of etcd"
+    exit 1
+fi
+echo "passed: data_plane can skip initializing the data of etcd"
+
+# start apisix to test data_plane can work with etcd
+make run
+sleep 3
+
+code=$(curl -o /dev/null -s -w %{http_code} http://127.0.0.1:9080/hello)
+if [ ! "$code" -eq 200 ]; then
+    echo "failed: data_plane should be able to access the route when using 
etcd"
+    exit 1
+fi
+echo "passed: data_plane can work with etcd"
+
+# prepare for data_plane with read-only etcd
+# stop apisix
+make stop
+sleep 3
+# add root user to help disable auth
+etcdctl user add "root:test"
+etcdctl role add root
+etcdctl user grant-role root root
+# add readonly user
+etcdctl user add "apisix-data-plane:test"
+etcdctl role add data-plane-role
+etcdctl role grant-permission --prefix=true data-plane-role read /apisix
+etcdctl user grant-role apisix-data-plane data-plane-role
+# enable auth
+etcdctl auth enable
+
+# data_plane can skip initializing the data when using read-only etcd
+echo '
+deployment:
+    role: data_plane
+    role_data_plane:
+        config_provider: etcd
+    etcd:
+        host:
+            - http://127.0.0.1:2379
+        user: apisix-data-plane
+        password: test
+        prefix: /apisix
+        timeout: 30
+' >conf/config.yaml
+
+out=$(make init 2>&1 || true)
+if echo "$out" | grep 'trying to initialize the data of etcd'; then
+    echo "failed: data_plane should not init the data of etcd (read-only)"
+    exit 1
+fi
+if ! echo "$out" | grep 'access from the data plane to etcd should be 
read-only, skip initializing the data of etcd'; then
+    echo "failed: data_plane should skip initializing the data of etcd 
(read-only)"
+    exit 1
+fi
+echo "passed: data_plane can skip initializing the data of etcd (read-only)"
+
+# start apisix to test data_plane can work with read-only etcd
+make run
+sleep 3
+
+code=$(curl -o /dev/null -s -w %{http_code} http://127.0.0.1:9080/hello)
+if [ ! "$code" -eq 200 ]; then
+    echo "failed: data_plane should be able to access the route when using 
read-only etcd"
+    exit 1
+fi
+echo "passed: data_plane can work with read-only etcd"
+
+# clean up
+etcdctl --user=root:test auth disable
+etcdctl user delete apisix-data-plane
+etcdctl role delete data-plane-role
+etcdctl user delete root
+etcdctl role delete root

Reply via email to