Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auth: Customize the settings of simpleTokenTTL. #11980

Merged
merged 1 commit into from
Jun 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions auth/simple_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const (

// var for testing purposes
var (
simpleTokenTTL = 5 * time.Minute
simpleTokenTTLDefault = 300 * time.Second
simpleTokenTTLResolution = 1 * time.Second
)

Expand All @@ -47,6 +47,7 @@ type simpleTokenTTLKeeper struct {
stopc chan struct{}
deleteTokenFunc func(string)
mu *sync.Mutex
simpleTokenTTL time.Duration
}

func (tm *simpleTokenTTLKeeper) stop() {
Expand All @@ -58,12 +59,12 @@ func (tm *simpleTokenTTLKeeper) stop() {
}

func (tm *simpleTokenTTLKeeper) addSimpleToken(token string) {
tm.tokens[token] = time.Now().Add(simpleTokenTTL)
tm.tokens[token] = time.Now().Add(tm.simpleTokenTTL)
}

func (tm *simpleTokenTTLKeeper) resetSimpleToken(token string) {
if _, ok := tm.tokens[token]; ok {
tm.tokens[token] = time.Now().Add(simpleTokenTTL)
tm.tokens[token] = time.Now().Add(tm.simpleTokenTTL)
}
}

Expand Down Expand Up @@ -101,6 +102,7 @@ type tokenSimple struct {
simpleTokenKeeper *simpleTokenTTLKeeper
simpleTokensMu sync.Mutex
simpleTokens map[string]string // token -> username
simpleTokenTTL time.Duration
}

func (t *tokenSimple) genTokenPrefix() (string, error) {
Expand Down Expand Up @@ -153,6 +155,10 @@ func (t *tokenSimple) invalidateUser(username string) {
}

func (t *tokenSimple) enable() {
if t.simpleTokenTTL <= 0 {
t.simpleTokenTTL = simpleTokenTTLDefault
}

delf := func(tk string) {
if username, ok := t.simpleTokens[tk]; ok {
t.lg.Info(
Expand All @@ -169,6 +175,7 @@ func (t *tokenSimple) enable() {
stopc: make(chan struct{}),
deleteTokenFunc: delf,
mu: &t.simpleTokensMu,
simpleTokenTTL: t.simpleTokenTTL,
}
go t.simpleTokenKeeper.run()
}
Expand Down Expand Up @@ -226,13 +233,14 @@ func (t *tokenSimple) isValidSimpleToken(ctx context.Context, token string) bool
return false
}

func newTokenProviderSimple(lg *zap.Logger, indexWaiter func(uint64) <-chan struct{}) *tokenSimple {
func newTokenProviderSimple(lg *zap.Logger, indexWaiter func(uint64) <-chan struct{}, TokenTTL time.Duration) *tokenSimple {
if lg == nil {
lg = zap.NewNop()
}
return &tokenSimple{
lg: lg,
simpleTokens: make(map[string]string),
indexWaiter: indexWaiter,
lg: lg,
simpleTokens: make(map[string]string),
indexWaiter: indexWaiter,
simpleTokenTTL: TokenTTL,
}
}
6 changes: 3 additions & 3 deletions auth/simple_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import (
// TestSimpleTokenDisabled ensures that TokenProviderSimple behaves correctly when
// disabled.
func TestSimpleTokenDisabled(t *testing.T) {
initialState := newTokenProviderSimple(zap.NewExample(), dummyIndexWaiter)
initialState := newTokenProviderSimple(zap.NewExample(), dummyIndexWaiter, simpleTokenTTLDefault)

explicitlyDisabled := newTokenProviderSimple(zap.NewExample(), dummyIndexWaiter)
explicitlyDisabled := newTokenProviderSimple(zap.NewExample(), dummyIndexWaiter, simpleTokenTTLDefault)
explicitlyDisabled.enable()
explicitlyDisabled.disable()

Expand All @@ -48,7 +48,7 @@ func TestSimpleTokenDisabled(t *testing.T) {
// TestSimpleTokenAssign ensures that TokenProviderSimple can correctly assign a
// token, look it up with info, and invalidate it by user.
func TestSimpleTokenAssign(t *testing.T) {
tp := newTokenProviderSimple(zap.NewExample(), dummyIndexWaiter)
tp := newTokenProviderSimple(zap.NewExample(), dummyIndexWaiter, simpleTokenTTLDefault)
tp.enable()
ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
token, err := tp.assign(ctx, "user1", 0)
Expand Down
6 changes: 4 additions & 2 deletions auth/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"strings"
"sync"
"sync/atomic"
"time"

"go.etcd.io/etcd/v3/auth/authpb"
"go.etcd.io/etcd/v3/etcdserver/api/v3rpc/rpctypes"
Expand Down Expand Up @@ -1213,7 +1214,8 @@ func decomposeOpts(lg *zap.Logger, optstr string) (string, map[string]string, er
func NewTokenProvider(
lg *zap.Logger,
tokenOpts string,
indexWaiter func(uint64) <-chan struct{}) (TokenProvider, error) {
indexWaiter func(uint64) <-chan struct{},
TokenTTL time.Duration) (TokenProvider, error) {
tokenType, typeSpecificOpts, err := decomposeOpts(lg, tokenOpts)
if err != nil {
return nil, ErrInvalidAuthOpts
Expand All @@ -1224,7 +1226,7 @@ func NewTokenProvider(
if lg != nil {
lg.Warn("simple token is not cryptographically signed")
}
return newTokenProviderSimple(lg, indexWaiter), nil
return newTokenProviderSimple(lg, indexWaiter, TokenTTL), nil

case tokenTypeJWT:
return newTokenProviderJWT(lg, typeSpecificOpts)
Expand Down
22 changes: 11 additions & 11 deletions auth/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestNewAuthStoreRevision(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer os.Remove(tPath)

tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter)
tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -78,7 +78,7 @@ func TestNewAuthStoreBcryptCost(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer os.Remove(tPath)

tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter)
tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
if err != nil {
t.Fatal(err)
}
Expand All @@ -98,7 +98,7 @@ func TestNewAuthStoreBcryptCost(t *testing.T) {
func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testing.T)) {
b, tPath := backend.NewDefaultTmpBackend()

tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter)
tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -650,7 +650,7 @@ func TestAuthInfoFromCtxRace(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer os.Remove(tPath)

tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter)
tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -716,7 +716,7 @@ func TestRecoverFromSnapshot(t *testing.T) {

as.Close()

tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter)
tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -749,13 +749,13 @@ func contains(array []string, str string) bool {

func TestHammerSimpleAuthenticate(t *testing.T) {
// set TTL values low to try to trigger races
oldTTL, oldTTLRes := simpleTokenTTL, simpleTokenTTLResolution
oldTTL, oldTTLRes := simpleTokenTTLDefault, simpleTokenTTLResolution
defer func() {
simpleTokenTTL = oldTTL
simpleTokenTTLDefault = oldTTL
simpleTokenTTLResolution = oldTTLRes
}()
simpleTokenTTL = 10 * time.Millisecond
simpleTokenTTLResolution = simpleTokenTTL
simpleTokenTTLDefault = 10 * time.Millisecond
simpleTokenTTLResolution = simpleTokenTTLDefault
users := make(map[string]struct{})

as, tearDown := setupAuthStore(t)
Expand Down Expand Up @@ -798,7 +798,7 @@ func TestRolesOrder(t *testing.T) {
b, tPath := backend.NewDefaultTmpBackend()
defer os.Remove(tPath)

tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter)
tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -853,7 +853,7 @@ func testAuthInfoFromCtxWithRoot(t *testing.T, opts string) {
b, tPath := backend.NewDefaultTmpBackend()
defer os.Remove(tPath)

tp, err := NewTokenProvider(zap.NewExample(), opts, dummyIndexWaiter)
tp, err := NewTokenProvider(zap.NewExample(), opts, dummyIndexWaiter, simpleTokenTTLDefault)
if err != nil {
t.Fatal(err)
}
Expand Down
8 changes: 6 additions & 2 deletions embed/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ type Config struct {
AuthToken string `json:"auth-token"`
BcryptCost uint `json:"bcrypt-cost"`

//The AuthTokenTTL in seconds of the simple token
AuthTokenTTL uint `json:"auth-token-ttl"`

ExperimentalInitialCorruptCheck bool `json:"experimental-initial-corrupt-check"`
ExperimentalCorruptCheckTime time.Duration `json:"experimental-corrupt-check-time"`
ExperimentalEnableV2V3 string `json:"experimental-enable-v2v3"`
Expand Down Expand Up @@ -396,8 +399,9 @@ func NewConfig() *Config {
CORS: map[string]struct{}{"*": {}},
HostWhitelist: map[string]struct{}{"*": {}},

AuthToken: "simple",
BcryptCost: uint(bcrypt.DefaultCost),
AuthToken: "simple",
BcryptCost: uint(bcrypt.DefaultCost),
AuthTokenTTL: 300,

PreVote: false, // TODO: enable by default in v3.5

Expand Down
1 change: 1 addition & 0 deletions embed/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) {
ClientCertAuthEnabled: cfg.ClientTLSInfo.ClientCertAuth,
AuthToken: cfg.AuthToken,
BcryptCost: cfg.BcryptCost,
TokenTTL: cfg.AuthTokenTTL,
CORS: cfg.CORS,
HostWhitelist: cfg.HostWhitelist,
InitialCorruptCheck: cfg.ExperimentalInitialCorruptCheck,
Expand Down
1 change: 1 addition & 0 deletions etcdmain/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ func newConfig() *config {
// auth
fs.StringVar(&cfg.ec.AuthToken, "auth-token", cfg.ec.AuthToken, "Specify auth token specific options.")
fs.UintVar(&cfg.ec.BcryptCost, "bcrypt-cost", cfg.ec.BcryptCost, "Specify bcrypt algorithm cost factor for auth password hashing.")
fs.UintVar(&cfg.ec.AuthTokenTTL, "auth-token-ttl", cfg.ec.AuthTokenTTL, "The lifetime in seconds of the auth token.")

// gateway
fs.BoolVar(&cfg.ec.EnableGRPCGateway, "enable-grpc-gateway", true, "Enable GRPC gateway.")
Expand Down
2 changes: 2 additions & 0 deletions etcdmain/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ Auth:
Specify a v3 authentication token type and its options ('simple' or 'jwt').
--bcrypt-cost ` + fmt.Sprintf("%d", bcrypt.DefaultCost) + `
Specify the cost / strength of the bcrypt algorithm for hashing auth passwords. Valid values are between ` + fmt.Sprintf("%d", bcrypt.MinCost) + ` and ` + fmt.Sprintf("%d", bcrypt.MaxCost) + `.
--auth-token-ttl 300
Time (in seconds) of the auth-token-ttl.

Profiling and Monitoring:
--enable-pprof 'false'
Expand Down
1 change: 1 addition & 0 deletions etcdserver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ type ServerConfig struct {

AuthToken string
BcryptCost uint
TokenTTL uint

// InitialCorruptCheck is true to check data corruption on boot
// before serving any peer/client traffic.
Expand Down
1 change: 1 addition & 0 deletions etcdserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ func NewServer(cfg ServerConfig) (srv *EtcdServer, err error) {
func(index uint64) <-chan struct{} {
return srv.applyWait.Wait(index)
},
time.Duration(cfg.TokenTTL)*time.Second,
)
if err != nil {
cfg.Logger.Warn("failed to create token provider", zap.Error(err))
Expand Down