-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Adds support for agent-side ACL token management via API instead of config files. #3324
Conversation
9d6ff91
to
c2f4670
Compare
c2f4670
to
9b53738
Compare
agent/token_store.go
Outdated
} | ||
|
||
// UpdateUserToken replaces the current user token in the store. | ||
func (t *TokenStore) UpdateUserToken(userToken string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/userToken/token/
agent/token_store.go
Outdated
} | ||
|
||
// UpdateAgentToken replaces the current agent token in the store. | ||
func (t *TokenStore) UpdateAgentToken(agentToken string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/agentToken/token/
agent/token_store.go
Outdated
} | ||
|
||
// GetTokenForUser returns the best token to use for user operations. | ||
func (t *TokenStore) GetTokenForUser() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/GetTokenForUser/UserToken/
agent/token_store.go
Outdated
t.l.RLock() | ||
defer t.l.RUnlock() | ||
|
||
if t.userToken != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's redundant. return t.userToken
should be sufficient.
agent/token_store.go
Outdated
} | ||
|
||
// GetTokenForAgent returns the best token to use for internal agent operations. | ||
func (t *TokenStore) GetTokenForAgent() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/GetTokenForAgent/AgentToken/
agent/token_store_test.go
Outdated
} | ||
} | ||
|
||
func TestTokenStore_UserToken(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you rewrite the previous test as a table driven test then you can roll this test in there as well.
agent/token_store_test.go
Outdated
} | ||
} | ||
|
||
func TestTokenStore_AgentMasterToken(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test feels a bit verbose. Not sure if a helper func would make it shorter but less readable though. You could add a helper to bail on wrong tokens but I'm not sure it really helps.
isNot := func(toks ...string) {
for _, tok := range toks {
if tokens.IsAgentMasterToken(tok) {
t.Fatalf("token %q is agent master token although it shouldn't be", tok)
}
}
}
...
isNot("", "nope")
agent/agent_endpoint_test.go
Outdated
a := NewTestAgent(t.Name(), TestACLConfig()) | ||
defer a.Shutdown() | ||
|
||
t.Run("bad method", func(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test bad json as well? Also, you can write this as a table driven test
tests := []struct {
name string
method, urlstr string
body io.Reader
code int
agentToken, masterToken string
}{
{"bad method", "HEAD", "...", nil, http.StatusMethodNotAllowed, "", "" },
...
}
agent/agent_endpoint_test.go
Outdated
}) | ||
} | ||
|
||
func TestAgent_Token_ACLDeny(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Roll this one into the previous test if you refactor to table driven?
agent/agent_endpoint_test.go
Outdated
} | ||
}) | ||
|
||
t.Run("management token", func(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works b/c the mgmt token is root
set in TestACLConfig
? Just curious?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - "root" is the default management token in all our test helpers. That's a little obscure.
@@ -155,7 +149,7 @@ func (m *aclManager) lookupACL(a *Agent, id string) (acl.ACL, error) { | |||
id = anonymousToken | |||
} else if acl.RootACL(id) != nil { | |||
return nil, errors.New(rootDenied) | |||
} else if m.master != nil && id == a.config.ACLAgentMasterToken { | |||
} else if a.tokens.IsAgentMasterToken(id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can agent.tokens be nil?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No - the token store is created as part of constructing an agent, so it will be there even if ACLs aren't enabled.
This is the first phase of secure ACL token introduction where we change the agent-side token management to happen via a new token store instead of the config object directly, and then we add an API to manage the token store on the fly. This lets us use APIs to manage the agent tokens vs. having to place ACL tokens in config files on the agent.
When we do the server side we will cover the other tokens:
acl_replication_token
andacl_master_token
. Theacl_replication_token
will get added to the token store (we don't expect to add any other things to the token store), and theacl_master_token
will be handled with a new /v1/acl/bootstrap API.