-
Couldn't load subscription status.
- Fork 13
feat: adding expiration time for secret cache in secret manager plugin #906
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -17,11 +17,13 @@ | |||||
| from json import JSONDecodeError, loads | ||||||
| from re import search | ||||||
| from types import SimpleNamespace | ||||||
| from typing import TYPE_CHECKING, Callable, Dict, Optional, Set, Tuple | ||||||
| from typing import TYPE_CHECKING, Callable, Optional, Set, Tuple | ||||||
|
|
||||||
| import boto3 | ||||||
| from botocore.exceptions import ClientError, EndpointConnectionError | ||||||
|
|
||||||
| from aws_advanced_python_wrapper.utils.cache_map import CacheMap | ||||||
|
|
||||||
| if TYPE_CHECKING: | ||||||
| from boto3 import Session | ||||||
| from aws_advanced_python_wrapper.driver_dialect import DriverDialect | ||||||
|
|
@@ -46,8 +48,10 @@ class AwsSecretsManagerPlugin(Plugin): | |||||
| _SUBSCRIBED_METHODS: Set[str] = {"connect", "force_connect"} | ||||||
|
|
||||||
| _SECRETS_ARN_PATTERN = r"^arn:aws:secretsmanager:(?P<region>[^:\n]*):[^:\n]*:([^:/\n]*[:/])?(.*)$" | ||||||
| _ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365 | ||||||
|
|
||||||
| _secrets_cache: Dict[Tuple, SimpleNamespace] = {} | ||||||
| _secret: Optional[SimpleNamespace] = None | ||||||
| _secrets_cache: CacheMap[Tuple, SimpleNamespace] = CacheMap() | ||||||
| _secret_key: Tuple = () | ||||||
|
|
||||||
| @property | ||||||
|
|
@@ -94,7 +98,13 @@ def force_connect( | |||||
| return self._connect(props, force_connect_func) | ||||||
|
|
||||||
| def _connect(self, props: Properties, connect_func: Callable) -> Connection: | ||||||
| secret_fetched: bool = self._update_secret() | ||||||
| token_expiration_sec: int = WrapperProperties.SECRETS_MANAGER_EXPIRATION.get_int(props) | ||||||
| # if value is less than 0, default to one year | ||||||
| if token_expiration_sec < 0: | ||||||
| token_expiration_sec = AwsSecretsManagerPlugin._ONE_YEAR_IN_SECONDS | ||||||
| token_expiration_ns = token_expiration_sec * 1_000_000_000 | ||||||
|
|
||||||
| secret_fetched: bool = self._update_secret(token_expiration_ns=token_expiration_ns) | ||||||
|
|
||||||
| try: | ||||||
| self._apply_secret_to_properties(props) | ||||||
|
|
@@ -105,7 +115,7 @@ def _connect(self, props: Properties, connect_func: Callable) -> Connection: | |||||
| raise AwsWrapperError( | ||||||
| Messages.get_formatted("AwsSecretsManagerPlugin.ConnectException", e)) from e | ||||||
|
|
||||||
| secret_fetched = self._update_secret(True) | ||||||
| secret_fetched = self._update_secret(token_expiration_ns=token_expiration_ns, force_refetch=True) | ||||||
|
|
||||||
| if secret_fetched: | ||||||
| try: | ||||||
|
|
@@ -117,9 +127,10 @@ def _connect(self, props: Properties, connect_func: Callable) -> Connection: | |||||
| unhandled_error)) from unhandled_error | ||||||
| raise AwsWrapperError(Messages.get_formatted("AwsSecretsManagerPlugin.FailedLogin", e)) from e | ||||||
|
|
||||||
| def _update_secret(self, force_refetch: bool = False) -> bool: | ||||||
| def _update_secret(self, token_expiration_ns: int, force_refetch: bool = False) -> bool: | ||||||
| """ | ||||||
| Called to update credentials from the cache, or from the AWS Secrets Manager service. | ||||||
| :param token_expiration_ns: Expiration time in nanoseconds for secret stored in cache. | ||||||
| :param force_refetch: Allows ignoring cached credentials and force fetches the latest credentials from the service. | ||||||
| :return: `True`, if credentials were fetched from the service. | ||||||
| """ | ||||||
|
|
@@ -135,7 +146,7 @@ def _update_secret(self, force_refetch: bool = False) -> bool: | |||||
| try: | ||||||
| self._secret = self._fetch_latest_credentials() | ||||||
| if self._secret: | ||||||
| AwsSecretsManagerPlugin._secrets_cache[self._secret_key] = self._secret | ||||||
| AwsSecretsManagerPlugin._secrets_cache.put(self._secret_key, self._secret, token_expiration_ns) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Based on the way CacheMap checks for expiration: This should be
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Put already adds the time.perf_counter_ns()
|
||||||
| fetched = True | ||||||
| except (ClientError, AttributeError) as e: | ||||||
| logger.debug("AwsSecretsManagerPlugin.FailedToFetchDbCredentials", e) | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.