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 <jie-em...@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