Skip to content

Commit

Permalink
support authentication for zookeeper/etcd (#1330)
Browse files Browse the repository at this point in the history
* add authentication for zookeeper

* add authentication for etcd (NOT TESTED)

* fix docopt arg parse

* fmt
  • Loading branch information
fancy-rabbit authored and spinlock committed Sep 17, 2017
1 parent fe6ff94 commit 3adf407
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 27 deletions.
9 changes: 8 additions & 1 deletion cmd/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,23 @@ func (t *cmdAdmin) newTopomClient(d map[string]interface{}) models.Client {
var coordinator struct {
name string
addr string
auth string
}

switch {
case d["--zookeeper"] != nil:
coordinator.name = "zookeeper"
coordinator.addr = utils.ArgumentMust(d, "--zookeeper")
if d["--zookeeper-auth"] != nil {
coordinator.auth = utils.ArgumentMust(d, "--zookeeper-auth")
}

case d["--etcd"] != nil:
coordinator.name = "etcd"
coordinator.addr = utils.ArgumentMust(d, "--etcd")
if d["--etcd-auth"] != nil {
coordinator.auth = utils.ArgumentMust(d, "--etcd-auth")
}

case d["--filesystem"] != nil:
coordinator.name = "filesystem"
Expand All @@ -59,7 +66,7 @@ func (t *cmdAdmin) newTopomClient(d map[string]interface{}) models.Client {
log.Panicf("invalid coordinator")
}

c, err := models.NewClient(coordinator.name, coordinator.addr, time.Minute)
c, err := models.NewClient(coordinator.name, coordinator.addr, coordinator.auth, time.Minute)
if err != nil {
log.PanicErrorf(err, "create '%s' client to '%s' failed", coordinator.name, coordinator.addr)
}
Expand Down
8 changes: 4 additions & 4 deletions cmd/admin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ Usage:
codis-admin [-v] --dashboard=ADDR --sentinel-add --addr=ADDR
codis-admin [-v] --dashboard=ADDR --sentinel-del --addr=ADDR [--force]
codis-admin [-v] --dashboard=ADDR --sentinel-resync
codis-admin [-v] --remove-lock --product=NAME (--zookeeper=ADDR|--etcd=ADDR|--filesystem=ROOT)
codis-admin [-v] --config-dump --product=NAME (--zookeeper=ADDR|--etcd=ADDR|--filesystem=ROOT) [-1]
codis-admin [-v] --remove-lock --product=NAME (--zookeeper=ADDR [--zookeeper-auth=USR:PWD]|--etcd=ADDR [--etcd-auth=USR:PWD]|--filesystem=ROOT)
codis-admin [-v] --config-dump --product=NAME (--zookeeper=ADDR [--zookeeper-auth=USR:PWD]|--etcd=ADDR [--etcd-auth=USR:PWD]|--filesystem=ROOT) [-1]
codis-admin [-v] --config-convert=FILE
codis-admin [-v] --config-restore=FILE --product=NAME (--zookeeper=ADDR|--etcd=ADDR|--filesystem=ROOT) [--confirm]
codis-admin [-v] --dashboard-list (--zookeeper=ADDR|--etcd=ADDR|--filesystem=ROOT)
codis-admin [-v] --config-restore=FILE --product=NAME (--zookeeper=ADDR [--zookeeper-auth=USR:PWD]|--etcd=ADDR [--etcd-auth=USR:PWD]|--filesystem=ROOT) [--confirm]
codis-admin [-v] --dashboard-list (--zookeeper=ADDR [--zookeeper-auth=USR:PWD]|--etcd=ADDR [--etcd-auth=USR:PWD]|--filesystem=ROOT)
Options:
-a AUTH, --auth=AUTH
Expand Down
2 changes: 1 addition & 1 deletion cmd/dashboard/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Options:
log.Warnf("option --product_auth = %s", s)
}

client, err := models.NewClient(config.CoordinatorName, config.CoordinatorAddr, time.Minute)
client, err := models.NewClient(config.CoordinatorName, config.CoordinatorAddr, config.CoordinatorAuth, time.Minute)
if err != nil {
log.PanicErrorf(err, "create '%s' client to '%s' failed", config.CoordinatorName, config.CoordinatorAddr)
}
Expand Down
11 changes: 9 additions & 2 deletions cmd/fe/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func init() {
func main() {
const usage = `
Usage:
codis-fe [--ncpu=N] [--log=FILE] [--log-level=LEVEL] [--assets-dir=PATH] [--pidfile=FILE] (--dashboard-list=FILE|--zookeeper=ADDR|--etcd=ADDR|--filesystem=ROOT) --listen=ADDR
codis-fe [--ncpu=N] [--log=FILE] [--log-level=LEVEL] [--assets-dir=PATH] [--pidfile=FILE] (--dashboard-list=FILE|--zookeeper=ADDR [--zookeeper-auth=USR:PWD]|--etcd=ADDR [--etcd-auth=USR:PWD]|--filesystem=ROOT) --listen=ADDR
codis-fe --version
Options:
Expand Down Expand Up @@ -133,16 +133,23 @@ Options:
var coordinator struct {
name string
addr string
auth string
}

switch {
case d["--zookeeper"] != nil:
coordinator.name = "zookeeper"
coordinator.addr = utils.ArgumentMust(d, "--zookeeper")
if d["--zookeeper-auth"] != nil {
coordinator.auth = utils.ArgumentMust(d, "--zookeeper-auth")
}

case d["--etcd"] != nil:
coordinator.name = "etcd"
coordinator.addr = utils.ArgumentMust(d, "--etcd")
if d["--etcd-auth"] != nil {
coordinator.auth = utils.ArgumentMust(d, "--etcd-auth")
}

case d["--filesystem"] != nil:
coordinator.name = "filesystem"
Expand All @@ -154,7 +161,7 @@ Options:

log.Warnf("set --%s = %s", coordinator.name, coordinator.addr)

c, err := models.NewClient(coordinator.name, coordinator.addr, time.Minute)
c, err := models.NewClient(coordinator.name, coordinator.addr, coordinator.auth, time.Minute)
if err != nil {
log.PanicErrorf(err, "create '%s' client to '%s' failed", coordinator.name, coordinator.addr)
}
Expand Down
15 changes: 11 additions & 4 deletions cmd/proxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
func main() {
const usage = `
Usage:
codis-proxy [--ncpu=N [--max-ncpu=MAX]] [--config=CONF] [--log=FILE] [--log-level=LEVEL] [--host-admin=ADDR] [--host-proxy=ADDR] [--dashboard=ADDR|--zookeeper=ADDR|--etcd=ADDR|--filesystem=ROOT|--fillslots=FILE] [--ulimit=NLIMIT] [--pidfile=FILE] [--product_name=NAME] [--product_auth=AUTH] [--session_auth=AUTH]
codis-proxy [--ncpu=N [--max-ncpu=MAX]] [--config=CONF] [--log=FILE] [--log-level=LEVEL] [--host-admin=ADDR] [--host-proxy=ADDR] [--dashboard=ADDR|--zookeeper=ADDR [--zookeeper-auth=USR:PWD]|--etcd=ADDR [--etcd-auth=USR:PWD]|--filesystem=ROOT|--fillslots=FILE] [--ulimit=NLIMIT] [--pidfile=FILE] [--product_name=NAME] [--product_auth=AUTH] [--session_auth=AUTH]
codis-proxy --default-config
codis-proxy --version
Expand Down Expand Up @@ -131,17 +131,24 @@ Options:
var coordinator struct {
name string
addr string
auth string
}

switch {

case d["--zookeeper"] != nil:
coordinator.name = "zookeeper"
coordinator.addr = utils.ArgumentMust(d, "--zookeeper")
if d["--zookeeper-auth"] != nil {
coordinator.auth = utils.ArgumentMust(d, "--zookeeper-auth")
}

case d["--etcd"] != nil:
coordinator.name = "etcd"
coordinator.addr = utils.ArgumentMust(d, "--etcd")
if d["--etcd-auth"] != nil {
coordinator.auth = utils.ArgumentMust(d, "--etcd-auth")
}

case d["--filesystem"] != nil:
coordinator.name = "filesystem"
Expand Down Expand Up @@ -213,7 +220,7 @@ Options:
case dashboard != "":
go AutoOnlineWithDashboard(s, dashboard)
case coordinator.name != "":
go AutoOnlineWithCoordinator(s, coordinator.name, coordinator.addr)
go AutoOnlineWithCoordinator(s, coordinator.name, coordinator.addr, coordinator.auth)
case slots != nil:
go AutoOnlineWithFillSlots(s, slots)
}
Expand Down Expand Up @@ -287,8 +294,8 @@ func AutoOnlineWithDashboard(p *proxy.Proxy, dashboard string) {
log.Panicf("online proxy failed")
}

func AutoOnlineWithCoordinator(p *proxy.Proxy, name, addr string) {
client, err := models.NewClient(name, addr, time.Minute)
func AutoOnlineWithCoordinator(p *proxy.Proxy, name, addr string, auth string) {
client, err := models.NewClient(name, addr, auth, time.Minute)
if err != nil {
log.PanicErrorf(err, "create '%s' client to '%s' failed", name, addr)
}
Expand Down
2 changes: 2 additions & 0 deletions config/dashboard.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
##################################################

# Set Coordinator, only accept "zookeeper" & "etcd" & "filesystem".
# for zookeeper/etcd, coorinator_auth accept "user:password"
# Quick Start
coordinator_name = "filesystem"
coordinator_addr = "/tmp/codis"
#coordinator_name = "zookeeper"
#coordinator_addr = "127.0.0.1:2181"
#coordinator_auth = ""

# Set Codis Product Name/Auth.
product_name = "codis-demo"
Expand Down
4 changes: 3 additions & 1 deletion config/proxy.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ proxy_addr = "0.0.0.0:19000"
# Set jodis address & session timeout
# 1. jodis_name is short for jodis_coordinator_name, only accept "zookeeper" & "etcd".
# 2. jodis_addr is short for jodis_coordinator_addr
# 3. proxy will be registered as node:
# 3. jodis_auth is short for jodis_coordinator_auth, for zookeeper/etcd, "user:password" is accepted.
# 4. proxy will be registered as node:
# if jodis_compatible = true (not suggested):
# /zk/codis/db_{PRODUCT_NAME}/proxy-{HASHID} (compatible with Codis2.0)
# or else
# /jodis/{PRODUCT_NAME}/proxy-{HASHID}
jodis_name = ""
jodis_addr = ""
jodis_auth = ""
jodis_timeout = "20s"
jodis_compatible = false

Expand Down
6 changes: 3 additions & 3 deletions pkg/models/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ type Client interface {
CreateEphemeralInOrder(path string, data []byte) (<-chan struct{}, string, error)
}

func NewClient(coordinator string, addrlist string, timeout time.Duration) (Client, error) {
func NewClient(coordinator string, addrlist string, auth string, timeout time.Duration) (Client, error) {
switch coordinator {
case "zk", "zookeeper":
return zkclient.New(addrlist, timeout)
return zkclient.New(addrlist, auth, timeout)
case "etcd":
return etcdclient.New(addrlist, timeout)
return etcdclient.New(addrlist, auth, timeout)
case "fs", "filesystem":
return fsclient.New(addrlist)
}
Expand Down
14 changes: 11 additions & 3 deletions pkg/models/etcd/etcdclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type Client struct {
context context.Context
}

func New(addrlist string, timeout time.Duration) (*Client, error) {
func New(addrlist string, auth string, timeout time.Duration) (*Client, error) {
endpoints := strings.Split(addrlist, ",")
for i, s := range endpoints {
if s != "" && !strings.HasPrefix(s, "http://") {
Expand All @@ -45,10 +45,18 @@ func New(addrlist string, timeout time.Duration) (*Client, error) {
timeout = time.Second * 5
}

c, err := client.New(client.Config{
config := client.Config{
Endpoints: endpoints, Transport: client.DefaultTransport,
HeaderTimeoutPerRequest: time.Second * 5,
})
}

if auth != "" {
a := strings.Split(auth, ":")
config.Username = a[0]
config.Password = a[1]
}

c, err := client.New(config)
if err != nil {
return nil, errors.Trace(err)
}
Expand Down
36 changes: 30 additions & 6 deletions pkg/models/zk/zkclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Client struct {
conn *zk.Conn

addrlist string
auth string
timeout time.Duration

logger *zkLogger
Expand All @@ -45,16 +46,16 @@ func (l *zkLogger) Printf(format string, v ...interface{}) {
}
}

func New(addrlist string, timeout time.Duration) (*Client, error) {
return NewWithLogfunc(addrlist, timeout, DefaultLogfunc)
func New(addrlist string, auth string, timeout time.Duration) (*Client, error) {
return NewWithLogfunc(addrlist, auth, timeout, DefaultLogfunc)
}

func NewWithLogfunc(addrlist string, timeout time.Duration, logfunc func(foramt string, v ...interface{})) (*Client, error) {
func NewWithLogfunc(addrlist string, auth string, timeout time.Duration, logfunc func(foramt string, v ...interface{})) (*Client, error) {
if timeout <= 0 {
timeout = time.Second * 5
}
c := &Client{
addrlist: addrlist, timeout: timeout,
addrlist: addrlist, auth: auth, timeout: timeout,
logger: &zkLogger{logfunc},
}
if err := c.reset(); err != nil {
Expand All @@ -77,6 +78,12 @@ func (c *Client) reset() error {

c.logger.Printf("zkclient setup new connection to %s", c.addrlist)

if c.auth != "" {
if err := c.conn.AddAuth("digest", []byte(c.auth)); err != nil {
return errors.Trace(err)
}
}

go func() {
for e := range events {
log.Debugf("zookeeper event: %+v", e)
Expand Down Expand Up @@ -155,7 +162,15 @@ func (c *Client) mkdir(conn *zk.Conn, path string) error {
if err := c.mkdir(conn, filepath.Dir(path)); err != nil {
return err
}
_, err := conn.Create(path, []byte{}, 0, zk.WorldACL(zk.PermAll))
var acl []zk.ACL

if c.auth != "" {
auth := strings.Split(c.auth, ":")
acl = zk.DigestACL(zk.PermAll, auth[0], auth[1])
} else {
acl = zk.WorldACL(zk.PermAll)
}
_, err := conn.Create(path, []byte{}, 0, acl)
if err != nil && errors.NotEqual(err, zk.ErrNodeExists) {
return errors.Trace(err)
}
Expand Down Expand Up @@ -213,7 +228,16 @@ func (c *Client) create(conn *zk.Conn, path string, data []byte, flag int32) (st
if err := c.mkdir(conn, filepath.Dir(path)); err != nil {
return "", err
}
p, err := conn.Create(path, data, flag, zk.WorldACL(zk.PermAdmin|zk.PermRead|zk.PermWrite))

var acl []zk.ACL

if c.auth != "" {
auth := strings.Split(c.auth, ":")
acl = zk.DigestACL(zk.PermAdmin|zk.PermRead|zk.PermWrite, auth[0], auth[1])
} else {
acl = zk.WorldACL(zk.PermAdmin|zk.PermRead|zk.PermWrite)
}
p, err := conn.Create(path, data, flag, acl)
if err != nil {
return "", errors.Trace(err)
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/proxy/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ proxy_addr = "0.0.0.0:19000"
# Set jodis address & session timeout
# 1. jodis_name is short for jodis_coordinator_name, only accept "zookeeper" & "etcd".
# 2. jodis_addr is short for jodis_coordinator_addr
# 3. proxy will be registered as node:
# 3. jodis_auth is short for jodis_coordinator_auth, for zookeeper/etcd, "user:password" is accepted.
# 4. proxy will be registered as node:
# if jodis_compatible = true (not suggested):
# /zk/codis/db_{PRODUCT_NAME}/proxy-{HASHID} (compatible with Codis2.0)
# or else
# /jodis/{PRODUCT_NAME}/proxy-{HASHID}
jodis_name = ""
jodis_addr = ""
jodis_auth = ""
jodis_timeout = "20s"
jodis_compatible = false
Expand Down Expand Up @@ -137,6 +139,7 @@ type Config struct {

JodisName string `toml:"jodis_name" json:"jodis_name"`
JodisAddr string `toml:"jodis_addr" json:"jodis_addr"`
JodisAuth string `toml:"jodis_auth" json:"jodis_auth"`
JodisTimeout timesize.Duration `toml:"jodis_timeout" json:"jodis_timeout"`
JodisCompatible bool `toml:"jodis_compatible" json:"jodis_compatible"`

Expand Down
2 changes: 1 addition & 1 deletion pkg/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (s *Proxy) setup(config *Config) error {
)

if config.JodisAddr != "" {
c, err := models.NewClient(config.JodisName, config.JodisAddr, config.JodisTimeout.Duration())
c, err := models.NewClient(config.JodisName, config.JodisAddr, config.JodisAuth, config.JodisTimeout.Duration())
if err != nil {
return err
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/topom/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ const DefaultConfig = `
##################################################
# Set Coordinator, only accept "zookeeper" & "etcd" & "filesystem".
# for zookeeper/etcd, coorinator_auth accept "user:password"
# Quick Start
coordinator_name = "filesystem"
coordinator_addr = "/tmp/codis"
#coordinator_name = "zookeeper"
#coordinator_addr = "127.0.0.1:2181"
#coordinator_auth = ""
# Set Codis Product Name/Auth.
product_name = "codis-demo"
Expand Down Expand Up @@ -57,6 +59,7 @@ sentinel_client_reconfig_script = ""
type Config struct {
CoordinatorName string `toml:"coordinator_name" json:"coordinator_name"`
CoordinatorAddr string `toml:"coordinator_addr" json:"coordinator_addr"`
CoordinatorAuth string `toml:"coordinator_auth" json:"coordinator_auth"`

AdminAddr string `toml:"admin_addr" json:"admin_addr"`

Expand Down

0 comments on commit 3adf407

Please sign in to comment.