Catalog + Namespace OSS changes. (#7219)

* Various Prepared Query + Namespace things

* Last round of OSS changes for a namespaced catalog
This commit is contained in:
Matt Keeler 2020-02-10 10:40:44 -05:00 committed by GitHub
parent 20600403b2
commit d0cd092e3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 57 additions and 27 deletions

View File

@ -110,7 +110,6 @@ func (s *HTTPServer) ACLRulesTranslate(resp http.ResponseWriter, req *http.Reque
}
// Should this require lesser permissions? Really the only reason to require authorization at all is
// to prevent external entities from DoS Consul with repeated rule translation requests
// TODO (namespaces) - pass through a real ent authz ctx
if rule != nil && rule.ACLRead(nil) != acl.Allow {
return nil, acl.ErrPermissionDenied
}

View File

@ -1107,7 +1107,6 @@ func (s *HTTPServer) AgentNodeMaintenance(resp http.ResponseWriter, req *http.Re
if err != nil {
return nil, err
}
// TODO (namespaces) - pass through a real ent authz ctx?
if rule != nil && rule.NodeWrite(s.agent.config.NodeName, nil) != acl.Allow {
return nil, acl.ErrPermissionDenied
}
@ -1325,12 +1324,15 @@ func (s *HTTPServer) AgentConnectCALeafCert(resp http.ResponseWriter, req *http.
// not the ID of the service instance.
serviceName := strings.TrimPrefix(req.URL.Path, "/v1/agent/connect/ca/leaf/")
// TODO (namespaces) add namespacing to connect leaf cert generation request
args := cachetype.ConnectCALeafRequest{
Service: serviceName, // Need name not ID
}
var qOpts structs.QueryOptions
if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil {
return nil, err
}
// Store DC in the ConnectCALeafRequest but query opts separately
if done := s.parse(resp, req, &args.Datacenter, &qOpts); done {
return nil, nil

View File

@ -226,7 +226,7 @@ func (s *HTTPServer) catalogServiceNodes(resp http.ResponseWriter, req *http.Req
// Set default DC
args := structs.ServiceSpecificRequest{Connect: connect}
if err := s.parseEntMeta(req, &args.EnterpriseMeta); err != nil {
if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil {
return nil, err
}

View File

@ -487,9 +487,12 @@ func (s *ConnectCA) Sign(
if err != nil {
return err
}
var authzContext acl.AuthorizerContext
var entMeta structs.EnterpriseMeta
if isService {
// TODO (namespaces) use actual ent authz context
if rule != nil && rule.ServiceWrite(serviceID.Service, nil) != acl.Allow {
entMeta.Merge(serviceID.GetEnterpriseMeta())
entMeta.FillAuthzContext(&authzContext)
if rule != nil && rule.ServiceWrite(serviceID.Service, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied
}
@ -500,8 +503,8 @@ func (s *ConnectCA) Sign(
"we are %s", serviceID.Datacenter, s.srv.config.Datacenter)
}
} else if isAgent {
// TODO (namespaces) use actual ent authz context
if rule != nil && rule.NodeWrite(agentID.Agent, nil) != acl.Allow {
structs.DefaultEnterpriseMeta().FillAuthzContext(&authzContext)
if rule != nil && rule.NodeWrite(agentID.Agent, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied
}
}
@ -588,10 +591,11 @@ func (s *ConnectCA) Sign(
// Set the response
*reply = structs.IssuedCert{
SerialNumber: connect.EncodeSerialNumber(cert.SerialNumber),
CertPEM: pem,
ValidAfter: cert.NotBefore,
ValidBefore: cert.NotAfter,
SerialNumber: connect.EncodeSerialNumber(cert.SerialNumber),
CertPEM: pem,
ValidAfter: cert.NotBefore,
ValidBefore: cert.NotAfter,
EnterpriseMeta: entMeta,
RaftIndex: structs.RaftIndex{
ModifyIndex: modIdx,
CreateIndex: modIdx,

View File

@ -139,13 +139,14 @@ func (c *Coordinate) Update(args *structs.CoordinateUpdateRequest, reply *struct
}
// Fetch the ACL token, if any, and enforce the node policy if enabled.
rule, err := c.srv.ResolveToken(args.Token)
authz, err := c.srv.ResolveToken(args.Token)
if err != nil {
return err
}
if rule != nil && c.srv.config.ACLEnforceVersion8 {
// TODO (namespaces) use actual ent authz context
if rule.NodeWrite(args.Node, nil) != acl.Allow {
if authz != nil && c.srv.config.ACLEnforceVersion8 {
var authzContext acl.AuthorizerContext
structs.DefaultEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.NodeWrite(args.Node, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied
}
}
@ -211,13 +212,15 @@ func (c *Coordinate) Node(args *structs.NodeSpecificRequest, reply *structs.Inde
}
// Fetch the ACL token, if any, and enforce the node policy if enabled.
rule, err := c.srv.ResolveToken(args.Token)
authz, err := c.srv.ResolveToken(args.Token)
if err != nil {
return err
}
if rule != nil && c.srv.config.ACLEnforceVersion8 {
// TODO (namespaces) use actual ent authz context
if rule.NodeRead(args.Node, nil) != acl.Allow {
if authz != nil && c.srv.config.ACLEnforceVersion8 {
var authzContext acl.AuthorizerContext
structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext)
if authz.NodeRead(args.Node, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied
}
}

View File

@ -28,6 +28,11 @@ func (m *Internal) NodeInfo(args *structs.NodeSpecificRequest,
return err
}
_, err := m.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
return m.srv.blockingQuery(
&args.QueryOptions,
&reply.QueryMeta,
@ -49,6 +54,11 @@ func (m *Internal) NodeDump(args *structs.DCSpecificRequest,
return err
}
_, err := m.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
filter, err := bexpr.CreateFilter(args.Filter, nil, reply.Dump)
if err != nil {
return err
@ -83,6 +93,11 @@ func (m *Internal) ServiceDump(args *structs.ServiceDumpRequest, reply *structs.
return err
}
_, err := m.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
filter, err := bexpr.CreateFilter(args.Filter, nil, reply.Nodes)
if err != nil {
return err

View File

@ -548,6 +548,7 @@ func (p *PreparedQuery) execute(query *structs.PreparedQuery,
// Capture the nodes and pass the DNS information through to the reply.
reply.Service = query.Service.Service
reply.EnterpriseMeta = query.Service.EnterpriseMeta
reply.Nodes = nodes
reply.DNS = query.DNS

View File

@ -43,6 +43,7 @@ func testServerACLConfig(cb func(*Config)) func(*Config) {
c.ACLsEnabled = true
c.ACLMasterToken = TestDefaultMasterToken
c.ACLDefaultPolicy = "deny"
c.ACLEnforceVersion8 = true
if cb != nil {
cb(c)

View File

@ -1206,7 +1206,7 @@ func (s *Store) getPolicyWithTxn(tx *memdb.Txn, ws memdb.WatchSet, value string,
}
ws.Add(watchCh)
if err != nil || policy == nil {
if policy == nil {
return nil, err
}

View File

@ -528,7 +528,6 @@ func (s *Store) deleteNodeCASTxn(tx *memdb.Txn, idx, cidx uint64, nodeName strin
// deleteNodeTxn is the inner method used for removing a node from
// the store within a given transaction.
// TODO (namespaces) (catalog) access to catalog tables needs to become namespace aware for services/checks
func (s *Store) deleteNodeTxn(tx *memdb.Txn, idx uint64, nodeName string) error {
// Look up the node.
node, err := tx.First("nodes", "id", nodeName)

View File

@ -256,8 +256,6 @@ func TestDiscoveryChainRead(t *testing.T) {
})
}))
// TODO(namespaces): add a test
expectTarget_DC2 := newTarget("web", "", "default", "dc2")
expectTarget_DC2.MeshGateway = structs.MeshGatewayConfig{
Mode: structs.MeshGatewayModeLocal,

View File

@ -108,7 +108,7 @@ RETRY_ONCE:
func (s *HTTPServer) HealthServiceChecks(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
// Set default DC
args := structs.ServiceSpecificRequest{}
if err := s.parseEntMeta(req, &args.EnterpriseMeta); err != nil {
if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil {
return nil, err
}
s.parseSource(req, &args.Source)
@ -164,7 +164,7 @@ func (s *HTTPServer) HealthServiceNodes(resp http.ResponseWriter, req *http.Requ
func (s *HTTPServer) healthServiceNodes(resp http.ResponseWriter, req *http.Request, connect bool) (interface{}, error) {
// Set default DC
args := structs.ServiceSpecificRequest{Connect: connect}
if err := s.parseEntMeta(req, &args.EnterpriseMeta); err != nil {
if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil {
return nil, err
}
s.parseSource(req, &args.Source)

View File

@ -305,6 +305,9 @@ type PreparedQueryExecuteResponse struct {
// Service is the service that was queried.
Service string
// EnterpriseMeta of the service that was queried.
EnterpriseMeta
// Nodes has the nodes that were output by the query.
Nodes CheckServiceNodes

View File

@ -33,7 +33,6 @@ func (d *DiscoveryChain) Get(name string, opts *DiscoveryChainOptions, q *QueryO
if opts.EvaluateInDatacenter != "" {
r.params.Set("compile-dc", opts.EvaluateInDatacenter)
}
// TODO(namespaces): handle possible EvaluateInNamespace here
}
if method == "POST" {

View File

@ -25,6 +25,9 @@ type ServiceQuery struct {
// Service is the service to query.
Service string
// Namespace of the service to query
Namespace string `json:",omitempty"`
// Near allows baking in the name of a node to automatically distance-
// sort from. The magic "_agent" value is supported, which sorts near
// the agent which initiated the request by default.
@ -119,6 +122,9 @@ type PreparedQueryExecuteResponse struct {
// Service is the service that was queried.
Service string
// Namespace of the service that was queried
Namespace string `json:",omitempty"`
// Nodes has the nodes that were output by the query.
Nodes []ServiceEntry