-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Explicit profile overrides environment variables #486
Conversation
@@ -275,7 +277,7 @@ class EnvProvider(CredentialProvider): | |||
# AWS_SESSION_TOKEN is what other AWS SDKs have standardized on. | |||
TOKENS = ['AWS_SECURITY_TOKEN', 'AWS_SESSION_TOKEN'] | |||
|
|||
def __init__(self, environ=None, mapping=None): | |||
def __init__(self, environ=None, mapping=None, profile_name=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the wrong level of abstraction and couples profiles to retrieving environment variables when they don't need to be. An env provider should just be a simple object that pulls credentials from environment variables and that's it. If something up the call stack wants to either re-arrange cred providers or ignore what this class returns, that's another thing, but this class should just stay minimal.
It also gives this class weird semantics. If you pass a profile_name to this class, then it won't do anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would something along these lines be more like what you were thinking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah something along those lines seems better abstracted to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. That would look better.
We also don't really clarify what precedence the EDIT: To clarify, what are we saying is the expected behavior for these cases:
If we're consistent with We'd probably also want to double check that given:
That the end result is that we pull creds from |
Coverage increased (+0.03%) to 94.58% when pulling bb67322b02bc4dd22ef5ccfe7ac87324d9fb2a16 on danielgtaylor:explicit-profile into 2eee0f1 on boto:develop. |
Here is the precedence leveling that I think we should be using:
The way I see it is that precedence should be based off of what is the most explicit. Similarly how access key in code is taking precedence of profile_name in code, access key in environment variable should take precedence over profile name in environment variable because the user is being more explicit and it is consistent with the code parallel of precedence. I honestly don't think But yet again the docs is a little vague in that it really does not say where its precedence lies when it describes it as "name of the CLI profile to use". Let me know what you guys think. |
Spoke with @kyleknap this morning about this and I think we both agree. To put this into more concrete examples, if these are set: Code / arguments:
Environment
The case we really need to get working is this one (which this PR solves):
$ AWS_ACCESS_KEY_ID=abc123 aws --profile dev s3 ls Thoughts? |
Sorry, just catching up on this now. To summarize, it sounds like we're saying: For any given precedence level (i.e config file, env vars, cmdline args, etc), the akid/sak will always trump a profile value if all three are specified at the same precedence value. A consequence of this is that in order to get a "profile" to take, you have to specify it at the next precedence level (or higher) of whatever is explicitly specifying the akid/skid. So if akid/sak are in env vars, profile has to be as a cmd line option or in boto3 via a method arg. In which case, I think that makes sense. Thanks for looking into this. I would suggest adding integration tests for these cases as well. |
This changes the behavior of environment variable credential loading to function as described in aws/aws-cli#113. Here is what this looks like for both the CLI and Botocore/Boto 3: CLI: ```bash $ AWS_ACCESS_KEY_ID=foo AWS_SECRET_ACCESS_KEY=bar aws s3 ls $ AWS_ACCESS_KEY_ID=foo AWS_SECRET_ACCESS_KEY=bar aws --profile dev s3 ls ``` Python: ```python $ AWS_ACCESS_KEY_ID=foo AWS_SECRET_ACCESS_KEY=bar python >>> import boto3 >>> boto3.setup_default_session(profile_name='dev') >>> # The following will use the profile, not the env vars! >>> s3dev = boto3.resource('s3') ``` Added a test and a new log message to ensure it's obvious what is happening.
841f54c
to
f3114d7
Compare
f3114d7
to
856eaec
Compare
'AWS_SECRET_ACCESS_KEY', | ||
'BOTO_DEFAULT_PROFILE']: | ||
if name in os.environ: | ||
del os.environ[name] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is general test case best practice advice: Do not leave global state modified outside the scope of a test. It's ok to mess with global state in a test if there's no better way to test what you need to test, but you have to put the state back to the way it initially was.
Here, if the vars you're deleting were defined in os.environ before the test, this setUp() is deleting these values and not restoring them after the test executes. This can lead to all sorts of hard to track down problems where the test order may affect whether or not a test passes depending on if it passes before/after the global state modification.
That being, said, just use BaseEnvVar
to handle the patching of env vars for you.
I think your integ tests cover a good set of cases, I just have some comments on how the tests themselves are implemented. Also, there are no unit tests for this. While I think we want the integ tests to ensure we don't regress as we refactor some of the internals, I still think this change should have a unit test. We should be able to call into The actual code change itself looks good. |
# or credentials. | ||
providers.insert(0, EnvProvider()) | ||
else: | ||
logger.info('Skipping environment variable credential check' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems more like a debug message. We'll still log which provider ultimately gives creds, but the fact that we're disabling a check seems mostly of interest to a dev.
@jamesls please take another look. |
self.session.profile = None | ||
resolver = credentials.create_credential_resolver(self.session) | ||
|
||
found = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or to assert that all the providers are not an instance of the env provider, you can just use: self.assertTrue(all(not isinstance(p, EnvProvider) for p in p.providers))
Looks good, just had a small suggestion. Thanks for updating. |
Explicit profile overrides environment variables.
This changes the behavior of environment variable credential loading to
function as described in aws/aws-cli#113. Here is what this looks like
for both the CLI and Botocore/Boto 3:
CLI:
Python:
Added a test and a new log message to ensure it's obvious what is happening.
cc @jamesls @kyleknap