-
Notifications
You must be signed in to change notification settings - Fork 18
Implement a configurable credentials resolver chain #452
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
Open
alextwoods
wants to merge
11
commits into
smithy-lang:develop
Choose a base branch
from
alextwoods:credentials_resolver_chain
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 7 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
2cd5625
Implement a configurable credentials resolver chain
alextwoods 368fd21
Add test cases
alextwoods 87f73ba
Fix lint
alextwoods c33518b
Update packages/smithy-aws-core/src/smithy_aws_core/credentials_resol…
alextwoods e5b55cc
Merge branch 'develop' into credentials_resolver_chain
alextwoods 4351de1
Updates to typing
alextwoods b325e70
Refactor Sources into a class/Protocol
alextwoods d14e85e
Doc string update
alextwoods 086d9ce
Improve tests
alextwoods ef5e169
Fix doc
alextwoods b7412fb
Update packages/smithy-aws-core/src/smithy_aws_core/credentials_resol…
alextwoods File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
packages/smithy-aws-core/src/smithy_aws_core/credentials_resolvers/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
packages/smithy-aws-core/src/smithy_aws_core/credentials_resolvers/chain.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
from collections.abc import Sequence | ||
|
||
from smithy_core.aio.interfaces.identity import IdentityResolver | ||
from smithy_core.exceptions import SmithyIdentityException | ||
from smithy_core.interfaces.identity import IdentityProperties | ||
|
||
from smithy_aws_core.credentials_resolvers.environment import ( | ||
EnvironmentCredentialsSource, | ||
) | ||
from smithy_aws_core.credentials_resolvers.imds import IMDSCredentialsSource | ||
from smithy_aws_core.credentials_resolvers.interfaces import ( | ||
AwsCredentialsConfig, | ||
CredentialsSource, | ||
) | ||
from smithy_aws_core.identity import AWSCredentialsIdentity, AWSCredentialsResolver | ||
|
||
_DEFAULT_SOURCES: Sequence[CredentialsSource] = ( | ||
EnvironmentCredentialsSource(), | ||
IMDSCredentialsSource(), | ||
) | ||
|
||
|
||
class CredentialsResolverChain( | ||
IdentityResolver[AWSCredentialsIdentity, IdentityProperties] | ||
): | ||
"""Resolves AWS Credentials from system environment variables.""" | ||
|
||
def __init__( | ||
self, | ||
*, | ||
config: AwsCredentialsConfig, | ||
sources: Sequence[CredentialsSource] = _DEFAULT_SOURCES, | ||
): | ||
self._config = config | ||
self._sources: Sequence[CredentialsSource] = sources | ||
self._credentials_resolver: AWSCredentialsResolver | None = None | ||
|
||
async def get_identity( | ||
self, *, identity_properties: IdentityProperties | ||
) -> AWSCredentialsIdentity: | ||
if self._credentials_resolver is not None: | ||
return await self._credentials_resolver.get_identity( | ||
identity_properties=identity_properties | ||
) | ||
|
||
for source in self._sources: | ||
if source.is_available(config=self._config): | ||
self._credentials_resolver = source.build_resolver(config=self._config) | ||
return await self._credentials_resolver.get_identity( | ||
identity_properties=identity_properties | ||
) | ||
|
||
raise SmithyIdentityException( | ||
"None of the configured credentials sources were able to resolve credentials." | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
packages/smithy-aws-core/src/smithy_aws_core/credentials_resolvers/interfaces.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
from typing import Protocol | ||
|
||
from smithy_http.aio.interfaces import HTTPClient | ||
|
||
from smithy_aws_core.identity import AWSCredentialsResolver | ||
|
||
|
||
class AwsCredentialsConfig(Protocol): | ||
"""Configuration required for resolving credentials.""" | ||
|
||
http_client: HTTPClient | ||
"""A static endpoint to use for the request.""" | ||
alextwoods marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
class CredentialsSource(Protocol): | ||
def is_available(self, config: AwsCredentialsConfig) -> bool: | ||
"""Returns True if credentials are available from this source.""" | ||
... | ||
|
||
def build_resolver(self, config: AwsCredentialsConfig) -> AWSCredentialsResolver: | ||
"""Builds a credentials resolver for the given configuration.""" | ||
... |
97 changes: 97 additions & 0 deletions
97
packages/smithy-aws-core/tests/unit/credentials_resolvers/test_credentials_resolver_chain.py
jonathan343 marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
from dataclasses import dataclass | ||
from unittest.mock import Mock | ||
|
||
import pytest | ||
from smithy_aws_core.credentials_resolvers import ( | ||
CredentialsResolverChain, | ||
StaticCredentialsResolver, | ||
) | ||
from smithy_aws_core.credentials_resolvers.environment import ( | ||
EnvironmentCredentialsSource, | ||
) | ||
from smithy_aws_core.credentials_resolvers.interfaces import ( | ||
AwsCredentialsConfig, | ||
CredentialsSource, | ||
) | ||
from smithy_aws_core.identity import AWSCredentialsIdentity, AWSCredentialsResolver | ||
from smithy_core.exceptions import SmithyIdentityException | ||
from smithy_core.interfaces.identity import IdentityProperties | ||
from smithy_http.aio.interfaces import HTTPClient | ||
|
||
|
||
@dataclass | ||
class Config: | ||
http_client: HTTPClient | ||
|
||
def __init__(self): | ||
self.http_client = Mock(spec=HTTPClient) # type: ignore | ||
|
||
|
||
async def test_no_sources_resolve(): | ||
resolver_chain = CredentialsResolverChain(sources=[], config=Config()) | ||
with pytest.raises(SmithyIdentityException): | ||
await resolver_chain.get_identity(identity_properties=IdentityProperties()) | ||
|
||
|
||
async def test_env_credentials_resolver_not_set(monkeypatch: pytest.MonkeyPatch): | ||
monkeypatch.delenv("AWS_ACCESS_KEY_ID", raising=False) | ||
monkeypatch.delenv("AWS_SECRET_ACCESS_KEY", raising=False) | ||
resolver_chain = CredentialsResolverChain( | ||
sources=[EnvironmentCredentialsSource()], config=Config() | ||
) | ||
|
||
with pytest.raises(SmithyIdentityException): | ||
await resolver_chain.get_identity(identity_properties=IdentityProperties()) | ||
|
||
|
||
async def test_env_credentials_resolver_partial(monkeypatch: pytest.MonkeyPatch): | ||
monkeypatch.setenv("AWS_ACCESS_KEY_ID", "akid") | ||
monkeypatch.delenv("AWS_SECRET_ACCESS_KEY", raising=False) | ||
resolver_chain = CredentialsResolverChain( | ||
sources=[EnvironmentCredentialsSource()], config=Config() | ||
) | ||
|
||
with pytest.raises(SmithyIdentityException): | ||
await resolver_chain.get_identity(identity_properties=IdentityProperties()) | ||
|
||
|
||
async def test_env_credentials_resolver_success(monkeypatch: pytest.MonkeyPatch): | ||
monkeypatch.setenv("AWS_ACCESS_KEY_ID", "akid") | ||
monkeypatch.setenv("AWS_SECRET_ACCESS_KEY", "secret") | ||
resolver_chain = CredentialsResolverChain( | ||
sources=[EnvironmentCredentialsSource()], config=Config() | ||
) | ||
|
||
credentials = await resolver_chain.get_identity( | ||
identity_properties=IdentityProperties() | ||
) | ||
assert credentials.access_key_id == "akid" | ||
assert credentials.secret_access_key == "secret" | ||
|
||
|
||
async def test_custom_sources_with_static_credentials(): | ||
static_credentials = AWSCredentialsIdentity( | ||
access_key_id="static_akid", | ||
secret_access_key="static_secret", | ||
) | ||
static_resolver = StaticCredentialsResolver(credentials=static_credentials) | ||
|
||
class TestStaticSource(CredentialsSource): | ||
def is_available(self, config: AwsCredentialsConfig) -> bool: | ||
return True | ||
|
||
def build_resolver( | ||
self, config: AwsCredentialsConfig | ||
) -> AWSCredentialsResolver: | ||
return static_resolver | ||
|
||
resolver_chain = CredentialsResolverChain( | ||
sources=[TestStaticSource()], | ||
config=Config(), # type: ignore | ||
) | ||
|
||
credentials = await resolver_chain.get_identity( | ||
identity_properties=IdentityProperties() | ||
) | ||
assert credentials.access_key_id == "static_akid" | ||
assert credentials.secret_access_key == "static_secret" |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.