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.92k stars 1.41k forks source link

Does JetStream key-value store support authorization for each user? #3548

Closed tomghuang closed 2 years ago

tomghuang commented 2 years ago

NATS already supports authorization using subject-level permissions on a per-user basis. However, does NATS also support such authorization mechanism for the key-value store?

For example, can I say user A can only access key A, user B can only access key B, but admin can access all keys?

We want to use JetStream key-value store in a NATS cluster, because NATS can automatically synchronize servers and make sure the key-value store is consistent in the cluster. However, we don't know if we can configure its authorization setting, so that each user can only access some of the keys. Is there anyway to achieve this? Thanks.

derekcollison commented 2 years ago

With direct gets by subject yes that is possible. You would need to suppress the other access methods to secure it.

tomghuang commented 2 years ago

@derekcollison : Thanks for your suggestion and confirming that it is possible.

To prove that, I created a bucket, test_kv, and three users: admin, router001, and router002. Each router stores its settings under the dev.<id> key. The goal is that router002 should not be able to access keys belonging to router001, which is under the dev.001 key. I've successfully proved that with the following configuration:

jetstream {
   max_memory_store: 1073741824
   max_file_store: 10737418240
}

authorization: {
    users: [
        {
            user: admin, password: "admin",
            permissions: {
                subscribe: ">",
                publish: ">"
            }
        },

        {
            user: router001, password: "router001",
            permissions: {
                subscribe: ["dev.001.>", "_INBOX.>"],
                publish: [
                    "dev.001.>",
                    "$JS.API.STREAM.INFO.>",
                    "$KV.test_kv.dev.001.>",
                    "$JS.API.DIRECT.GET.KV_test_kv.$KV.test_kv.dev.001.>"
                ]
            }
        },

        {
            user: router002, password: "router002",
            permissions: {
                subscribe: "dev.002.>",
                publish: "dev.002.>"
            }
        }
    ]
}

Although I've successfully achieved what I want, I do not feel confident in what I've done. I added those subject wildcard patterns simply because the error messages told me that I didn't have permission to access them, not because I understand how to do it. I don't know if subjects like $JS.API.STREAM.INFO, $KV.test_kv.dev.001, and $JS.API.DIRECT.GET.KV_test_kv.$KV.test_kv.dev.001 are meant to be used in this way. I don't know if there is any other "official/better" way to setup the permission for the key-value store.

Can the NATS team enhance the key-value store document, so that we can understand how to properly setup key-value store permission for each user? Thanks.

derekcollison commented 2 years ago

Those are indeed the correct permissions.

We will look into enhancing the docs, thanks.

/cc @bruth @jnmoyne

bruth commented 2 years ago

@tomghuang Thanks for calling this out. Defining JS/KV-specific permissions is definitely a bit low-level as of now. Assuming you only need to put and get values from the KV, here is a minimal example that should achieve what you need: https://nats-by-example-q877a1djf-connecteverything.vercel.app/examples/auth/perms/cli (below the code shows the output)

tomghuang commented 2 years ago

@bruth : Really appreciate the official clearly-explained example. It helps to complete my understanding of the key-value store feature.

bjorndm commented 8 months ago

I would like to define many permissions per user, so for me it is somewhat difficult to define 3 permissions per key like this:

 "\$JS.API.STREAM.INFO.KV_test_kv",
"\$KV.test_kv.dev.001.>",
"\$JS.API.DIRECT.GET.KV_test_kv.\$KV.test_kv.dev.001.>" 

I would appreciate it if there was a more user-friendly way of defining key-value permissions and object store read and write.