From fe7b92e6d0626b799465646c3c195197893e4d40 Mon Sep 17 00:00:00 2001 From: xhe Date: Tue, 26 Jul 2022 14:31:54 +0800 Subject: [PATCH] manager: new namespace manager based on etcd (#13) --- cmd/weirproxy/main.go | 2 +- conf/namespace/test_namespace.yaml | 6 + pkg/config/namespace.go | 2 + pkg/config/namespace_test.go | 13 +- pkg/config/proxy.go | 27 +-- pkg/config/proxy_test.go | 21 +-- pkg/manager/config/manager.go | 2 - pkg/manager/namespace/builder.go | 62 ------- pkg/manager/namespace/domain.go | 26 --- pkg/manager/namespace/errcode.go | 4 +- pkg/manager/namespace/frontend.go | 49 ------ pkg/manager/namespace/manager.go | 218 ++++++++++++------------- pkg/manager/namespace/namespace.go | 98 ++--------- pkg/manager/namespace/user.go | 61 ------- pkg/manager/router/backend_observer.go | 3 +- pkg/proxy/driver/domain.go | 4 +- pkg/proxy/driver/queryctx.go | 6 +- pkg/proxy/sqlserver/sql_server.go | 6 +- pkg/server/api/debug.go | 12 +- pkg/server/api/namespace.go | 42 +++-- pkg/server/server.go | 2 +- pkg/util/datastructure/dsutil.go | 24 --- pkg/util/datastructure/dsutil_test.go | 40 ----- pkg/util/security/tls.go | 52 +----- 24 files changed, 213 insertions(+), 569 deletions(-) delete mode 100644 pkg/manager/namespace/builder.go delete mode 100644 pkg/manager/namespace/domain.go delete mode 100644 pkg/manager/namespace/frontend.go delete mode 100644 pkg/manager/namespace/user.go delete mode 100644 pkg/util/datastructure/dsutil.go delete mode 100644 pkg/util/datastructure/dsutil_test.go diff --git a/cmd/weirproxy/main.go b/cmd/weirproxy/main.go index e1409fa7..f04ace90 100644 --- a/cmd/weirproxy/main.go +++ b/cmd/weirproxy/main.go @@ -43,7 +43,7 @@ func main() { return err } - cfg, err := config.NewProxyConfig(proxyConfigData) + cfg, err := config.NewConfig(proxyConfigData) if err != nil { return err } diff --git a/conf/namespace/test_namespace.yaml b/conf/namespace/test_namespace.yaml index 34ab3772..7982316a 100644 --- a/conf/namespace/test_namespace.yaml +++ b/conf/namespace/test_namespace.yaml @@ -1,6 +1,12 @@ namespace: "test_namespace" frontend: + security: + cert: "./ttt" + key: "./ttt" backend: instances: - "127.0.0.1:4000" selector_type: "random" + security: + cert: "./ttt" + key: "./ttt" diff --git a/pkg/config/namespace.go b/pkg/config/namespace.go index d556e2fe..d2a83738 100644 --- a/pkg/config/namespace.go +++ b/pkg/config/namespace.go @@ -28,11 +28,13 @@ type Namespace struct { } type FrontendNamespace struct { + Security TLSCert `yaml:"security"` } type BackendNamespace struct { Instances []string `yaml:"instances"` SelectorType string `yaml:"selector_type"` + Security TLSCert `yaml:"security"` } func NewNamespaceConfig(data []byte) (*Namespace, error) { diff --git a/pkg/config/namespace_test.go b/pkg/config/namespace_test.go index 3686d740..fb148299 100644 --- a/pkg/config/namespace_test.go +++ b/pkg/config/namespace_test.go @@ -8,10 +8,21 @@ import ( var testNamespaceConfig = Namespace{ Namespace: "test_ns", - Frontend: FrontendNamespace{}, + Frontend: FrontendNamespace{ + Security: TLSCert{ + CA: "t", + Cert: "t", + Key: "t", + }, + }, Backend: BackendNamespace{ Instances: []string{"127.0.0.1:4000", "127.0.0.1:4001"}, SelectorType: "random", + Security: TLSCert{ + CA: "t", + Cert: "t", + Key: "t", + }, }, } diff --git a/pkg/config/proxy.go b/pkg/config/proxy.go index 5b45f918..4714e10b 100644 --- a/pkg/config/proxy.go +++ b/pkg/config/proxy.go @@ -76,19 +76,26 @@ type LogFile struct { MaxBackups int `yaml:"max_backups"` } +type TLSCert struct { + CA string `toml:"ca" json:"ca"` + Cert string `toml:"cert" json:"cert"` + Key string `toml:"key" json:"key"` +} + +func (c TLSCert) HasCert() bool { + return !(c.Cert == "" && c.Key == "") +} + +func (c TLSCert) HasCA() bool { + return c.CA != "" +} + type Security struct { - SSLCA string `toml:"ssl-ca" json:"ssl-ca"` - SSLCert string `toml:"ssl-cert" json:"ssl-cert"` - SSLKey string `toml:"ssl-key" json:"ssl-key"` - ClusterSSLCA string `toml:"cluster-ssl-ca" json:"cluster-ssl-ca"` - ClusterSSLCert string `toml:"cluster-ssl-cert" json:"cluster-ssl-cert"` - ClusterSSLKey string `toml:"cluster-ssl-key" json:"cluster-ssl-key"` - ClusterVerifyCN []string `toml:"cluster-verify-cn" json:"cluster-verify-cn"` - MinTLSVersion string `toml:"tls-version" json:"tls-version"` - RSAKeySize int `toml:"rsa-key-size" json:"rsa-key-size"` + Server TLSCert `toml:"server" json:"server"` + Cluster TLSCert `toml:"cluster" json:"cluster"` } -func NewProxyConfig(data []byte) (*Config, error) { +func NewConfig(data []byte) (*Config, error) { var cfg Config if err := yaml.Unmarshal(data, &cfg); err != nil { return nil, err diff --git a/pkg/config/proxy_test.go b/pkg/config/proxy_test.go index 949550c6..ff649ac3 100644 --- a/pkg/config/proxy_test.go +++ b/pkg/config/proxy_test.go @@ -41,22 +41,23 @@ var testProxyConfig = Config{ }, }, Security: Security{ - SSLCA: "a", - SSLCert: "b", - SSLKey: "c", - ClusterSSLCA: "d", - ClusterSSLCert: "e", - ClusterSSLKey: "f", - ClusterVerifyCN: []string{}, - MinTLSVersion: "g", - RSAKeySize: 0, + Server: TLSCert{ + CA: "a", + Cert: "b", + Key: "c", + }, + Cluster: TLSCert{ + CA: "a", + Cert: "b", + Key: "c", + }, }, } func TestProxyConfig(t *testing.T) { data, err := testProxyConfig.ToBytes() require.NoError(t, err) - cfg, err := NewProxyConfig(data) + cfg, err := NewConfig(data) require.NoError(t, err) require.Equal(t, testProxyConfig, *cfg) } diff --git a/pkg/manager/config/manager.go b/pkg/manager/config/manager.go index b02cfb44..42c31a3c 100644 --- a/pkg/manager/config/manager.go +++ b/pkg/manager/config/manager.go @@ -40,8 +40,6 @@ type ConfigManager struct { kv clientv3.KV basePath string cfg config.ConfigManager - - // TODO: remove namespace manager based on files } func NewConfigManager() *ConfigManager { diff --git a/pkg/manager/namespace/builder.go b/pkg/manager/namespace/builder.go deleted file mode 100644 index 5124cb4f..00000000 --- a/pkg/manager/namespace/builder.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2020 Ipalfish, Inc. -// Copyright 2022 PingCAP, Inc. -// -// Licensed 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 namespace - -import ( - "github.com/pingcap/TiProxy/pkg/config" - "github.com/pingcap/TiProxy/pkg/manager/router" - "github.com/pingcap/TiProxy/pkg/proxy/driver" - "github.com/pingcap/errors" - clientv3 "go.etcd.io/etcd/client/v3" -) - -type NamespaceImpl struct { - name string - router driver.Router -} - -func BuildNamespace(cfg *config.Namespace, client *clientv3.Client) (Namespace, error) { - rt, err := BuildRouter(&cfg.Backend, client) - if err != nil { - return nil, errors.WithMessage(err, "build router error") - } - wrapper := &NamespaceImpl{ - name: cfg.Namespace, - router: rt, - } - - return wrapper, nil -} - -func (n *NamespaceImpl) Name() string { - return n.name -} - -func (n *NamespaceImpl) GetRouter() driver.Router { - return n.router -} - -func (n *NamespaceImpl) Close() { - n.router.Close() -} - -func BuildRouter(cfg *config.BackendNamespace, client *clientv3.Client) (driver.Router, error) { - return router.NewRandomRouter(cfg, client) -} - -func DefaultAsyncCloseNamespace(ns Namespace) error { - return nil -} diff --git a/pkg/manager/namespace/domain.go b/pkg/manager/namespace/domain.go deleted file mode 100644 index a903874f..00000000 --- a/pkg/manager/namespace/domain.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2020 Ipalfish, Inc. -// Copyright 2022 PingCAP, Inc. -// -// Licensed 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 namespace - -import ( - "github.com/pingcap/TiProxy/pkg/proxy/driver" -) - -type Namespace interface { - Name() string - Close() - GetRouter() driver.Router -} diff --git a/pkg/manager/namespace/errcode.go b/pkg/manager/namespace/errcode.go index 77752783..fbf2db1f 100644 --- a/pkg/manager/namespace/errcode.go +++ b/pkg/manager/namespace/errcode.go @@ -15,9 +15,7 @@ package namespace -import ( - "github.com/pingcap/errors" -) +import "github.com/pingcap/TiProxy/pkg/util/errors" var ( ErrDuplicatedUser = errors.New("duplicated user") diff --git a/pkg/manager/namespace/frontend.go b/pkg/manager/namespace/frontend.go deleted file mode 100644 index ecae9634..00000000 --- a/pkg/manager/namespace/frontend.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2020 Ipalfish, Inc. -// Copyright 2022 PingCAP, Inc. -// -// Licensed 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 namespace - -type SQLInfo struct { - SQL string -} - -type FrontendNamespace struct { - allowedDBs []string - allowedDBSet map[string]struct{} - usernames []string - sqlBlacklist map[uint32]SQLInfo - sqlWhitelist map[uint32]SQLInfo -} - -func (n *FrontendNamespace) IsDatabaseAllowed(db string) bool { - _, ok := n.allowedDBSet[db] - return ok -} - -func (n *FrontendNamespace) ListDatabases() []string { - ret := make([]string, len(n.allowedDBs)) - copy(ret, n.allowedDBs) - return ret -} - -func (n *FrontendNamespace) IsDeniedSQL(sqlFeature uint32) bool { - _, ok := n.sqlBlacklist[sqlFeature] - return ok -} - -func (n *FrontendNamespace) IsAllowedSQL(sqlFeature uint32) bool { - _, ok := n.sqlWhitelist[sqlFeature] - return ok -} diff --git a/pkg/manager/namespace/manager.go b/pkg/manager/namespace/manager.go index 3c5e814b..826fbbbc 100644 --- a/pkg/manager/namespace/manager.go +++ b/pkg/manager/namespace/manager.go @@ -16,162 +16,156 @@ package namespace import ( + "crypto/tls" + "crypto/x509" + "fmt" + "io/ioutil" "sync" "github.com/pingcap/TiProxy/pkg/config" + "github.com/pingcap/TiProxy/pkg/manager/router" "github.com/pingcap/TiProxy/pkg/proxy/driver" - "github.com/pingcap/errors" - "github.com/pingcap/tidb/util/logutil" + "github.com/pingcap/TiProxy/pkg/util/errors" clientv3 "go.etcd.io/etcd/client/v3" "go.uber.org/zap" ) type NamespaceManager struct { sync.RWMutex - - switchIndex int - users [2]*UserNamespaceMapper - nss [2]*NamespaceHolder - reloadPrepared map[string]bool - client *clientv3.Client + logger *zap.Logger + nsm map[string]*Namespace } func NewNamespaceManager() *NamespaceManager { return &NamespaceManager{} } - -func (mgr *NamespaceManager) Init(cfgs []*config.Namespace, client *clientv3.Client) error { - mgr.Lock() - defer mgr.Unlock() - - users, err := CreateUserNamespaceMapper(cfgs) +func (mgr *NamespaceManager) buildNamespace(cfg *config.Namespace, client *clientv3.Client) (*Namespace, error) { + logger := mgr.logger.With(zap.String("namespace", cfg.Namespace)) + rt, err := router.NewRandomRouter(&cfg.Backend, client) if err != nil { - return errors.WithMessage(err, "create UserNamespaceMapper error") + return nil, errors.Errorf("build router error: %w", err) } - - nss, err := CreateNamespaceHolder(cfgs, client) - if err != nil { - return errors.WithMessage(err, "create NamespaceHolder error") + r := &Namespace{ + name: cfg.Namespace, + router: rt, } - mgr.reloadPrepared = make(map[string]bool) - mgr.client = client - mgr.users[0] = users - mgr.nss[0] = nss - return nil -} + // frontend tls configuration + { + r.frontendTLS = &tls.Config{} + + if !cfg.Frontend.Security.HasCert() { + return nil, errors.Errorf("require certificates to secure frontend tls connections") + } else { + cert, err := tls.LoadX509KeyPair(cfg.Frontend.Security.Cert, cfg.Frontend.Security.Key) + if err != nil { + return nil, errors.Errorf("failed to load server certs: %w", err) + } + r.frontendTLS.Certificates = append(r.frontendTLS.Certificates, cert) + } -func (n *NamespaceManager) Auth(username string, pwd, salt []byte) (driver.Namespace, bool) { - nsName, ok := n.getNamespaceByUsername(username) - if !ok { - return nil, false + if cfg.Frontend.Security.HasCA() { + r.frontendTLS.ClientAuth = tls.RequireAndVerifyClientCert + r.frontendTLS.ClientCAs = x509.NewCertPool() + certBytes, err := ioutil.ReadFile(cfg.Frontend.Security.CA) + if err != nil { + return nil, errors.Errorf("failed to read server signed certs from disk: %w", err) + } + if !r.frontendTLS.ClientCAs.AppendCertsFromPEM(certBytes) { + return nil, errors.Errorf("failed to load server signed certs") + } + } else { + logger.Warn("no signed certs for frontend, proxy will not authenticate clients (connection is still secured)") + } } - wrapper := &NamespaceWrapper{ - nsmgr: n, - name: nsName, - } + { + r.backendTLS = &tls.Config{} + // backend tls configuration + if !cfg.Backend.Security.HasCA() { + return nil, errors.Errorf("require signed certs to verify backend tls connections") + } else { + r.backendTLS.RootCAs = x509.NewCertPool() + certBytes, err := ioutil.ReadFile(cfg.Backend.Security.CA) + if err != nil { + return nil, errors.Errorf("failed to read server signed certs from disk: %w", err) + } + if !r.backendTLS.RootCAs.AppendCertsFromPEM(certBytes) { + return nil, errors.Errorf("failed to load server signed certs") + } + } - return wrapper, true -} + if cfg.Backend.Security.HasCert() { + cert, err := tls.LoadX509KeyPair(cfg.Backend.Security.Cert, cfg.Backend.Security.Key) + if err != nil { + return nil, errors.Errorf("failed to load cluster certs: %w", err) + } + r.backendTLS.Certificates = append(r.backendTLS.Certificates, cert) + } else { + logger.Warn("no certs for backend authentication, backend may reject proxy connections (connection is still secured)") + } + } -func (n *NamespaceManager) RedirectConnections() error { - return n.getCurrentNamespaces().RedirectConnections() + return r, nil } -func (n *NamespaceManager) PrepareReloadNamespace(namespace string, cfg *config.Namespace) error { - n.Lock() - defer n.Unlock() - - newUsers := n.getCurrentUsers().Clone() - newUsers.RemoveNamespaceUsers(namespace) - if err := newUsers.AddNamespaceUsers(namespace, &cfg.Frontend); err != nil { - return errors.WithMessage(err, "add namespace users error") +func (mgr *NamespaceManager) CommitNamespaces(nss []*config.Namespace, nss_delete []bool) error { + nsm := make(map[string]*Namespace) + mgr.RLock() + for k, v := range mgr.nsm { + nsm[k] = v } + mgr.RUnlock() - newNs, err := BuildNamespace(cfg, n.client) - if err != nil { - return errors.WithMessage(err, "build namespace error") - } - - newNss := n.getCurrentNamespaces().Clone() - newNss.Set(namespace, newNs) - - n.setOther(newUsers, newNss) - n.reloadPrepared[namespace] = true - - return nil -} - -func (n *NamespaceManager) CommitReloadNamespaces(namespaces []string) error { - n.Lock() - defer n.Unlock() + for i, nsc := range nss { + if nss_delete != nil && nss_delete[i] { + delete(nsm, nsc.Namespace) + continue + } - for _, namespace := range namespaces { - if !n.reloadPrepared[namespace] { - return errors.Errorf("namespace is not prepared: %s", namespace) + ns, err := mgr.buildNamespace(nsc, mgr.client) + if err != nil { + return fmt.Errorf("%w: create namespace error, namespace: %s", err, nsc.Namespace) } + nsm[ns.Name()] = ns } - n.toggle() + mgr.Lock() + mgr.nsm = nsm + mgr.Unlock() return nil } -func (n *NamespaceManager) RemoveNamespace(name string) { - n.Lock() - defer n.Unlock() - - n.getCurrentUsers().RemoveNamespaceUsers(name) - nss := n.getCurrentNamespaces() - ns, ok := nss.Get(name) - if !ok { - return - } - - if err := n.closeNamespace(ns); err != nil { - logutil.BgLogger().Error("remove namespace error", zap.Error(err), zap.String("namespace", name)) - return - } - - nss.Delete(name) -} +func (mgr *NamespaceManager) Init(logger *zap.Logger, nss []*config.Namespace, client *clientv3.Client) error { + mgr.Lock() + mgr.client = client + mgr.logger = logger + mgr.Unlock() -func (n *NamespaceManager) getNamespaceByUsername(username string) (string, bool) { - return n.getCurrentUsers().GetUserNamespace(username) + return mgr.CommitNamespaces(nss, nil) } -func (n *NamespaceManager) getCurrent() (*UserNamespaceMapper, *NamespaceHolder) { - return n.users[n.switchIndex], n.nss[n.switchIndex] -} +func (n *NamespaceManager) GetNamespace(nm string) (driver.Namespace, bool) { + n.RLock() + defer n.RUnlock() -func (n *NamespaceManager) getCurrentUsers() *UserNamespaceMapper { - return n.users[n.switchIndex] + ns, ok := n.nsm[nm] + return ns, ok } -func (n *NamespaceManager) getCurrentNamespaces() *NamespaceHolder { - return n.nss[n.switchIndex] -} +func (n *NamespaceManager) RedirectConnections() []error { + n.RLock() + defer n.RUnlock() -func (n *NamespaceManager) getOtherIndex() int { - if n.switchIndex == 0 { - return 1 - } else { - return 0 + var errs []error + for _, ns := range n.nsm { + err1 := ns.GetRouter().RedirectConnections() + if err1 != nil { + errs = append(errs, err1) + } } -} - -func (n *NamespaceManager) setOther(users *UserNamespaceMapper, nss *NamespaceHolder) { - other := n.getOtherIndex() - n.users[other], n.nss[other] = users, nss -} - -func (n *NamespaceManager) toggle() { - n.switchIndex = n.getOtherIndex() -} - -func (n *NamespaceManager) closeNamespace(ns Namespace) error { - return nil + return errs } func (n *NamespaceManager) Close() error { diff --git a/pkg/manager/namespace/namespace.go b/pkg/manager/namespace/namespace.go index 26b6e040..fc4840b3 100644 --- a/pkg/manager/namespace/namespace.go +++ b/pkg/manager/namespace/namespace.go @@ -16,104 +16,34 @@ package namespace import ( - "fmt" - "sync/atomic" + "crypto/tls" - "github.com/pingcap/TiProxy/pkg/config" - "github.com/pingcap/TiProxy/pkg/metrics" "github.com/pingcap/TiProxy/pkg/proxy/driver" - "github.com/pingcap/errors" - clientv3 "go.etcd.io/etcd/client/v3" ) -type NamespaceHolder struct { - nss map[string]Namespace -} - -type NamespaceWrapper struct { - nsmgr *NamespaceManager +type Namespace struct { name string - connCounter int64 -} - -func CreateNamespaceHolder(cfgs []*config.Namespace, client *clientv3.Client) (*NamespaceHolder, error) { - nss := make(map[string]Namespace, len(cfgs)) - - for _, cfg := range cfgs { - ns, err := BuildNamespace(cfg, client) - if err != nil { - return nil, errors.WithMessage(err, fmt.Sprintf("create namespace error, namespace: %s", cfg.Namespace)) - } - nss[cfg.Namespace] = ns - } - - holder := &NamespaceHolder{ - nss: nss, - } - return holder, nil -} - -func (n *NamespaceHolder) Get(name string) (Namespace, bool) { - ns, ok := n.nss[name] - return ns, ok -} - -func (n *NamespaceHolder) Set(name string, ns Namespace) { - n.nss[name] = ns -} - -func (n *NamespaceHolder) Delete(name string) { - delete(n.nss, name) -} - -func (n *NamespaceHolder) Clone() *NamespaceHolder { - nss := make(map[string]Namespace) - for name, ns := range n.nss { - nss[name] = ns - } - return &NamespaceHolder{ - nss: nss, - } + router driver.Router + frontendTLS *tls.Config + backendTLS *tls.Config } -func (n *NamespaceHolder) RedirectConnections() error { - var err error - for _, ns := range n.nss { - err1 := ns.GetRouter().RedirectConnections() - if err == nil && err1 != nil { - err = err1 - } - } - return err -} - -func (n *NamespaceWrapper) Name() string { +func (n *Namespace) Name() string { return n.name } -func (n *NamespaceWrapper) IncrConnCount() { - currCnt := atomic.AddInt64(&n.connCounter, 1) - metrics.QueryCtxGauge.WithLabelValues(n.name).Set(float64(currCnt)) -} - -func (n *NamespaceWrapper) DescConnCount() { - currCnt := atomic.AddInt64(&n.connCounter, -1) - metrics.QueryCtxGauge.WithLabelValues(n.name).Set(float64(currCnt)) +func (n *Namespace) FrontendTLSConfig() *tls.Config { + return n.frontendTLS } -func (n *NamespaceWrapper) Closed() bool { - _, ok := n.nsmgr.getCurrentNamespaces().Get(n.name) - return !ok +func (n *Namespace) BackendTLSConfig() *tls.Config { + return n.backendTLS } -func (n *NamespaceWrapper) GetRouter() driver.Router { - return n.mustGetCurrentNamespace().GetRouter() +func (n *Namespace) GetRouter() driver.Router { + return n.router } -func (n *NamespaceWrapper) mustGetCurrentNamespace() Namespace { - ns, ok := n.nsmgr.getCurrentNamespaces().Get(n.name) - if !ok { - panic(errors.New("namespace not found")) - } - return ns +func (n *Namespace) Close() { + n.router.Close() } diff --git a/pkg/manager/namespace/user.go b/pkg/manager/namespace/user.go deleted file mode 100644 index 665cbca9..00000000 --- a/pkg/manager/namespace/user.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2020 Ipalfish, Inc. -// Copyright 2022 PingCAP, Inc. -// -// Licensed 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 namespace - -import ( - "github.com/pingcap/TiProxy/pkg/config" -) - -type UserNamespaceMapper struct { - userToNamespace map[string]string -} - -func CreateUserNamespaceMapper(namespaces []*config.Namespace) (*UserNamespaceMapper, error) { - mapper := make(map[string]string) - ret := &UserNamespaceMapper{userToNamespace: mapper} - return ret, nil -} - -func (u *UserNamespaceMapper) GetUserNamespace(username string) (string, bool) { - if username == "" { - for _, ns := range u.userToNamespace { - return ns, true - } - } - - ns, ok := u.userToNamespace[username] - return ns, ok -} - -func (u *UserNamespaceMapper) Clone() *UserNamespaceMapper { - ret := make(map[string]string) - for k, v := range u.userToNamespace { - ret[k] = v - } - return &UserNamespaceMapper{userToNamespace: ret} -} - -func (u *UserNamespaceMapper) RemoveNamespaceUsers(ns string) { - for k, namespace := range u.userToNamespace { - if ns == namespace { - delete(u.userToNamespace, k) - } - } -} - -func (u *UserNamespaceMapper) AddNamespaceUsers(ns string, cfg *config.FrontendNamespace) error { - return nil -} diff --git a/pkg/manager/router/backend_observer.go b/pkg/manager/router/backend_observer.go index 39639ff2..c5e6cc58 100644 --- a/pkg/manager/router/backend_observer.go +++ b/pkg/manager/router/backend_observer.go @@ -109,8 +109,7 @@ func InitEtcdClient(cfg *config.Config) (*clientv3.Client, error) { pdEndpoints := strings.Split(pdAddr, ",") logConfig := zap.NewProductionConfig() logConfig.Level = zap.NewAtomicLevelAt(zap.ErrorLevel) - tlsConfig, err := security.CreateClusterTLSConfig(cfg.Security.ClusterSSLCA, cfg.Security.ClusterSSLKey, - cfg.Security.ClusterSSLCert) + tlsConfig, err := security.CreateClusterTLSConfig(cfg.Security.Cluster.CA, cfg.Security.Cluster.Key, cfg.Security.Cluster.Cert) if err != nil { return nil, err } diff --git a/pkg/proxy/driver/domain.go b/pkg/proxy/driver/domain.go index f2f5dfe2..9319ac52 100644 --- a/pkg/proxy/driver/domain.go +++ b/pkg/proxy/driver/domain.go @@ -24,14 +24,12 @@ import ( ) type NamespaceManager interface { - Auth(username string, pwd, salt []byte) (Namespace, bool) + GetNamespace(string) (Namespace, bool) Close() error } type Namespace interface { Name() string - IncrConnCount() - DescConnCount() GetRouter() Router } diff --git a/pkg/proxy/driver/queryctx.go b/pkg/proxy/driver/queryctx.go index adb74e10..458686ef 100644 --- a/pkg/proxy/driver/queryctx.go +++ b/pkg/proxy/driver/queryctx.go @@ -62,14 +62,11 @@ func (q *QueryCtxImpl) Close() error { if q.connMgr != nil { return q.connMgr.Close() } - if q.ns != nil { - q.ns.DescConnCount() - } return nil } func (q *QueryCtxImpl) ConnectBackend(ctx context.Context, clientIO *pnet.PacketIO, serverTLSConfig, backendTLSConfig *tls.Config) error { - ns, ok := q.nsmgr.Auth("", nil, nil) + ns, ok := q.nsmgr.GetNamespace("") if !ok { return errors.New("failed to find a namespace") } @@ -82,6 +79,5 @@ func (q *QueryCtxImpl) ConnectBackend(ctx context.Context, clientIO *pnet.Packet if err = q.connMgr.Connect(ctx, addr, clientIO, serverTLSConfig, backendTLSConfig); err != nil { return err } - q.ns.IncrConnCount() return nil } diff --git a/pkg/proxy/sqlserver/sql_server.go b/pkg/proxy/sqlserver/sql_server.go index 7391874f..b5861928 100644 --- a/pkg/proxy/sqlserver/sql_server.go +++ b/pkg/proxy/sqlserver/sql_server.go @@ -63,12 +63,10 @@ func NewSQLServer(cfg *config.Config, d driver.IDriver) (*SQLServer, error) { clients: make(map[uint64]driver.ClientConnection), } - if s.serverTLSConfig, err = security.CreateServerTLSConfig(cfg.Security.SSLCA, cfg.Security.SSLKey, cfg.Security.SSLCert, - cfg.Security.MinTLSVersion, cfg.Workdir, cfg.Security.RSAKeySize); err != nil { + if s.serverTLSConfig, err = security.CreateServerTLSConfig(cfg.Security.Server.CA, cfg.Security.Server.Key, cfg.Security.Server.Cert); err != nil { return nil, err } - if s.clusterTLSConfig, err = security.CreateClientTLSConfig(cfg.Security.ClusterSSLCA, cfg.Security.ClusterSSLKey, - cfg.Security.ClusterSSLCert); err != nil { + if s.clusterTLSConfig, err = security.CreateClientTLSConfig(cfg.Security.Cluster.CA, cfg.Security.Cluster.Key, cfg.Security.Cluster.Cert); err != nil { return nil, err } diff --git a/pkg/server/api/debug.go b/pkg/server/api/debug.go index 21d6dcd4..d0a66d07 100644 --- a/pkg/server/api/debug.go +++ b/pkg/server/api/debug.go @@ -29,10 +29,16 @@ type debugHttpHandler struct { } func (h *debugHttpHandler) Redirect(c *gin.Context) { - err := h.nsmgr.RedirectConnections() - if err != nil { + errs := h.nsmgr.RedirectConnections() + if len(errs) != 0 { errMsg := "redirect connections error" - h.logger.Error(errMsg, zap.Error(err)) + + var err_fields []zap.Field + for _, err := range errs { + err_fields = append(err_fields, zap.Error(err)) + } + h.logger.Error(errMsg, err_fields...) + c.JSON(http.StatusInternalServerError, errMsg) } else { c.JSON(http.StatusOK, "") diff --git a/pkg/server/api/namespace.go b/pkg/server/api/namespace.go index a279875a..6244c920 100644 --- a/pkg/server/api/namespace.go +++ b/pkg/server/api/namespace.go @@ -66,13 +66,6 @@ func (h *namespaceHttpHandler) HandleUpsertNamesapce(c *gin.Context) { return } - if err := h.nsmgr.PrepareReloadNamespace(ns, nsc); err != nil { - errMsg := "reload namespace error" - h.logger.Error(errMsg, zap.Error(err), zap.String("namespace", ns)) - c.YAML(http.StatusOK, errMsg) - return - } - c.YAML(http.StatusOK, "") } @@ -88,23 +81,38 @@ func (h *namespaceHttpHandler) HandleRemoveNamespace(c *gin.Context) { return } - h.nsmgr.RemoveNamespace(ns) - c.YAML(http.StatusOK, "") } func (h *namespaceHttpHandler) HandleCommit(c *gin.Context) { - nss := c.QueryArray("namespace") - - if len(nss) > 0 { - if err := h.nsmgr.CommitReloadNamespaces(nss); err != nil { - errMsg := "commit reload namespace error" - h.logger.Error(errMsg, zap.Error(err), zap.Strings("namespaces", nss)) - c.YAML(http.StatusInternalServerError, errMsg) - return + ns_names := c.QueryArray("namespace") + + var nss []*config.Namespace + var nss_delete []bool + var err error + if len(ns_names) == 0 { + nss, err = h.cfgmgr.ListAllNamespace(c) + if err != nil { + } + } else { + nss = make([]*config.Namespace, len(ns_names)) + nss_delete = make([]bool, len(ns_names)) + for i, ns_name := range ns_names { + ns, err := h.cfgmgr.GetNamespace(c, ns_name) + if err != nil { + } + nss[i] = ns + nss_delete[i] = false } } + if err := h.nsmgr.CommitNamespaces(nss, nss_delete); err != nil { + errMsg := "commit reload namespace error" + h.logger.Error(errMsg, zap.Error(err), zap.Any("namespaces", nss)) + c.YAML(http.StatusInternalServerError, errMsg) + return + } + c.YAML(http.StatusOK, "") } diff --git a/pkg/server/server.go b/pkg/server/server.go index 3efe71c9..9e0fac3e 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -155,7 +155,7 @@ func NewServer(ctx context.Context, cfg *config.Config, logger *zap.Logger, name return } - err = srv.NamespaceManager.Init(nss, srv.ObserverClient) + err = srv.NamespaceManager.Init(logger.Named("nsmgr"), nss, srv.ObserverClient) if err != nil { err = errors.WithStack(err) return diff --git a/pkg/util/datastructure/dsutil.go b/pkg/util/datastructure/dsutil.go deleted file mode 100644 index b3cad50d..00000000 --- a/pkg/util/datastructure/dsutil.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2020 Ipalfish, Inc. -// Copyright 2022 PingCAP, Inc. -// -// Licensed 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 datastructure - -func StringSliceToSet(ss []string) map[string]struct{} { - sset := make(map[string]struct{}, len(ss)) - for _, s := range ss { - sset[s] = struct{}{} - } - return sset -} diff --git a/pkg/util/datastructure/dsutil_test.go b/pkg/util/datastructure/dsutil_test.go deleted file mode 100644 index 2d115758..00000000 --- a/pkg/util/datastructure/dsutil_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2020 Ipalfish, Inc. -// Copyright 2022 PingCAP, Inc. -// -// Licensed 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 datastructure - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestStringSliceToSet(t *testing.T) { - tests := []struct { - name string - args []string - want map[string]struct{} - }{ - {name: "nil", args: nil, want: map[string]struct{}{}}, - {name: "one", args: []string{"db0"}, want: map[string]struct{}{"db0": {}}}, - {name: "two", args: []string{"db0", "db1"}, want: map[string]struct{}{"db0": {}, "db1": {}}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ret := StringSliceToSet(tt.args) - assert.Equal(t, ret, tt.want) - }) - } -} diff --git a/pkg/util/security/tls.go b/pkg/util/security/tls.go index fd3e303d..808ef004 100644 --- a/pkg/util/security/tls.go +++ b/pkg/util/security/tls.go @@ -31,15 +31,10 @@ import ( "github.com/pingcap/tidb/util/logutil" ) -func CreateServerTLSConfig(ca, key, cert, minTLSVer, path string, rsaKeySize int) (tlsConfig *tls.Config, err error) { +func CreateServerTLSConfig(ca, key, cert string) (tlsConfig *tls.Config, err error) { if len(cert) == 0 || len(key) == 0 { - cert = filepath.Join(path, "/cert.pem") - key = filepath.Join(path, "/key.pem") - err = createTLSCertificates(cert, key, rsaKeySize) - if err != nil { - logutil.BgLogger().Warn("TLS Certificate creation failed", zap.Error(err)) - return - } + cert = filepath.Join(cert, "cert.pem") + key = filepath.Join(key, "key.pem") } var tlsCert tls.Certificate @@ -50,29 +45,6 @@ func CreateServerTLSConfig(ca, key, cert, minTLSVer, path string, rsaKeySize int return } - var minTLSVersion uint16 = tls.VersionTLS11 - switch minTLSVer { - case "TLSv1.0": - minTLSVersion = tls.VersionTLS10 - case "TLSv1.1": - minTLSVersion = tls.VersionTLS11 - case "TLSv1.2": - minTLSVersion = tls.VersionTLS12 - case "TLSv1.3": - minTLSVersion = tls.VersionTLS13 - case "": - default: - logutil.BgLogger().Warn( - "Invalid TLS version, using default instead", - zap.String("tls-version", minTLSVer), - ) - } - if minTLSVersion < tls.VersionTLS12 { - logutil.BgLogger().Warn( - "Minimum TLS version allows pre-TLSv1.2 protocols, this is not recommended", - ) - } - // Try loading CA cert. clientAuthPolicy := tls.NoClientCert var certPool *x509.CertPool @@ -90,28 +62,10 @@ func CreateServerTLSConfig(ca, key, cert, minTLSVer, path string, rsaKeySize int } } - // This excludes ciphers listed in tls.InsecureCipherSuites() and can be used to filter out more - var cipherSuites []uint16 - var cipherNames []string - for _, sc := range tls.CipherSuites() { - switch sc.ID { - case tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: - logutil.BgLogger().Info("Disabling weak cipherSuite", zap.String("cipherSuite", sc.Name)) - default: - cipherNames = append(cipherNames, sc.Name) - cipherSuites = append(cipherSuites, sc.ID) - } - - } - logutil.BgLogger().Info("Enabled ciphersuites", zap.Strings("cipherNames", cipherNames)) - - /* #nosec G402 */ tlsConfig = &tls.Config{ Certificates: []tls.Certificate{tlsCert}, ClientCAs: certPool, ClientAuth: clientAuthPolicy, - MinVersion: minTLSVersion, - CipherSuites: cipherSuites, } return }