Skip to content

Commit 1ed3546

Browse files
authored
feat: add system properties credentials provider & include it in default credentials provider chain (#1037)
1 parent b340f2c commit 1ed3546

File tree

11 files changed

+157
-7
lines changed

11 files changed

+157
-7
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "ec4b3c6c-c63f-499d-a032-026139b4627e",
3+
"type": "feature",
4+
"description": "Add `SystemPropertyCredentialsProvider` and make it first in default chain credentials provider",
5+
"issues": [
6+
"awslabs/aws-sdk-kotlin#1033"
7+
]
8+
}

aws-runtime/aws-config/api/aws-config.api

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,13 @@ public final class aws/sdk/kotlin/runtime/auth/credentials/StsWebIdentityCredent
161161
public static synthetic fun fromEnvironment-TUY-ock$default (Laws/sdk/kotlin/runtime/auth/credentials/StsWebIdentityCredentialsProvider$Companion;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JLaws/smithy/kotlin/runtime/util/PlatformProvider;Laws/smithy/kotlin/runtime/http/engine/HttpClientEngine;ILjava/lang/Object;)Laws/sdk/kotlin/runtime/auth/credentials/StsWebIdentityCredentialsProvider;
162162
}
163163

164+
public final class aws/sdk/kotlin/runtime/auth/credentials/SystemPropertyCredentialsProvider : aws/smithy/kotlin/runtime/auth/awscredentials/CredentialsProvider {
165+
public fun <init> ()V
166+
public fun <init> (Lkotlin/jvm/functions/Function1;)V
167+
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
168+
public fun resolve (Laws/smithy/kotlin/runtime/util/Attributes;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
169+
}
170+
164171
public final class aws/sdk/kotlin/runtime/auth/credentials/internal/ManagedBearerTokenProviderKt {
165172
public static final fun manage (Laws/smithy/kotlin/runtime/http/auth/CloseableBearerTokenProvider;)Laws/smithy/kotlin/runtime/http/auth/BearerTokenProvider;
166173
}

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/DefaultChainCredentialsProvider.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class DefaultChainCredentialsProvider constructor(
5252
private val engine = httpClient ?: DefaultHttpEngine()
5353

5454
private val chain = CredentialsProviderChain(
55+
SystemPropertyCredentialsProvider(platformProvider::getProperty),
5556
EnvironmentCredentialsProvider(platformProvider::getenv),
5657
ProfileCredentialsProvider(profileName = profileName, platformProvider = platformProvider, httpClient = engine, region = region),
5758
// STS web identity provider can be constructed from either the profile OR 100% from the environment
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package aws.sdk.kotlin.runtime.auth.credentials
7+
8+
import aws.sdk.kotlin.runtime.config.AwsSdkSetting
9+
import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
10+
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider
11+
import aws.smithy.kotlin.runtime.telemetry.logging.trace
12+
import aws.smithy.kotlin.runtime.util.Attributes
13+
import aws.smithy.kotlin.runtime.util.PlatformProvider
14+
import kotlin.coroutines.coroutineContext
15+
16+
private const val PROVIDER_NAME = "SystemProperties"
17+
18+
private val ACCESS_KEY_ID = AwsSdkSetting.AwsAccessKeyId.sysProp
19+
private val SECRET_ACCESS_KEY = AwsSdkSetting.AwsSecretAccessKey.sysProp
20+
private val SESSION_TOKEN = AwsSdkSetting.AwsSessionToken.sysProp
21+
22+
/**
23+
* A [CredentialsProvider] which reads `aws.accessKeyId`, `aws.secretAccessKey`, and `aws.sessionToken` from system properties.
24+
*/
25+
public class SystemPropertyCredentialsProvider
26+
public constructor(private val getProperty: (String) -> String? = PlatformProvider.System::getProperty) : CredentialsProvider {
27+
28+
private fun requireProperty(variable: String): String =
29+
getProperty(variable) ?: throw ProviderConfigurationException("Missing value for system property `$variable`")
30+
31+
override suspend fun resolve(attributes: Attributes): Credentials {
32+
coroutineContext.trace<SystemPropertyCredentialsProvider> {
33+
"Attempting to load credentials from system properties $ACCESS_KEY_ID/$SECRET_ACCESS_KEY/$SESSION_TOKEN"
34+
}
35+
return Credentials(
36+
accessKeyId = requireProperty(ACCESS_KEY_ID),
37+
secretAccessKey = requireProperty(SECRET_ACCESS_KEY),
38+
sessionToken = getProperty(SESSION_TOKEN),
39+
providerName = PROVIDER_NAME,
40+
)
41+
}
42+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"HOME": "/home",
3+
"AWS_ACCESS_KEY_ID": "incorrect_key",
4+
"AWS_SECRET_ACCESS_KEY": "incorrect_secret"
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[default]
2+
region = us-east-1
3+
role_arn = arn:aws:iam::123456789:role/integration-test
4+
source_profile = base
5+
6+
[profile base]
7+
region = us-east-1
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[base]
2+
aws_access_key_id = AKIAFAKE
3+
aws_secret_access_key = FAKE
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"aws.accessKeyId": "correct_key",
3+
"aws.secretAccessKey": "correct_secret"
4+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "prefer system properties",
3+
"docs": "prefer system properties over environment and profile",
4+
"result": {
5+
"Ok": {
6+
"access_key_id": "correct_key",
7+
"secret_access_key": "correct_secret"
8+
}
9+
}
10+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package aws.sdk.kotlin.runtime.auth.credentials
7+
8+
import aws.sdk.kotlin.runtime.config.AwsSdkSetting
9+
import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
10+
import io.kotest.matchers.string.shouldContain
11+
import kotlinx.coroutines.test.runTest
12+
import org.junit.jupiter.api.Test
13+
import kotlin.test.assertEquals
14+
import kotlin.test.assertFailsWith
15+
16+
class SystemPropertyCredentialsProviderTest {
17+
private fun provider(vararg vars: Pair<String, String>) = SystemPropertyCredentialsProvider((vars.toMap())::get)
18+
19+
@Test
20+
fun readAllSystemProperties() = runTest {
21+
val provider = provider(
22+
AwsSdkSetting.AwsAccessKeyId.sysProp to "abc",
23+
AwsSdkSetting.AwsSecretAccessKey.sysProp to "def",
24+
AwsSdkSetting.AwsSessionToken.sysProp to "ghi",
25+
)
26+
assertEquals(provider.resolve(), Credentials("abc", "def", "ghi", providerName = "SystemProperties"))
27+
}
28+
29+
@Test
30+
fun readAllSystemPropertiesExceptSessionToken() = runTest {
31+
val provider = provider(
32+
AwsSdkSetting.AwsAccessKeyId.sysProp to "abc",
33+
AwsSdkSetting.AwsSecretAccessKey.sysProp to "def",
34+
)
35+
assertEquals(provider.resolve(), Credentials("abc", "def", null, providerName = "SystemProperties"))
36+
}
37+
38+
@Test
39+
fun throwsExceptionWhenMissingAccessKey() = runTest {
40+
assertFailsWith<ProviderConfigurationException> {
41+
provider(AwsSdkSetting.AwsSecretAccessKey.sysProp to "def").resolve()
42+
}.message.shouldContain("Missing value for system property `aws.accessKeyId`")
43+
}
44+
45+
@Test
46+
fun throwsExceptionWhenMissingSecretKey() = runTest {
47+
assertFailsWith<ProviderConfigurationException> {
48+
provider(AwsSdkSetting.AwsAccessKeyId.sysProp to "abc").resolve()
49+
}.message.shouldContain("Missing value for system property `aws.secretAccessKey`")
50+
}
51+
}

0 commit comments

Comments
 (0)