我有一个使用 AWS SDK Ruby v3 的 Ruby 应用程序,最近我添加了对使用 SSO 配置文件而不是静态“密钥 ID + 秘密”配置的支持。
新设置在一段时间内运行良好,直到令牌“过期”并且我开始出现
Aws::Errors::InvalidSSOToken
异常,此时用户需要手动运行 CLI 的 aws sso login
才能获取浏览器登录屏幕。
我希望跳过手动 AWS CLI 运行步骤 - 如果开发工具包可以直接执行
aws sso login
步骤(使用正确的配置文件)。
我可能可以使用正确的参数来实现
exec
- 但我想以“SDK 方式”实现。
是的,可以。您可以在收到
InvalidSSOToken
时添加错误处理程序,然后进行 SSO 身份验证。
我从未尝试过SDK方式。我尝试过
exec
cli 命令 aws sso login
(因为它更容易)。它将创建一个包含 cache.json
和 token
值的 expiresAt
文件。
这是我用作参考的项目:https://github.com/NeilJed/aws-sso-credentials/blob/master/awssso
这是您可以用作检查令牌是否过期的参考部分。 https://github.com/NeilJed/aws-sso-credentials/blob/master/awssso#L110-L137
这是通过 SDK 但使用 Python 执行此操作的另一个示例: https://stackoverflow.com/a/71850591/22277802
这不是一个完整的实现,而是我要进行的测试的一些草稿本。下面代码的当前状态是,运行后,
Aws
API 无需额外凭据即可工作,但我有一些担忧。
向 @tsal-troser 致敬,他在自己的回答中指出了用于创建此示例代码的 Python 示例,以及编写该 Python 代码的 @2ps。
require 'aws-sdk-core'
class SSOConfig
def initialize profile = nil
profile = 'default' if profile.to_s.empty?
@profile = profile
raise "No AWS config file found!" unless File.exists? "#{ENV['HOME']}/.aws/config"
@config = File.readlines("#{ENV['HOME']}/.aws/config").collect(&:chomp)
@profile_config = @config.select do |l|
(l =~ /^\[profile #{@profile}\]$/ .. l =~ /^(?!\[profile #{@profile}\])(\[|$)/) ? true : false
end
raise "Failed to find session for profile #{profile!}" if session.to_s.empty?
@session_config = @config.select do |l|
(l =~ /^\[sso-session #{session}\]$/ .. l =~ /^(?!\[sso-session #{session}\])(\[|$)/) ? true : false
end
end
def session
@profile_config.select do |l|
l =~ /^sso_session/
end.collect do |l|
(l.split /\s*=\s*/).last
end.first
end
def start_url
@session_config.select do |l|
l =~ /^sso_start_url/
end.collect do |l|
(l.split /\s*=\s*/).last
end.first
end
def account_id
@profile_config.select do |l|
l =~ /^sso_account_id/
end.collect do |l|
(l.split /\s*=\s*/).last
end.first
end
def region
'us-east-1' # can we use other regions?
end
def client_name
'MyClientName' # change to what you want
end
def try_renew_token
puts "SSO token has expired! Trying to re-authorize SSO session..."
oidc_client = Aws::SSOOIDC::Client.new(region: self.region)
creds = oidc_client.register_client(client_name: self.client_name, client_type: 'public')
auth = oidc_client.start_device_authorization(
client_id: creds.client_id,
client_secret: creds.client_secret,
start_url: self.start_url)
puts "Verification code: #{auth.user_code}"
puts "Open your browser with this url: #{auth.verification_uri_complete}"
puts "When complete, press ENTER here"
STDIN.getch
puts ""
token = oidc_client.create_token(
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
device_code: auth.device_code,
client_id: creds.client_id,
client_secret: creds.client_secret)
sso_client = Aws::SSO::Client.new(region: self.region)
account_roles = sso_client.list_account_roles(
access_token: token.access_token,
account_id: self.account_id)
role = account_roles.role_list.first
role_creds = sso_client.get_role_credentials(
role_name: role.role_name,
account_id: role.account_id,
access_token: token.access_token)
Aws.config[:credentials] = Class.new do
def initialize creds
@creds = creds
end
def credentials
Aws::Credentials.new(@creds.access_key_id, @creds.secret_access_key, @creds.session_token)
end
end.new(role_creds.role_credentials)
true
end
end
用法:抓住
Aws::Errors::InvalidSSOToken
时,拨打SSOConfig.new("your-profile").try_renew_token
。调用成功返回后,Aws.config[:credentials]
会加载凭据提供程序,该提供程序将返回正确的凭据。
~/.aws/sso/cache
或其他东西中写入一些内容。CredentialProvider
,而不是这种奇怪的黑客。false
。(我关闭了语法高亮,因为 StackOverflow 无法处理我的 Ruby 代码,而且颜色很乱)