Skip to content

The decorators do not refresh the cache #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jrobbins-LiveData opened this issue Oct 20, 2021 · 6 comments
Closed

The decorators do not refresh the cache #27

jrobbins-LiveData opened this issue Oct 20, 2021 · 6 comments

Comments

@jrobbins-LiveData
Copy link

jrobbins-LiveData commented Oct 20, 2021

The decorators capture their secrets at import time, and do not re-get their secrets when the target function is called. So the cache logic doesn't have a chance to run again, and the values stay potentially stale. This code illustrates the problem:

class Cache():
    def __init__(self):
        self.n = 0

    def get_secret_string(self, secret_id):
        self.n += 1
        return str(self.n)


cache = Cache()


class InjectSecretString:
    def __init__(self, secret_id, cache):
        self.cache = cache
        self.secret_id = secret_id

    def __call__(self, func):
        secret = self.cache.get_secret_string(secret_id=self.secret_id)

        def _wrapped_func(*args, **kwargs):
            return func(secret, *args, **kwargs)

        return _wrapped_func


@InjectSecretString("mysecretid", cache)
def test_function(args):
    print(f"{args=}")


def main():
    # NOTE: decorated function doesn't refresh cache
    test_function()
    test_function()

    print(f'{cache.get_secret_string("mysecretid")}')
    print(f'{cache.get_secret_string("mysecretid")}')


if __name__ == "__main__":
    main()
@goyalya
Copy link

goyalya commented Sep 26, 2022

We are looking into the request and will share more details.

@ibraheem-111
Copy link

Is there any update on this? I am also facing this issue.

We have secret rotation setup on our database, and the cache manager does refresh the value of the secret on exception or even when the TTL has elapsed.

@nitsujri
Copy link

nitsujri commented Sep 8, 2024

We just ran into this with the same (AWS Rotate Secret) and had to directly/manually manage the password failure.

For our use case, we're in Django, so we use refresh_secret_now and monkey patch by wrapping connect and _cursor to catch the "password authentication failed" error.

I'm not sure if there's a good "general" solution for this because most likely it would involve an SQS notification and then SecretsCache would have to subscribe to that.

@ibraheem-111
Copy link

@nitsujri Can you share some sample code for that? I am struggling with the same problem.

@nitsujri
Copy link

@ibraheem-111 Yeah this discussion helped me open source our library:

https://github.com/jenfi-eng/dj-db-rotated-secret

The code that pulls the secret:

# DJ_DB_ROTATED_SECRET_FUNC points wherever this function lives.
def get_db_creds_now():
    return SecretsHelper.by_name_json(f"/{core_network_name}/RDS_CREDENTIALS", break_cache=True)
   

# secrets_helper.py
import json
from aws_secretsmanager_caching import SecretCache

class SecretsHelper:
    cache = SecretCache()

    @classmethod
    def by_name(cls, name, break_cache=False):
        if break_cache:
            cls.cache.refresh_secret_now(name)

        return cls.cache.get_secret_string(name)

    @classmethod
    def by_name_json(cls, name, break_cache=False):
        secret_json_str = cls.by_name(name, break_cache)

        return json.loads(secret_json_str)

The above library combined with this code gives us rotation protection on both our Website & background Workers.

@ThirdEyeSqueegee
Copy link
Member

While secrets being stale after rotation is expected behavior and therefore not considered a bug, the issue of the decorators not refreshing secrets on subsequent calls is fixed by #59

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants