-
Notifications
You must be signed in to change notification settings - Fork 94
feat: SSO creds resolver #1958
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
feat: SSO creds resolver #1958
Changes from 64 commits
6795e09
34110d2
d7f7973
5736a0e
d5d1673
b38d3fd
4cb29a8
5794bc3
d594231
4e91782
117fbe2
a42d5e0
7fdd73a
42bf26e
874db10
a15f5d1
3c7b1ec
3403985
2518d6d
d354c67
f930815
fd17646
24dcd28
4c102b7
2e2fe06
e5e0a72
79de694
1d91db1
11cc78f
8306959
e746831
02f072b
bd40a8c
e8124d4
a4a5cec
3e75e06
5fa33e4
e328aa1
612e765
e3a26f5
087e32c
bf0d9d7
89a1217
54bee08
d23ebcc
0f0af49
60b728c
56b21e7
3bfd6ba
595c264
7b92ee7
a894abd
39ed7d3
1bb811d
03d3e02
edb086b
483f959
dec8217
a06496b
16b4628
a29a275
bf2c873
241476b
7c86429
419e781
5821aa2
f0cdab3
43184a3
8ec0fc2
b304503
679f15d
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 |
|---|---|---|
|
|
@@ -161,6 +161,54 @@ private var runtimeTargets: [Target] { | |
| ], | ||
| path: "Sources/Core/AWSSDKIdentity/Sources/InternalAWSSTS" | ||
| ), | ||
| .target( | ||
| name: "InternalAWSSSO", | ||
| dependencies: [ | ||
|
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. Are these internal client dependencies the same list as for a public AWS service client? 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. Only difference is that public AWS service clients also depend on the internal client targets, but internal client targets don't depend on any other internal clients. |
||
| .clientRuntime, | ||
| .awsClientRuntime, | ||
| .smithyRetriesAPI, | ||
| .smithyRetries, | ||
| .smithy, | ||
| .smithyIdentity, | ||
| .smithyIdentityAPI, | ||
| .smithyEventStreamsAPI, | ||
| .smithyEventStreamsAuthAPI, | ||
| .smithyEventStreams, | ||
| .smithyChecksumsAPI, | ||
| .smithyChecksums, | ||
| .smithyWaitersAPI, | ||
| .awsSDKCommon, | ||
| .awsSDKIdentity, | ||
| .awsSDKHTTPAuth, | ||
| .awsSDKEventStreamsAuth, | ||
| .awsSDKChecksums, | ||
| ], | ||
| path: "Sources/Core/AWSSDKIdentity/Sources/InternalAWSSSO" | ||
| ), | ||
| .target( | ||
| name: "InternalAWSSSOOIDC", | ||
| dependencies: [ | ||
| .clientRuntime, | ||
| .awsClientRuntime, | ||
| .smithyRetriesAPI, | ||
| .smithyRetries, | ||
| .smithy, | ||
| .smithyIdentity, | ||
| .smithyIdentityAPI, | ||
| .smithyEventStreamsAPI, | ||
| .smithyEventStreamsAuthAPI, | ||
| .smithyEventStreams, | ||
| .smithyChecksumsAPI, | ||
| .smithyChecksums, | ||
| .smithyWaitersAPI, | ||
| .awsSDKCommon, | ||
| .awsSDKIdentity, | ||
| .awsSDKHTTPAuth, | ||
| .awsSDKEventStreamsAuth, | ||
| .awsSDKChecksums, | ||
| ], | ||
| path: "Sources/Core/AWSSDKIdentity/Sources/InternalAWSSSOOIDC" | ||
| ), | ||
| .target( | ||
| name: "AWSSDKChecksums", | ||
| dependencies: [.crt, .smithy, .clientRuntime, .smithyChecksumsAPI, .smithyChecksums, .smithyHTTPAPI], | ||
|
|
@@ -224,6 +272,8 @@ private func target(_ service: String) -> Target { | |
| .awsSDKEventStreamsAuth, | ||
| .awsSDKChecksums, | ||
| "InternalAWSSTS", | ||
| "InternalAWSSSO", | ||
| "InternalAWSSSOOIDC", | ||
| ], | ||
| path: "Sources/Services/\(service)/Sources/\(service)" | ||
| ) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,15 +5,19 @@ | |
| // SPDX-License-Identifier: Apache-2.0 | ||
|
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. Uses |
||
| // | ||
|
|
||
| import class AwsCommonRuntimeKit.CredentialsProvider | ||
| import protocol SmithyIdentity.AWSCredentialIdentityResolver | ||
| import struct Smithy.Attributes | ||
| import ClientRuntime | ||
| import protocol SmithyIdentity.AWSCredentialIdentityResolvedByCRT | ||
| import class Foundation.ProcessInfo | ||
| import enum Smithy.ClientError | ||
| @_spi(FileBasedConfig) import AWSSDKCommon | ||
|
|
||
| /// A credential identity resolver that resolves credentials using GetRoleCredentialsRequest to the AWS Single Sign-On Service to maintain short-lived sessions. | ||
| /// [Details link](https://docs.aws.amazon.com/sdkref/latest/guide/feature-sso-credentials.html) | ||
| public struct SSOAWSCredentialIdentityResolver: AWSCredentialIdentityResolvedByCRT { | ||
| public let crtAWSCredentialIdentityResolver: AwsCommonRuntimeKit.CredentialsProvider | ||
| public struct SSOAWSCredentialIdentityResolver: AWSCredentialIdentityResolver { | ||
| private let configFilePath: String? | ||
| private let credentialsFilePath: String? | ||
| private let profileName: String? | ||
|
|
||
| /// - Parameters: | ||
| /// - profileName: The profile name to use. If not provided it will be resolved internally via the `AWS_PROFILE` environment variable or defaulted to `default` if not configured. | ||
|
|
@@ -24,15 +28,74 @@ public struct SSOAWSCredentialIdentityResolver: AWSCredentialIdentityResolvedByC | |
| configFilePath: String? = nil, | ||
| credentialsFilePath: String? = nil | ||
| ) throws { | ||
| self.profileName = profileName | ||
| self.configFilePath = configFilePath | ||
| self.credentialsFilePath = credentialsFilePath | ||
| } | ||
|
|
||
| public func getIdentity(identityProperties: Attributes?) async throws -> AWSCredentialIdentity { | ||
| guard let identityProperties, let internalSSOClient = identityProperties.get( | ||
| key: InternalClientKeys.internalSSOClientKey | ||
| ) else { | ||
| throw AWSCredentialIdentityResolverError.failedToResolveAWSCredentials( | ||
| "SSOAWSCredentialIdentityResolver: " | ||
| + "Missing IdentityProvidingSSOClient in identity properties." | ||
| ) | ||
| } | ||
|
|
||
| let fileBasedConfig = try CRTFileBasedConfiguration( | ||
| configFilePath: configFilePath, | ||
| credentialsFilePath: credentialsFilePath | ||
| ) | ||
| self.crtAWSCredentialIdentityResolver = try AwsCommonRuntimeKit.CredentialsProvider(source: .sso( | ||
| bootstrap: SDKDefaultIO.shared.clientBootstrap, | ||
| tlsContext: SDKDefaultIO.shared.tlsContext, | ||
| fileBasedConfiguration: fileBasedConfig, | ||
| profileFileNameOverride: profileName | ||
| )) | ||
| let resolvedProfileName = self.profileName ?? ProcessInfo.processInfo.environment["AWS_PROFIE"] ?? "default" | ||
| let (accountID, roleName, region) = try fetchSSOConfigFromSharedConfigFile( | ||
| profileName: resolvedProfileName, | ||
| fileBasedConfig: fileBasedConfig | ||
| ) | ||
|
|
||
| let ssoToken = try await SSOBearerTokenIdentityResolver( | ||
| profileName: resolvedProfileName, | ||
| configFilePath: configFilePath | ||
| ).getIdentity(identityProperties: identityProperties) | ||
|
|
||
| return try await internalSSOClient.getCredentialsWithSSOToken( | ||
| region: region, | ||
| accessToken: ssoToken.token, | ||
| accountID: accountID, | ||
| roleName: roleName | ||
| ) | ||
| } | ||
|
|
||
| private func fetchSSOConfigFromSharedConfigFile( | ||
| profileName: String, | ||
| fileBasedConfig: CRTFileBasedConfiguration | ||
| ) throws -> (accountID: String, roleName: String, region: String) { | ||
| // Get `sso_account_id` and `sso_role_name` properties. | ||
| let ssoAccountID = try getProperty(profileName, .profile, "sso_account_id", fileBasedConfig) | ||
| let ssoRoleName = try getProperty(profileName, .profile, "sso_role_name", fileBasedConfig) | ||
|
|
||
| // Get `sso_region` property from sso-session section referenced by the profile section.. | ||
| let ssoSessionName = try getProperty(profileName, .profile, "sso_session", fileBasedConfig) | ||
| let ssoRegion = try getProperty(ssoSessionName, .ssoSession, "sso_region", fileBasedConfig) | ||
|
|
||
| return (ssoAccountID, ssoRoleName, ssoRegion) | ||
| } | ||
|
|
||
| private func getProperty( | ||
| _ sectionName: String, | ||
| _ sectionType: CRTFileBasedConfiguration.SectionType, | ||
| _ propertyName: String, | ||
| _ fileBasedConfig: CRTFileBasedConfiguration | ||
| ) throws -> String { | ||
| guard let value = fileBasedConfig | ||
| .getSection(name: sectionName, sectionType: sectionType)? | ||
| .getProperty(name: propertyName)? | ||
| .value | ||
| else { | ||
| throw ClientError.dataNotFound( | ||
| "Failed to retrieve \(propertyName) from \(sectionName) \(sectionType) section." | ||
| ) | ||
| } | ||
| return value | ||
| } | ||
| } | ||
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.
Adds two new targets:
InternalAWSSSOandInternalAWSSSOOIDC. Just likeInternalAWSSTS, they are service clients generated for internal use with only the couple operations needed for the SSO credential resolver.