nats-io / nats-server

High-Performance server for NATS.io, the cloud and edge native messaging system.
https://nats.io
Apache License 2.0
15.67k stars 1.39k forks source link

Deny wildcard subscriptions but allow literals #2667

Open jcidoni-ocp opened 2 years ago

jcidoni-ocp commented 2 years ago

Feature Request

There should be a feature to deny wildcard subscriptions, but allow literal-variable subscriptions. This would be huge in preventing wiretap situations.

For example, I should be able to subscribe to: "client.69f3-432f-s234", but not to "client.*", without having to of had entered "69f3-432f-s234" already in the NATS configuration file for specifically "client.69f3-432f-s234".

Use Case:

This is useful for those of us who incorporate application-level GUIDs into topic names and do not want others to be able to easily listen to all communications to all GUIDs.

Proposed Change:

A change in the configuration file to allow for the denial of wildcard subscriptions, but acceptance of wildcard subscriptions that are entered literally.

Who Benefits From The Change(s)?

Everyone who wants to prevent wiretapping.

Alternative Approaches

I've seen other mention the JWT approach, but that is a lot more complicated and cumbersome to implement. A simple option to exclude wildcard subscriptions while allowing literal variable subscriptions

derekcollison commented 2 years ago

Allow by default is open, but deny can limit scope. So would not deny <client.*> work in your case for sub perms?

jcidoni-ocp commented 2 years ago

This is what happens with a simple deny of <client.*>, even if you specify , you are still disallowed from subscribing. And the key part is, the "asd" in is unknown, considering it is a dynamically generated GUID only good for the life of the client session.

joshc@DESKTOP-T5GGTU1:/mnt/c/Users/ec$ nats sub "client.*"
14:16:11 Subscribing on client.*
14:16:11 Unexpected NATS error: nats: Permissions Violation for Subscription to "client.*"
nats: error: nats: Permissions Violation for Subscription to "client.*", try --help
joshc@DESKTOP-T5GGTU1:/mnt/c/Users/ec$ nats sub "client.asd"
14:16:14 Subscribing on client.asd
14:16:14 Unexpected NATS error: nats: Permissions Violation for Subscription to "client.asd"
nats: error: nats: Permissions Violation for Subscription to "client.asd", try --help

This is with the following permissions:

authorization: {
    users = [
        {
            user: test
            password: test
            permissions: {
                publish: {
                    deny: ">"
                },
                subscribe: {
                  deny: "client.*"
                }
            }
        }
    ]
}
derekcollison commented 2 years ago

Ah you are correct.. We will consider, thanks.

nuharaf commented 2 years ago

+1

I remember there is similar discussion on slack but so long ago that it gone. also https://github.com/nats-io/nats-server/issues/664 is similar in nature I guess, though this one raised before the deny feature

themartorana commented 1 year ago

We ran into this recently. We have tens of thousands of clients, and would like them to be able to subscribe to their specific client ID clients.<id>, but would like to disallow the snooping of clients.* by any specific client.

kumpfdp commented 11 months ago

+1

We are evaluating replacing mosquitto with nats and have quickly run into this issue. In mosquitto, we have read ACLs set up using client/%c/#, allowing clients by default to sub to their specific topic(s) but not others. Would be nice to enable this type of feature in nats.

derekcollison commented 11 months ago

You can do what you need today. I think this is specifically asking about disallowing wildcard subscriptions. For what you are trying to do @kumpfdp its not needed AFAIK.

kumpfdp commented 11 months ago

Interesting @derekcollison, I may have misunderstood. I was thinking this is about avoiding wiretapping, or as i understand it, restricting clients from reading from other clients' topics but still allowing them access to their own.

If I currently have an ACL set up as read client/%c/# in mosquitto, this allows clients to read from their specific client id topics under client/. %c is a special character that allows this to work. Is there something similar in nats that I've overlooked?

derekcollison commented 11 months ago

In NATS you would need to be more explicit, but can achieve the same thing. Say you want all communications for a client to have a prefix of CLIENT., where ID uniquely identifies the client.

It would follow that you could place allow perms for both pub and sub to CLIENT.<ID>.>.

You would use the inbox prefix to make sure request / response followed same rules.

Lastly you could use account scoped subject mappings to make this a bit more transparent to the end applications if desired.

kumpfdp commented 11 months ago

Is dynamic meaning it applies to any client’s id? Or do you have to know the client id before configuring the authorization within nats? If it’s the latter, that’s a deal breaker for our use case.

derekcollison commented 11 months ago

Yes you would need to know. NATS is not a single server system, you can arrange NATS servers into any topology you want. Meaning that the permissions would be beyond a single server.

Most of our users/customers who care deeply about this have an external identity of some sort, whether it be a client certificate or the credentials themselves used to connect to a NATS system, which also gives you a unique identity within our system.

kumpfdp commented 11 months ago

Yes, we care very much about the identity of the connections, as well. However, these identities aren’t known upfront in my scenario. This is where having the system be capable of dynamically injecting a client id into an authorization subject definition would be beneficial.

Example would be client.%cid.> where %cid is replaced with the connected client’s id by the system automatically for the connecting client. This would allow for a single authorization definition that could apply without having to know the exact client id of the connecting client.

Appreciate the continued discussion @derekcollison.

derekcollison commented 11 months ago

How do you trust the connection? The CID in NATS world is an ephemeral identity that is scoped to the server. It's not used for AuthN nor AuthZ, in a NATS system.

Most folks use either NATS JWTs or client certificates. These for the AuthN and bind to the connection. For the NATS JWT, it has all the information included for AuthZ.

kumpfdp commented 11 months ago

We do enforce trust of our connections and it is handled externally from our broker. This external component assigns the client id which is unique, per client connection. What I'm looking to replicate from mosquitto into nats is the pattern ACLs (https://mosquitto.org/man/mosquitto-conf-5.html). Specifically, %c and %u topic patterns.

jnmoyne commented 7 months ago

I think your use case maybe could be implemented using the new Auth callout feature. That unique ID that is assigned by another system could be simply part of what the client application passes as an authentication token, which is then passed to your implementation of the authentication callout service that can generate the JWT on the fly allowing the subscription to "foo.<id>" but disallowing subscriptions to "foo.>".