-
Notifications
You must be signed in to change notification settings - Fork 55
feat(rt)!: implement kmp profile credentials provider #478
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
Changes from all commits
b12f814
48dc8df
c0f7961
6a213cc
613032d
a6ae977
8934ffa
acd8b82
680107a
d1e355d
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 |
|---|---|---|
|
|
@@ -38,6 +38,8 @@ import aws.smithy.kotlin.runtime.util.PlatformEnvironProvider | |
| */ | ||
| private const val AWS_CONTAINER_SERVICE_ENDPOINT = "http://169.254.170.2" | ||
|
|
||
| private const val PROVIDER_NAME = "EcsContainer" | ||
|
|
||
| /** | ||
| * A [CredentialsProvider] that sources credentials from a local metadata service. | ||
| * | ||
|
|
@@ -46,13 +48,20 @@ private const val AWS_CONTAINER_SERVICE_ENDPOINT = "http://169.254.170.2" | |
| * | ||
| * For more information on configuring ECS credentials see [IAM Roles for tasks](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html) | ||
| * | ||
| * @param platform the platform provider | ||
| * @param httpClientEngine the [HttpClientEngine] instance to use to make requests. NOTE: This engine's resources and lifetime | ||
| * are NOT managed by the provider. Caller is responsible for closing. | ||
| * | ||
| */ | ||
| public class EcsCredentialsProvider internal constructor( | ||
| private val platform: PlatformEnvironProvider, | ||
| private val httpClientEngine: HttpClientEngine | ||
| httpClientEngine: HttpClientEngine? = null | ||
| ) : CredentialsProvider, Closeable { | ||
|
|
||
| public constructor() : this(Platform, CrtHttpEngine()) | ||
| public constructor() : this(Platform) | ||
|
|
||
| private val manageEngine = httpClientEngine == null | ||
|
Contributor
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. style IMO
Contributor
Author
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. Yeah true, I made it I kind of expect this is going to change when we decide on our ownership direction |
||
| private val httpClientEngine = httpClientEngine ?: CrtHttpEngine() | ||
|
|
||
| private val retryMiddleware = run { | ||
| val tokenBucket = StandardRetryTokenBucket(StandardRetryTokenBucketOptions.Default) | ||
|
|
@@ -147,9 +156,12 @@ public class EcsCredentialsProvider internal constructor( | |
| } | ||
|
|
||
| override fun close() { | ||
| httpClientEngine.close() | ||
| if (manageEngine) { | ||
| httpClientEngine.close() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private class EcsCredentialsDeserializer : HttpDeserialize<Credentials> { | ||
| override suspend fun deserialize(context: ExecutionContext, response: HttpResponse): Credentials { | ||
| val payload = response.body.readAll() ?: throw CredentialsProviderException("HTTP credentials response did not contain a payload") | ||
|
|
@@ -159,7 +171,8 @@ private class EcsCredentialsDeserializer : HttpDeserialize<Credentials> { | |
| resp.accessKeyId, | ||
| resp.secretAccessKey, | ||
| resp.sessionToken, | ||
| resp.expiration | ||
| resp.expiration, | ||
| PROVIDER_NAME | ||
| ) | ||
| is JsonCredentialsResponse.Error -> throw CredentialsProviderException("Error retrieving credentials from container service: code=${resp.code}; message=${resp.message}") | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| /* | ||
| * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| * SPDX-License-Identifier: Apache-2.0. | ||
| */ | ||
|
|
||
| package aws.sdk.kotlin.runtime.auth.credentials.profile | ||
|
|
||
| import aws.sdk.kotlin.runtime.auth.credentials.Credentials | ||
|
|
||
| /** | ||
| * A standalone member of the profile chain. Leaf providers do not require | ||
| * input credentials to provide their own credentials (e.g. IMDS, ECS, Environment, etc) | ||
| */ | ||
| internal sealed class LeafProvider { | ||
|
Contributor
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. question it's not connecting for me, what meaning does 'leaf' mean for this type? Is it that it's terminal, as in a leaf in a tree?
Contributor
Author
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. yeah the provider that doesn't depend on any other providers. In the Rust implementation they called it |
||
|
|
||
| /** | ||
| * A profile that specifies a named credentials source | ||
| * e.g. `credential_source = Ec2InstanceMetadata` | ||
| */ | ||
| data class NamedSource(val name: String) : LeafProvider() | ||
|
|
||
| /** | ||
| * A profile with explicitly configured access keys | ||
| * | ||
| * Example | ||
| * ```ini | ||
| * [profile C] | ||
| * aws_access_key_id = AKID | ||
| * aws_secret_access_key = secret | ||
| * ``` | ||
| */ | ||
| data class AccessKey(val credentials: Credentials) : LeafProvider() | ||
|
|
||
| /** | ||
| * A provider that uses OIDC web identity tokens | ||
| * | ||
| * Example | ||
| * ```ini | ||
| * [profile W] | ||
| * role_arn = arn:aws:iam:123456789:role/example | ||
| * web_identity_token_file = /path/to/token.jwt | ||
| * ``` | ||
| */ | ||
| data class WebIdentityTokenRole( | ||
| val roleArn: String, | ||
| val webIdentityTokenFile: String, | ||
| val sessionName: String? = null | ||
| ) : LeafProvider() | ||
|
|
||
| /** | ||
| * A provider that uses AWS SSO | ||
| * | ||
| * Example | ||
| * ```ini | ||
| * [profile W] | ||
| * sso_start_url = https://my-sso-portal.awsapps.com/start | ||
| * sso_region = us-east-1 | ||
| * sso_account_id = 123456789011 | ||
| * sso_role_name = readOnly | ||
| * region = us-west-2 | ||
| * ``` | ||
| */ | ||
| data class Sso( | ||
| val ssoStartUrl: String, | ||
| val ssoRegion: String, | ||
| val ssoAccountId: String, | ||
| val ssoRoleName: String | ||
| ) : LeafProvider() | ||
| } | ||
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.
Question: Would using the class name be simpler than custom names for each provider?
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.
Provider names are actually called out in an SEP