open-consul/agent/token/store.go
Matt Keeler fbb5c28c80
Updates to allow for using an enterprise specific token as the agents token
This is needed to allow for managed Consul instances to register themselves in the catalog with one of the managed service provider tokens.
2020-04-28 09:44:26 -04:00

180 lines
4.9 KiB
Go

package token
import (
"sync"
"crypto/subtle"
)
type TokenSource bool
const (
TokenSourceConfig TokenSource = false
TokenSourceAPI TokenSource = true
)
// Store is used to hold the special ACL tokens used by Consul agents. It is
// designed to update the tokens on the fly, so the token store itself should be
// plumbed around and used to get tokens at runtime, don't save the resulting
// tokens.
type Store struct {
// l synchronizes access to the token store.
l sync.RWMutex
// userToken is passed along for requests when the user didn't supply a
// token, and may be left blank to use the anonymous token. This will
// also be used for agent operations if the agent token isn't set.
userToken string
// userTokenSource indicates where this token originated from
userTokenSource TokenSource
// agentToken is used for internal agent operations like self-registering
// with the catalog and anti-entropy, but should never be used for
// user-initiated operations.
agentToken string
// agentTokenSource indicates where this token originated from
agentTokenSource TokenSource
// agentMasterToken is a special token that's only used locally for
// access to the /v1/agent utility operations if the servers aren't
// available.
agentMasterToken string
// agentMasterTokenSource indicates where this token originated from
agentMasterTokenSource TokenSource
// replicationToken is a special token that's used by servers to
// replicate data from the primary datacenter.
replicationToken string
// replicationTokenSource indicates where this token originated from
replicationTokenSource TokenSource
// enterpriseTokens contains tokens only used in consul-enterprise
enterpriseTokens
}
// UpdateUserToken replaces the current user token in the store.
// Returns true if it was changed.
func (t *Store) UpdateUserToken(token string, source TokenSource) bool {
t.l.Lock()
changed := (t.userToken != token || t.userTokenSource != source)
t.userToken = token
t.userTokenSource = source
t.l.Unlock()
return changed
}
// UpdateAgentToken replaces the current agent token in the store.
// Returns true if it was changed.
func (t *Store) UpdateAgentToken(token string, source TokenSource) bool {
t.l.Lock()
changed := (t.agentToken != token || t.agentTokenSource != source)
t.agentToken = token
t.agentTokenSource = source
t.l.Unlock()
return changed
}
// UpdateAgentMasterToken replaces the current agent master token in the store.
// Returns true if it was changed.
func (t *Store) UpdateAgentMasterToken(token string, source TokenSource) bool {
t.l.Lock()
changed := (t.agentMasterToken != token || t.agentMasterTokenSource != source)
t.agentMasterToken = token
t.agentMasterTokenSource = source
t.l.Unlock()
return changed
}
// UpdateReplicationToken replaces the current replication token in the store.
// Returns true if it was changed.
func (t *Store) UpdateReplicationToken(token string, source TokenSource) bool {
t.l.Lock()
changed := (t.replicationToken != token || t.replicationTokenSource != source)
t.replicationToken = token
t.replicationTokenSource = source
t.l.Unlock()
return changed
}
// UserToken returns the best token to use for user operations.
func (t *Store) UserToken() string {
t.l.RLock()
defer t.l.RUnlock()
return t.userToken
}
// AgentToken returns the best token to use for internal agent operations.
func (t *Store) AgentToken() string {
t.l.RLock()
defer t.l.RUnlock()
if tok := t.enterpriseAgentToken(); tok != "" {
return tok
}
if t.agentToken != "" {
return t.agentToken
}
return t.userToken
}
func (t *Store) AgentMasterToken() string {
t.l.RLock()
defer t.l.RUnlock()
return t.agentMasterToken
}
// ReplicationToken returns the replication token.
func (t *Store) ReplicationToken() string {
t.l.RLock()
defer t.l.RUnlock()
return t.replicationToken
}
// UserToken returns the best token to use for user operations.
func (t *Store) UserTokenAndSource() (string, TokenSource) {
t.l.RLock()
defer t.l.RUnlock()
return t.userToken, t.userTokenSource
}
// AgentToken returns the best token to use for internal agent operations.
func (t *Store) AgentTokenAndSource() (string, TokenSource) {
t.l.RLock()
defer t.l.RUnlock()
return t.agentToken, t.agentTokenSource
}
func (t *Store) AgentMasterTokenAndSource() (string, TokenSource) {
t.l.RLock()
defer t.l.RUnlock()
return t.agentMasterToken, t.agentMasterTokenSource
}
// ReplicationToken returns the replication token.
func (t *Store) ReplicationTokenAndSource() (string, TokenSource) {
t.l.RLock()
defer t.l.RUnlock()
return t.replicationToken, t.replicationTokenSource
}
// IsAgentMasterToken checks to see if a given token is the agent master token.
// This will never match an empty token for safety.
func (t *Store) IsAgentMasterToken(token string) bool {
t.l.RLock()
defer t.l.RUnlock()
return (token != "") && (subtle.ConstantTimeCompare([]byte(token), []byte(t.agentMasterToken)) == 1)
}