agent: Ensure partition is considered in agent endpoints (#11427)

This commit is contained in:
Chris S. Kim 2021-10-26 15:20:57 -04:00 committed by GitHub
parent 3c6331e9be
commit 27f8a85664
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 30 deletions

View File

@ -28,7 +28,7 @@ func TestHTTPHandlers_ACLLegacy(t *testing.T) {
resp := httptest.NewRecorder()
a.srv.h.ServeHTTP(resp, req)
require.Equal(t, resp.Code, http.StatusGone)
require.Equal(t, http.StatusGone, resp.Code)
require.Contains(t, resp.Body.String(), "the legacy ACL system was removed")
}

View File

@ -139,7 +139,7 @@ type delegate interface {
// ResolveTokenAndDefaultMeta returns an acl.Authorizer which authorizes
// actions based on the permissions granted to the token.
// If either entMeta or authzContext are non-nil they will be populated with the
// default namespace from the token.
// default partition and namespace from the token.
ResolveTokenAndDefaultMeta(token string, entMeta *structs.EnterpriseMeta, authzContext *acl.AuthorizerContext) (acl.Authorizer, error)
RPC(method string, args interface{}, reply interface{}) error

View File

@ -55,7 +55,11 @@ func (s *HTTPHandlers) AgentSelf(resp http.ResponseWriter, req *http.Request) (i
if err != nil {
return nil, err
}
if authz.AgentRead(s.agent.config.NodeName, nil) != acl.Allow {
// Authorize using the agent's own enterprise meta, not the token.
var authzContext acl.AuthorizerContext
s.agent.agentEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.AgentRead(s.agent.config.NodeName, &authzContext) != acl.Allow {
return nil, acl.ErrPermissionDenied
}
@ -141,7 +145,11 @@ func (s *HTTPHandlers) AgentMetrics(resp http.ResponseWriter, req *http.Request)
if err != nil {
return nil, err
}
if authz.AgentRead(s.agent.config.NodeName, nil) != acl.Allow {
// Authorize using the agent's own enterprise meta, not the token.
var authzContext acl.AuthorizerContext
s.agent.agentEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.AgentRead(s.agent.config.NodeName, &authzContext) != acl.Allow {
return nil, acl.ErrPermissionDenied
}
if enablePrometheusOutput(req) {
@ -169,10 +177,14 @@ func (s *HTTPHandlers) AgentMetricsStream(resp http.ResponseWriter, req *http.Re
var token string
s.parseToken(req, &token)
authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil)
switch {
case err != nil:
if err != nil {
return nil, err
case authz.AgentRead(s.agent.config.NodeName, nil) != acl.Allow:
}
// Authorize using the agent's own enterprise meta, not the token.
var authzContext acl.AuthorizerContext
s.agent.agentEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.AgentRead(s.agent.config.NodeName, &authzContext) != acl.Allow {
return nil, acl.ErrPermissionDenied
}
@ -221,7 +233,11 @@ func (s *HTTPHandlers) AgentReload(resp http.ResponseWriter, req *http.Request)
if err != nil {
return nil, err
}
if authz.AgentWrite(s.agent.config.NodeName, nil) != acl.Allow {
// Authorize using the agent's own enterprise meta, not the token.
var authzContext acl.AuthorizerContext
s.agent.agentEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.AgentWrite(s.agent.config.NodeName, &authzContext) != acl.Allow {
return nil, acl.ErrPermissionDenied
}
@ -528,7 +544,11 @@ func (s *HTTPHandlers) AgentJoin(resp http.ResponseWriter, req *http.Request) (i
if err != nil {
return nil, err
}
if authz.AgentWrite(s.agent.config.NodeName, nil) != acl.Allow {
// Authorize using the agent's own enterprise meta, not the token.
var authzContext acl.AuthorizerContext
s.agent.agentEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.AgentWrite(s.agent.config.NodeName, &authzContext) != acl.Allow {
return nil, acl.ErrPermissionDenied
}
@ -561,7 +581,11 @@ func (s *HTTPHandlers) AgentLeave(resp http.ResponseWriter, req *http.Request) (
if err != nil {
return nil, err
}
if authz.AgentWrite(s.agent.config.NodeName, nil) != acl.Allow {
// Authorize using the agent's own enterprise meta, not the token.
var authzContext acl.AuthorizerContext
s.agent.agentEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.AgentWrite(s.agent.config.NodeName, &authzContext) != acl.Allow {
return nil, acl.ErrPermissionDenied
}
@ -1272,7 +1296,11 @@ func (s *HTTPHandlers) AgentMonitor(resp http.ResponseWriter, req *http.Request)
if err != nil {
return nil, err
}
if authz.AgentRead(s.agent.config.NodeName, nil) != acl.Allow {
// Authorize using the agent's own enterprise meta, not the token.
var authzContext acl.AuthorizerContext
s.agent.agentEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.AgentRead(s.agent.config.NodeName, &authzContext) != acl.Allow {
return nil, acl.ErrPermissionDenied
}
@ -1351,7 +1379,11 @@ func (s *HTTPHandlers) AgentToken(resp http.ResponseWriter, req *http.Request) (
if err != nil {
return nil, err
}
if authz.AgentWrite(s.agent.config.NodeName, nil) != acl.Allow {
// Authorize using the agent's own enterprise meta, not the token.
var authzContext acl.AuthorizerContext
s.agent.agentEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.AgentWrite(s.agent.config.NodeName, &authzContext) != acl.Allow {
return nil, acl.ErrPermissionDenied
}
@ -1359,9 +1391,7 @@ func (s *HTTPHandlers) AgentToken(resp http.ResponseWriter, req *http.Request) (
// fields to this later if needed.
var args api.AgentToken
if err := decodeBody(req.Body, &args); err != nil {
resp.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(resp, "Request decode failed: %v", err)
return nil, nil
return nil, BadRequestError{Reason: fmt.Sprintf("Request decode failed: %v", err)}
}
// Figure out the target token.

View File

@ -4685,7 +4685,7 @@ func TestAgent_NodeMaintenance_BadRequest(t *testing.T) {
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
// Fails when no enable flag provided
req, _ := http.NewRequest("PUT", "/v1/agent/self/maintenance", nil)
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance", nil)
resp := httptest.NewRecorder()
if _, err := a.srv.AgentNodeMaintenance(resp, req); err != nil {
t.Fatalf("err: %s", err)
@ -4706,7 +4706,7 @@ func TestAgent_NodeMaintenance_Enable(t *testing.T) {
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
// Force the node into maintenance mode
req, _ := http.NewRequest("PUT", "/v1/agent/self/maintenance?enable=true&reason=broken&token=mytoken", nil)
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance?enable=true&reason=broken&token=mytoken", nil)
resp := httptest.NewRecorder()
if _, err := a.srv.AgentNodeMaintenance(resp, req); err != nil {
t.Fatalf("err: %s", err)
@ -4746,7 +4746,7 @@ func TestAgent_NodeMaintenance_Disable(t *testing.T) {
a.EnableNodeMaintenance("", "")
// Leave maintenance mode
req, _ := http.NewRequest("PUT", "/v1/agent/self/maintenance?enable=false", nil)
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance?enable=false", nil)
resp := httptest.NewRecorder()
if _, err := a.srv.AgentNodeMaintenance(resp, req); err != nil {
t.Fatalf("err: %s", err)
@ -4772,14 +4772,14 @@ func TestAgent_NodeMaintenance_ACLDeny(t *testing.T) {
testrpc.WaitForLeader(t, a.RPC, "dc1")
t.Run("no token", func(t *testing.T) {
req, _ := http.NewRequest("PUT", "/v1/agent/self/maintenance?enable=true&reason=broken", nil)
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance?enable=true&reason=broken", nil)
if _, err := a.srv.AgentNodeMaintenance(nil, req); !acl.IsErrPermissionDenied(err) {
t.Fatalf("err: %v", err)
}
})
t.Run("root token", func(t *testing.T) {
req, _ := http.NewRequest("PUT", "/v1/agent/self/maintenance?enable=true&reason=broken&token=root", nil)
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance?enable=true&reason=broken&token=root", nil)
if _, err := a.srv.AgentNodeMaintenance(nil, req); err != nil {
t.Fatalf("err: %v", err)
}
@ -5227,21 +5227,21 @@ func TestAgent_Token(t *testing.T) {
init tokens
raw tokens
effective tokens
expectedErr error
expectedErr string
}{
{
name: "bad token name",
method: "PUT",
url: "nope?token=root",
body: body("X"),
expectedErr: NotFoundError{Reason: `Token "nope" is unknown`},
expectedErr: `Token "nope" is unknown`,
},
{
name: "bad JSON",
method: "PUT",
url: "acl_token?token=root",
body: badJSON(),
code: http.StatusBadRequest,
expectedErr: `Bad request: Request decode failed: json: cannot unmarshal bool into Go value of type api.AgentToken`,
},
{
name: "set user legacy",
@ -5398,8 +5398,8 @@ func TestAgent_Token(t *testing.T) {
req, _ := http.NewRequest(tt.method, url, tt.body)
_, err := a.srv.AgentToken(resp, req)
if tt.expectedErr != nil {
require.Equal(t, tt.expectedErr, err)
if tt.expectedErr != "" {
require.EqualError(t, err, tt.expectedErr)
return
}
require.NoError(t, err)

View File

@ -58,6 +58,10 @@ func (c *Client) ResolveTokenAndDefaultMeta(token string, entMeta *structs.Enter
return nil, err
}
if entMeta == nil {
entMeta = &structs.EnterpriseMeta{}
}
// Default the EnterpriseMeta based on the Tokens meta or actual defaults
// in the case of unknown identity
if identity != nil {

View File

@ -178,6 +178,10 @@ func (s *Server) ResolveTokenAndDefaultMeta(token string, entMeta *structs.Enter
return nil, err
}
if entMeta == nil {
entMeta = &structs.EnterpriseMeta{}
}
// Default the EnterpriseMeta based on the Tokens meta or actual defaults
// in the case of unknown identity
if identity != nil {