You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ch...@apache.org on 2020/12/08 13:02:55 UTC

[apisix-dashboard] branch master updated: feat: add etcd basic auth support (#951)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 0383021  feat: add etcd basic auth support (#951)
0383021 is described below

commit 0383021a07e646a2a8406162fb298c637da000a8
Author: JTrancender <ji...@jie-trancender.org>
AuthorDate: Tue Dec 8 21:02:49 2020 +0800

    feat: add etcd basic auth support (#951)
    
    * add etcd basic auth support
---
 api/conf/conf.go                               | 22 +++++++++--
 api/conf/conf.yaml                             |  4 ++
 api/go.sum                                     |  1 +
 api/internal/core/storage/etcd.go              |  7 +++-
 api/internal/handler/consumer/consumer_test.go |  4 +-
 api/internal/handler/route/route_test.go       |  5 ++-
 api/internal/handler/service/service_test.go   |  3 +-
 api/internal/handler/ssl/ssl_test.go           |  3 +-
 api/internal/handler/upstream/upstream_test.go |  3 +-
 api/main.go                                    | 11 +++---
 api/test/shell/cli_test.sh                     | 51 ++++++++++++++++++++++++++
 11 files changed, 98 insertions(+), 16 deletions(-)

diff --git a/api/conf/conf.go b/api/conf/conf.go
index 91eb89b..578fcbd 100644
--- a/api/conf/conf.go
+++ b/api/conf/conf.go
@@ -45,7 +45,7 @@ var (
 	WorkDir          = "."
 	ServerHost       = "127.0.0.1"
 	ServerPort       = 80
-	ETCDEndpoints    = []string{"127.0.0.1:2379"}
+	ETCDConfig       *Etcd
 	ErrorLogLevel    = "warn"
 	ErrorLogPath     = "logs/error.log"
 	UserList         = make(map[string]User, 2)
@@ -55,6 +55,8 @@ var (
 
 type Etcd struct {
 	Endpoints []string
+	Username  string
+	Password  string
 }
 
 type Listen struct {
@@ -128,9 +130,9 @@ func setConf() {
 			ServerHost = config.Conf.Listen.Host
 		}
 
-		//etcd
+		// for etcd
 		if len(config.Conf.Etcd.Endpoints) > 0 {
-			ETCDEndpoints = config.Conf.Etcd.Endpoints
+			initEtcdConfig(config.Conf.Etcd)
 		}
 
 		//error log
@@ -180,3 +182,17 @@ func initSchema() {
 		Schema = gjson.ParseBytes(schemaContent)
 	}
 }
+
+// initialize etcd config
+func initEtcdConfig(conf Etcd) {
+	var endpoints = []string{"127.0.0.1:2379"}
+	if len(conf.Endpoints) > 0 {
+		endpoints = conf.Endpoints
+	}
+
+	ETCDConfig = &Etcd{
+		Endpoints: endpoints,
+		Username:  conf.Username,
+		Password:  conf.Password,
+	}
+}
diff --git a/api/conf/conf.yaml b/api/conf/conf.yaml
index e971761..7f147cb 100644
--- a/api/conf/conf.yaml
+++ b/api/conf/conf.yaml
@@ -22,6 +22,10 @@ conf:
   etcd:
     endpoints:          # supports defining multiple etcd host addresses for an etcd cluster
       - 127.0.0.1:2379
+    
+                        # etcd basic auth info
+    # username: "root"    # ignore etcd username if not enable etcd auth
+    # password: "123456"  # ignore etcd password if not enable etcd auth
   log:
     error_log:
       level: warn       # supports levels, lower to higher: debug, info, warn, error, panic, fatal
diff --git a/api/go.sum b/api/go.sum
index d245362..80c6f95 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -118,6 +118,7 @@ github.com/shiningrush/droplet v0.2.1 h1:p2utttTbCfgiL+x0Zrb2jFeWspB7/o+v3e+R94G
 github.com/shiningrush/droplet v0.2.1/go.mod h1:akW2vIeamvMD6zj6wIBfzYn6StGXBxwlW3gA+hcHu5M=
 github.com/shiningrush/droplet v0.2.2 h1:jEqSGoJXlybt1yQdauu+waE+l7KYlguNs8VayMfQ96Q=
 github.com/shiningrush/droplet v0.2.2/go.mod h1:akW2vIeamvMD6zj6wIBfzYn6StGXBxwlW3gA+hcHu5M=
+github.com/shiningrush/droplet v0.2.3 h1:bzPDzkE0F54r94XsultGS8uAPeL3pZIRmjqM0zIlpeI=
 github.com/shiningrush/droplet v0.2.3/go.mod h1:akW2vIeamvMD6zj6wIBfzYn6StGXBxwlW3gA+hcHu5M=
 github.com/shiningrush/droplet/wrapper/gin v0.2.0 h1:LHkU+TbSkpePgXrTg3hJoSZlCMS03GeWMl0t+oLkd44=
 github.com/shiningrush/droplet/wrapper/gin v0.2.0/go.mod h1:ZJu+sCRrVXn5Pg618c1KK3Ob2UiXGuPM1ROx5uMM9YQ=
diff --git a/api/internal/core/storage/etcd.go b/api/internal/core/storage/etcd.go
index 5a9c23e..99db3d2 100644
--- a/api/internal/core/storage/etcd.go
+++ b/api/internal/core/storage/etcd.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"time"
 
+	"github.com/apisix/manager-api/conf"
 	"github.com/apisix/manager-api/internal/utils"
 	"go.etcd.io/etcd/clientv3"
 )
@@ -32,10 +33,12 @@ var (
 type EtcdV3Storage struct {
 }
 
-func InitETCDClient(endpoints []string) error {
+func InitETCDClient(etcdConf *conf.Etcd) error {
 	cli, err := clientv3.New(clientv3.Config{
-		Endpoints:   endpoints,
+		Endpoints:   etcdConf.Endpoints,
 		DialTimeout: 5 * time.Second,
+		Username:    etcdConf.Username,
+		Password:    etcdConf.Password,
 	})
 	if err != nil {
 		return fmt.Errorf("init etcd failed: %w", err)
diff --git a/api/internal/handler/consumer/consumer_test.go b/api/internal/handler/consumer/consumer_test.go
index 1f88c52..ba02f28 100644
--- a/api/internal/handler/consumer/consumer_test.go
+++ b/api/internal/handler/consumer/consumer_test.go
@@ -19,12 +19,14 @@ package consumer
 
 import (
 	"encoding/json"
+
 	"testing"
 	"time"
 
 	"github.com/shiningrush/droplet"
 	"github.com/stretchr/testify/assert"
 
+	"github.com/apisix/manager-api/conf"
 	"github.com/apisix/manager-api/internal/core/entity"
 	"github.com/apisix/manager-api/internal/core/storage"
 	"github.com/apisix/manager-api/internal/core/store"
@@ -32,7 +34,7 @@ import (
 
 func TestConsumer(t *testing.T) {
 	// init
-	err := storage.InitETCDClient([]string{"127.0.0.1:2379"})
+	err := storage.InitETCDClient(conf.ETCDConfig)
 	assert.Nil(t, err)
 	err = store.InitStores()
 	assert.Nil(t, err)
diff --git a/api/internal/handler/route/route_test.go b/api/internal/handler/route/route_test.go
index 00a86a3..bb906f4 100644
--- a/api/internal/handler/route/route_test.go
+++ b/api/internal/handler/route/route_test.go
@@ -27,6 +27,7 @@ import (
 	"github.com/shiningrush/droplet/data"
 	"github.com/stretchr/testify/assert"
 
+	"github.com/apisix/manager-api/conf"
 	"github.com/apisix/manager-api/internal/core/entity"
 	"github.com/apisix/manager-api/internal/core/storage"
 	"github.com/apisix/manager-api/internal/core/store"
@@ -34,7 +35,7 @@ import (
 
 func TestRoute(t *testing.T) {
 	// init
-	err := storage.InitETCDClient([]string{"127.0.0.1:2379"})
+	err := storage.InitETCDClient(conf.ETCDConfig)
 	assert.Nil(t, err)
 	err = store.InitStores()
 	assert.Nil(t, err)
@@ -989,7 +990,7 @@ func TestRoute(t *testing.T) {
 
 func Test_Route_With_Script(t *testing.T) {
 	// init
-	err := storage.InitETCDClient([]string{"127.0.0.1:2379"})
+	err := storage.InitETCDClient(conf.ETCDConfig)
 	assert.Nil(t, err)
 	err = store.InitStores()
 	assert.Nil(t, err)
diff --git a/api/internal/handler/service/service_test.go b/api/internal/handler/service/service_test.go
index 6f801c4..81a56fe 100644
--- a/api/internal/handler/service/service_test.go
+++ b/api/internal/handler/service/service_test.go
@@ -25,6 +25,7 @@ import (
 	"github.com/shiningrush/droplet"
 	"github.com/stretchr/testify/assert"
 
+	"github.com/apisix/manager-api/conf"
 	"github.com/apisix/manager-api/internal/core/entity"
 	"github.com/apisix/manager-api/internal/core/storage"
 	"github.com/apisix/manager-api/internal/core/store"
@@ -32,7 +33,7 @@ import (
 
 func TestService(t *testing.T) {
 	// init
-	err := storage.InitETCDClient([]string{"127.0.0.1:2379"})
+	err := storage.InitETCDClient(conf.ETCDConfig)
 	assert.Nil(t, err)
 	err = store.InitStores()
 	assert.Nil(t, err)
diff --git a/api/internal/handler/ssl/ssl_test.go b/api/internal/handler/ssl/ssl_test.go
index 47ea9c2..4a52032 100644
--- a/api/internal/handler/ssl/ssl_test.go
+++ b/api/internal/handler/ssl/ssl_test.go
@@ -25,6 +25,7 @@ import (
 	"github.com/shiningrush/droplet"
 	"github.com/stretchr/testify/assert"
 
+	"github.com/apisix/manager-api/conf"
 	"github.com/apisix/manager-api/internal/core/entity"
 	"github.com/apisix/manager-api/internal/core/storage"
 	"github.com/apisix/manager-api/internal/core/store"
@@ -32,7 +33,7 @@ import (
 
 func TestSSL(t *testing.T) {
 	// init
-	err := storage.InitETCDClient([]string{"127.0.0.1:2379"})
+	err := storage.InitETCDClient(conf.ETCDConfig)
 	assert.Nil(t, err)
 	err = store.InitStores()
 	assert.Nil(t, err)
diff --git a/api/internal/handler/upstream/upstream_test.go b/api/internal/handler/upstream/upstream_test.go
index c11089c..03f4fe0 100644
--- a/api/internal/handler/upstream/upstream_test.go
+++ b/api/internal/handler/upstream/upstream_test.go
@@ -25,6 +25,7 @@ import (
 	"github.com/shiningrush/droplet"
 	"github.com/stretchr/testify/assert"
 
+	"github.com/apisix/manager-api/conf"
 	"github.com/apisix/manager-api/internal/core/entity"
 	"github.com/apisix/manager-api/internal/core/storage"
 	"github.com/apisix/manager-api/internal/core/store"
@@ -34,7 +35,7 @@ var upstreamHandler *Handler
 
 func TestUpstream(t *testing.T) {
 	// init
-	err := storage.InitETCDClient([]string{"127.0.0.1:2379"})
+	err := storage.InitETCDClient(conf.ETCDConfig)
 	assert.Nil(t, err)
 	err = store.InitStores()
 	assert.Nil(t, err)
diff --git a/api/main.go b/api/main.go
index ce05fdd..38ee8bd 100644
--- a/api/main.go
+++ b/api/main.go
@@ -19,14 +19,15 @@ package main
 import (
 	"context"
 	"fmt"
-	"github.com/apisix/manager-api/internal/handler"
-	"github.com/shiningrush/droplet"
 	"net/http"
 	"os"
 	"os/signal"
 	"syscall"
 	"time"
 
+	"github.com/apisix/manager-api/internal/handler"
+	"github.com/shiningrush/droplet"
+
 	"github.com/apisix/manager-api/conf"
 	"github.com/apisix/manager-api/internal"
 	"github.com/apisix/manager-api/internal/core/storage"
@@ -44,12 +45,12 @@ func main() {
 		newMws = append(newMws, mws[1:]...)
 		return newMws
 	}
-	if err := storage.InitETCDClient(conf.ETCDEndpoints); err != nil {
-		log.Error("init etcd client fail: %w", err)
+	if err := storage.InitETCDClient(conf.ETCDConfig); err != nil {
+		log.Errorf("init etcd client fail: %w", err)
 		panic(err)
 	}
 	if err := store.InitStores(); err != nil {
-		log.Error("init stores fail: %w", err)
+		log.Errorf("init stores fail: %w", err)
 		panic(err)
 	}
 	// routes
diff --git a/api/test/shell/cli_test.sh b/api/test/shell/cli_test.sh
index 8f142b1..af3744b 100755
--- a/api/test/shell/cli_test.sh
+++ b/api/test/shell/cli_test.sh
@@ -93,3 +93,54 @@ if [[ `grep -c "INFO" ./error.log` -eq '0' ]]; then
     echo "failed: failed to write log on right level"
     exit 1
 fi
+
+
+# etcd basic auth
+# add root user
+curl -L http://localhost:2379/v3/auth/user/add -d '{"name": "root", "password": "root"}'
+
+# add root role
+curl -L http://localhost:2379/v3/auth/role/add -d '{"name": "root"}'
+
+# grant root role to root user
+curl -L http://localhost:2379/v3/auth/user/grant -d '{"user": "root", "role": "root"}'
+
+# enable auth
+curl -L http://localhost:2379/v3/auth/enable -d '{}'
+
+./manager-api &
+sleep 3
+
+# make sure it's wrong
+if [[ `grep -c "etcdserver: user name is empty" ./error.log` -eq '0' ]]; then
+    echo "failed: failed to validate etcd basic auth"
+    exit 1
+fi
+
+# modify etcd auth config
+sed -i '1,$s/# username: "root"    # ignore etcd username if not enable etcd auth/username: "root"/g' conf/conf.yaml
+sed -i '1,$s/# password: "123456"  # ignore etcd password if not enable etcd auth/password: "root"/g' conf/conf.yaml
+
+./manager-api &
+sleep 3
+
+# validate process is right by requesting login api
+resp=$(curl http://127.0.0.1:9000/apisix/admin/user/login -d '{"username":"admin", "password": "admin"}')
+token=$(echo "${resp}" | sed 's/{/\n/g' | sed 's/,/\n/g' | grep "token" | sed 's/:/\n/g' | sed '1d' | sed 's/}//g'  | sed 's/"//g')
+if [ -z "${token}" ]; then
+    echo "login failed"
+    exit 1
+fi
+
+# more validation to make sure it's ok to access etcd
+resp=$(curl -ig http://127.0.0.1:9000/apisix/admin/consumers -i -H "Authorization: $token" -d '{"username":"etcd_basic_auth_test"}')
+respCode=$(echo "${resp}" | sed 's/{/\n/g'| sed 's/,/\n/g' | grep "code" | sed 's/:/\n/g' | sed '1d')
+respMessage=$(echo "${resp}" | sed 's/{/\n/g'| sed 's/,/\n/g' | grep "message" | sed 's/:/\n/g' | sed '1d')
+if [ "$respCode" != "0" ] || [ $respMessage != "\"\"" ]; then
+    echo "verify access etcd failed"
+    exit 1
+fi
+
+pkill -f manager-api
+
+check_logfile