django-cacheops icon indicating copy to clipboard operation
django-cacheops copied to clipboard

Permissions issue writing to redis

Open shacker opened this issue 3 years ago • 3 comments
trafficstars

Redis is running on an external service (AWS) and I'm having trouble configuring cacheops to talk to it without getting this error:

redis.exceptions.NoPermissionError: this user has no permissions to access one of the keys used as arguments

I had no trouble setting up Django's main cache to use my prefix:

CACHES = {
    "default": {
        ...
        "KEY_PREFIX": config.REDIS_PREFIX,  # loaded from an env var
        ...
    }
}

# Then from a Django shell:
from django.core.cache import cache
cache.set("foo", "bar")
cache.get("foo")
'bar'

I'm having trouble wiring up cacheops to work the same way. Docs say we cannot use a simple string, but must reference a function or lambda:

CACHEOPS_PREFIX = lambda query: ...
# or
CACHEOPS_PREFIX = 'some.module.cacheops_prefix'

So, two questions:

  1. Why can't we use a simple string here? I'm not following the point of requiring a lambda or function to set this var, when a string works fine for the main Django cache settings.

  2. Even when I do set it up as a callable, still get the permissions error.

If I don't create the setting CACHEOPS_PREFIX , I get the permissions error. If I do set it, I get the permissions error.

def get_cacheops_prefix():
    return config.REDIS_PREFIX

# Neither of these work
#CACHEOPS_PREFIX = "myapp.settings.get_cacheops_prefix"
#CACHEOPS_PREFIX = lambda query: get_cacheops_prefix()

Since Django's main cache works fine, it feels like the Permissions error is red herring or mistake in my configuration, but I can't see what. Maybe this isn't about the prefix? But if not that, then what? Thanks for a clue.

shacker avatar Feb 24 '22 02:02 shacker

Django cache does not support callable prefix, so it's just string, here things are different.

CACHEOPS_PREFIX = lambda _: "your_prefix"

Should work. If not then need to look at particular key you get permission error on.

Suor avatar Feb 24 '22 02:02 Suor

I dug into this a bit more and found the issue. If you are using Redis' ACL to restrict a user to a specific key namespace, you can replicate the problem. In Redis add a user like this:

ACL SETUSER user on nopass ~user/* +@all

Now set CACHEOPS_PREFIX = lambda _: "user/" and connect to redis://user@localhost:6379/0.

When you query the database the cache_thing.lua script will get called with 3 keys:

  1. "user/"
  2. "user/q:..."
  3. ""

Redis won't run the script because the last key cannot be accessed by this user and you'll get this error:

NOPERM this user has no permissions to access one of the keys used as arguments

I'm not deeply familiar with how this library works, but I submitted a PR which seems to fix the issue in #423

ipmb avatar Feb 24 '22 23:02 ipmb

Thanks very much for the PR @ipmb and thanks for the speedy merge @Suor . Just need to get this into pypi and we'll be off and running.

shacker avatar Feb 25 '22 18:02 shacker