acl: fix ACL bypass for anon requests that pass thru client HTTP
Requests without an ACL token that pass thru the client's HTTP API are treated as though they come from the client itself. This allows bypass of ACLs on RPC requests where ACL permissions are checked (like `Job.Register`). Invalid tokens are correctly rejected. Fix the bypass by only setting a client ID on the identity if we have a valid node secret. Note that this changeset will break rate metrics for RPCs sent by clients without a client secret such as `Node.GetClientAllocs`; these requests will be recorded as anonymous. Future work should: * Ensure the node secret is sent with all client-driven RPCs except `Node.Register` which is TOFU. * Create a new `acl.ACL` object from client requests so that we can enforce ACLs for all endpoints in a uniform way that's less error-prone.~
This commit is contained in:
parent
9b4871fece
commit
8278f23042
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:security
|
||||||
|
acl: Fixed a bug where unauthenticated HTTP API requests through the client could bypass ACL policy checking [CVE-2023-1782](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-1782) [[GH-16775](https://github.com/hashicorp/nomad/issues/16775)]
|
||||||
|
```
|
|
@ -102,12 +102,9 @@ func (s *Server) Authenticate(ctx *RPCContext, args structs.RequestWithIdentity)
|
||||||
|
|
||||||
// At this point we either have an anonymous token or an invalid one.
|
// At this point we either have an anonymous token or an invalid one.
|
||||||
|
|
||||||
// Previously-connected clients will have a NodeID set on the context, which
|
// TODO(tgross): remove this entirely in 1.6.0 and enforce that all RPCs
|
||||||
// is available for all yamux streams over the same yamux session (and TCP
|
// driven by the clients have secret IDs set
|
||||||
// connection). This will be a large portion of the RPCs sent, but we can't
|
if ctx.NodeID != "" && secretID != "" {
|
||||||
// fast-path this at the top of the method, because authenticated HTTP
|
|
||||||
// requests to the clients will come in over to the same session.
|
|
||||||
if ctx.NodeID != "" {
|
|
||||||
args.SetIdentity(&structs.AuthenticatedIdentity{ClientID: ctx.NodeID})
|
args.SetIdentity(&structs.AuthenticatedIdentity{ClientID: ctx.NodeID})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,6 +217,13 @@ func TestAuthenticate_mTLS(t *testing.T) {
|
||||||
expectClientID: node.ID,
|
expectClientID: node.ID,
|
||||||
expectIDKey: fmt.Sprintf("client:%s", node.ID),
|
expectIDKey: fmt.Sprintf("client:%s", node.ID),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "from client missing secret", // ex. Node.Register
|
||||||
|
tlsCfg: clientTLSCfg,
|
||||||
|
expectAccessor: "anonymous",
|
||||||
|
expectTLSName: "regionFoo.nomad",
|
||||||
|
expectIP: follower.GetConfig().RPCAddr.IP.String(),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "from failed workload", // ex. Variables.List
|
name: "from failed workload", // ex. Variables.List
|
||||||
tlsCfg: clientTLSCfg,
|
tlsCfg: clientTLSCfg,
|
||||||
|
|
Loading…
Reference in New Issue