-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Allow reuse of the current profile's sso_session while providing a different sso_role_name or sso_account_id #3120
Comments
Thanks for submitting - this is an interesting, but I think valid use case. In general resolution of defaults (including the profile, credential/token providers, ect) is complex and we generally want to keep those details as api private so I don't necessarily think we should make Can you provide more details on how you are creating and using clients? In general, a user may have more than 1 sso-sessions configured and which would get used is based on configured profile (which in client creation, is resolved from various possible locations). |
Thanks for the the response!
I totally understand. I would much rather rely on the SDK to do the right thing with respect to finding the right credentials. I didn't know that I can access a client's
Sure. This is a utility script used by many different developers at my organization to make changes to SSM parameters in one of several AWS accounts (for example, the
and I could hard-code the appropriate roles: account_name = ... # get account name from command line
roles = {
sandbox: 'arn:aws:iam::111111111111:role/ConfigureSSM',
production: 'arn:aws:iam::222222222222:role/ConfigureSSM'
}
ssm = Aws::SSM::Client.new(role_arn: roles[account_name]) This meant that the script didn't care about the developer's AWS CLI configuration. As long as the developer provided credentials that could assume the necessary role, the script worked. Now, we'd like to switch from ordinary IAM roles in the member accounts to SSO permission sets, while keeping the same convenient developer experience. The developer will still call the script as before, but now script will hard-code permission sets and account IDs: account_name = ... # get account name from command line
permission_sets = {
sandbox: {
sso_account_id: '111111111111',
sso_role_name: 'ConfigureSSM',
sso_region: 'us-west-2',
sso_session: '' # required - but what do I put here?
},
production: {
sso_account_id: '111111111111',
sso_role_name: 'ConfigureSSM',
sso_region: 'us-west-2',
sso_session: '' # required - but what do I put here?
},
}
credentials = Aws::SSOCredentials.new(**permission_sets[account_name])
ssm = Aws::SSM::Client.new(credentials:) I opened this issue when I could not figure out how to keep the same convenient developer experience we had when using roles directly.
Absolutely, and I would rather my script not know anything about which sso-session is used. Ideally, the script just knows it needs to use permission set |
That makes sense and I think I may have a relatively simple solution for you: AssumeRoleCredentials. You can provide a credentials = Aws::AssumeRoleCredentials.new(role_arn: roles[account_name], role_session_name: 'whatever-session-name-you-want') # will use the users default credentials to assume the role
ssm = Aws::SSM::Client.new(credentials:) |
Thanks for the suggestion! I don't think I was clear, though: we currently use role assumption with no issue. The problem is that we want to switch from using roles we provision in each account, to using IAM Identity Center permission sets, and eliminate the existing roles. As you demonstrated, it's easy and seamless to assume a role whose ARN you know, but it's much more complex to assume a permission set whose account ID and name you know, without relying on details of the developer's |
That makes sense. I think we don't want to expose any of the shared config or default resolution behavior required for this. However, I believe you can get this functionality, using only public functionality by extending the SSOCredentials. Something like: class SSOCredsDefaultToken < Aws::SSOCredentials
def initialize(options = nil)
@legacy = false
@sso_role_name = options.delete(:sso_role_name)
@sso_account_id = options.delete(:sso_account_id)
@sso_region = options.delete(:sso_region)
@client = options.delete(:client)
unless @client
client_opts = {}
options.each_pair { |k,v| client_opts[k] = v unless CLIENT_EXCLUDE_OPTIONS.include?(k) }
client_opts[:region] = @sso_region
client_opts[:credentials] = nil
@client = Aws::SSO::Client.new(client_opts)
end
# get default token_provider resolved by normal chain
@token_provider = @client.config.token_provider
raise 'No token provider configured' unless @token_provider
# do not call super, instead just call refresh
@async_refresh = true
refresh
end
end Its then fairly easy to use as: credentials = SSOCredsDefaultToken.new(
sso_account_id: '222222222222',
sso_role_name: 'PermissionSetB',
sso_region: 'us-west-2'
# No need to put sso_session
)
sts = Aws::STS::Client.new(credentials:) I think the other alternative would be to just rely on private functionality and do something like:
|
@ravron - did either of those suggestions work for your use case? |
Thank you for the suggestions! Due to the complexity of using permission sets for this purpose, I've decided to simply keep ordinary roles which the user's typical permission set will have the ability to assume. It's a shame it wasn't easier to make permission sets work, but continuing to use roles means the script will work for all users without extra complexity. I really appreciate your help here. |
This issue is now closed. Comments on closed issues are hard for our team to see. |
Describe the feature
When creating an instance of
SSOCredentials
to provide to an API client, I would like a way to indicate that the instance should look up and use thesso_session
associated with the current profile, rather than passing it myself.Use Case
When creating an instance of
SSOCredentials
to provide to an API client, I would like to select the permission set used by providing thesso_role_name
. However, doing so requires that I know the name of the user's configuredsso_session
, which I generally do not, so I must needlessly require that users of the tool I'm building name theirsso_session
a particular string.For example, imagine a user has this
~/.aws/config
:If
PermissionSetA
has the necessary permissions to perform my task, this is easy. The user first runsaws sso login
and the SSO token is cached to disk. My code can simply create a client without any options and rely on theCredentialProviderChain
to find the SSO token and create a validSSOCredentials
instance:However, consider the case where I would like to use
PermissionSetB
in account 222222222222. I expect that the user's existing SSO token should work to assume thatPermissionSetB
, so I simply need to specify a different permission set:The user's SSO session is named
unusual-session-name
, and theSharedConfig
knows it. But, as far as I can tell, that information isn't exposed.SharedConfig
has bothsso_credentials_from_config
andsso_token_from_config
, but both are private. Even if they were public, they wouldn't quite work:sso_credentials_from_config
returns anSSOCredentials
that has the permission set baked in, whilesso_token_from_config
returns anSSOTokenProvider
that cannot be used to construct anSSOCredentials
.Proposed Solution
The first solution that comes to mind requires two changes:
SharedConfig#sso_token_from_config
public. This would make it possible to get anSSOTokenProvider
corresponding to the user's current AWS profile and SSO session. This is challenging, though, because all ofSharedConfig
is currently a private API.SSOCredentials.initialize
to accept a:token_provider
option. If passed,:sso_session
is no longer needed, and the providedSSOTokenProvider
is used instead of creating a new one.I'm not sure what's a clean option here, though, and I'm looking for feedback.
Other Information
No response
Acknowledgements
SDK version used
3.188.0
Environment details (OS name and version, etc.)
macOS 14.6.1
The text was updated successfully, but these errors were encountered: