Skip to content

Commit 552263d

Browse files
jiangbaojunericbottard
authored andcommitted
Add bedrock profile autoconfiguration support and replace deprecated
Signed-off-by: Baojun Jiang <jiangbaojun1001@163.com>
1 parent c08409f commit 552263d

File tree

8 files changed

+215
-14
lines changed

8 files changed

+215
-14
lines changed

auto-configurations/models/spring-ai-autoconfigure-model-bedrock-ai/src/main/java/org/springframework/ai/model/bedrock/autoconfigure/BedrockAwsConnectionConfiguration.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616

1717
package org.springframework.ai.model.bedrock.autoconfigure;
1818

19+
import java.nio.file.Paths;
20+
1921
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
2022
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
2123
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
2224
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
25+
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
2326
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
27+
import software.amazon.awssdk.profiles.ProfileFile;
2428
import software.amazon.awssdk.regions.Region;
2529
import software.amazon.awssdk.regions.providers.AwsRegionProvider;
2630
import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain;
@@ -36,6 +40,7 @@
3640
*
3741
* @author Christian Tzolov
3842
* @author Wei Jiang
43+
* @author Baojun Jiang
3944
*/
4045
@Configuration
4146
@EnableConfigurationProperties(BedrockAwsConnectionProperties.class)
@@ -44,19 +49,48 @@ public class BedrockAwsConnectionConfiguration {
4449
@Bean
4550
@ConditionalOnMissingBean
4651
public AwsCredentialsProvider credentialsProvider(BedrockAwsConnectionProperties properties) {
47-
4852
if (StringUtils.hasText(properties.getAccessKey()) && StringUtils.hasText(properties.getSecretKey())) {
49-
53+
// Security key
5054
if (StringUtils.hasText(properties.getSessionToken())) {
5155
return StaticCredentialsProvider.create(AwsSessionCredentials.create(properties.getAccessKey(),
5256
properties.getSecretKey(), properties.getSessionToken()));
5357
}
54-
5558
return StaticCredentialsProvider
5659
.create(AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
5760
}
58-
59-
return DefaultCredentialsProvider.create();
61+
else if (properties.getProfile() != null && StringUtils.hasText(properties.getProfile().getName())) {
62+
// Profile
63+
ProfileProperties profile = properties.getProfile();
64+
String configurationPath = profile.getConfigurationPath();
65+
String credentialsPath = profile.getCredentialsPath();
66+
boolean hasCredentials = StringUtils.hasText(credentialsPath);
67+
boolean hasConfig = StringUtils.hasText(configurationPath);
68+
ProfileCredentialsProvider.Builder providerBuilder = ProfileCredentialsProvider.builder();
69+
if (hasCredentials || hasConfig) {
70+
ProfileFile.Aggregator aggregator = ProfileFile.aggregator();
71+
if (hasCredentials) {
72+
ProfileFile profileFile = ProfileFile.builder()
73+
.content(Paths.get(credentialsPath))
74+
.type(ProfileFile.Type.CREDENTIALS)
75+
.build();
76+
aggregator.addFile(profileFile);
77+
}
78+
if (hasConfig) {
79+
ProfileFile configFile = ProfileFile.builder()
80+
.content(Paths.get(configurationPath))
81+
.type(ProfileFile.Type.CONFIGURATION)
82+
.build();
83+
aggregator.addFile(configFile);
84+
}
85+
ProfileFile aggregatedProfileFile = aggregator.build();
86+
providerBuilder.profileFile(aggregatedProfileFile);
87+
}
88+
return providerBuilder.profileName(profile.getName()).build();
89+
}
90+
else {
91+
// Default: IAM Role, System Environment, etc.
92+
return DefaultCredentialsProvider.builder().build();
93+
}
6094
}
6195

6296
@Bean

auto-configurations/models/spring-ai-autoconfigure-model-bedrock-ai/src/main/java/org/springframework/ai/model/bedrock/autoconfigure/BedrockAwsConnectionProperties.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
import java.time.Duration;
2020

2121
import org.springframework.boot.context.properties.ConfigurationProperties;
22+
import org.springframework.boot.context.properties.NestedConfigurationProperty;
2223

2324
/**
2425
* Configuration properties for Bedrock AWS connection.
2526
*
2627
* @author Christian Tzolov
28+
* @author Baojun Jiang
2729
* @since 0.8.0
2830
*/
2931
@ConfigurationProperties(BedrockAwsConnectionProperties.CONFIG_PREFIX)
@@ -48,10 +50,17 @@ public class BedrockAwsConnectionProperties {
4850

4951
/**
5052
* AWS session token. (optional) When provided the AwsSessionCredentials are used.
51-
* Otherwise the AwsBasicCredentials are used.
53+
* Otherwise, the AwsBasicCredentials are used.
5254
*/
5355
private String sessionToken;
5456

57+
/**
58+
* Aws profile. (optional) When the {@link #accessKey} and {@link #secretKey} are not
59+
* declared. Otherwise, the AwsBasicCredentials are used.
60+
*/
61+
@NestedConfigurationProperty
62+
private ProfileProperties profile;
63+
5564
/**
5665
* Maximum duration of the entire API call operation.
5766
*/
@@ -149,4 +158,12 @@ public void setSessionToken(String sessionToken) {
149158
this.sessionToken = sessionToken;
150159
}
151160

161+
public ProfileProperties getProfile() {
162+
return this.profile;
163+
}
164+
165+
public void setProfile(ProfileProperties profile) {
166+
this.profile = profile;
167+
}
168+
152169
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2023-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.model.bedrock.autoconfigure;
18+
19+
/**
20+
* Configuration properties for Bedrock AWS connection using profile.
21+
*
22+
* @author Baojun Jiang
23+
*/
24+
public class ProfileProperties {
25+
26+
/**
27+
* Name of the profile to use.
28+
*/
29+
private String name;
30+
31+
/**
32+
* (optional) Path to the credentials file. default: ~/.aws/credentials
33+
*/
34+
private String credentialsPath;
35+
36+
/**
37+
* (optional) Path to the configuration file. default: ~/.aws/config
38+
*/
39+
private String configurationPath;
40+
41+
public String getName() {
42+
return this.name;
43+
}
44+
45+
public void setName(String name) {
46+
this.name = name;
47+
}
48+
49+
public String getCredentialsPath() {
50+
return this.credentialsPath;
51+
}
52+
53+
public void setCredentialsPath(String credentialsPath) {
54+
this.credentialsPath = credentialsPath;
55+
}
56+
57+
public String getConfigurationPath() {
58+
return this.configurationPath;
59+
}
60+
61+
public void setConfigurationPath(String configurationPath) {
62+
this.configurationPath = configurationPath;
63+
}
64+
65+
}

auto-configurations/models/spring-ai-autoconfigure-model-bedrock-ai/src/test/java/org/springframework/ai/model/bedrock/autoconfigure/BedrockAwsConnectionConfigurationIT.java

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@
1616

1717
package org.springframework.ai.model.bedrock.autoconfigure;
1818

19+
import java.lang.reflect.Field;
20+
import java.nio.file.Files;
21+
import java.nio.file.Paths;
22+
1923
import org.junit.jupiter.api.Test;
2024
import software.amazon.awssdk.auth.credentials.AwsCredentials;
2125
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
26+
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
27+
import software.amazon.awssdk.profiles.ProfileFile;
2228
import software.amazon.awssdk.regions.Region;
2329
import software.amazon.awssdk.regions.providers.AwsRegionProvider;
2430

@@ -63,7 +69,8 @@ public void autoConfigureAWSCredentialAndRegionProvider() {
6369
public void autoConfigureWithCustomAWSCredentialAndRegionProvider() {
6470
BedrockTestUtils.getContextRunner()
6571
.withConfiguration(AutoConfigurations.of(TestAutoConfiguration.class,
66-
CustomAwsCredentialsProviderAndAwsRegionProviderAutoConfiguration.class))
72+
CustomAwsCredentialsProviderAutoConfiguration.class,
73+
CustomAwsRegionProviderAutoConfiguration.class))
6774
.run(context -> {
6875
var awsCredentialsProvider = context.getBean(AwsCredentialsProvider.class);
6976
var awsRegionProvider = context.getBean(AwsRegionProvider.class);
@@ -80,14 +87,73 @@ public void autoConfigureWithCustomAWSCredentialAndRegionProvider() {
8087
});
8188
}
8289

90+
@Test
91+
public void autoConfigureWithCustomAWSProfileCredentialAndRegionProvider() {
92+
BedrockTestUtils.getContextRunner()
93+
.withConfiguration(AutoConfigurations.of(TestAutoConfiguration.class,
94+
CustomAwsProfileCredentialsProviderAutoConfiguration.class,
95+
CustomAwsRegionProviderAutoConfiguration.class))
96+
.run(context -> {
97+
var awsCredentialsProvider = context.getBean(AwsCredentialsProvider.class);
98+
var awsRegionProvider = context.getBean(AwsRegionProvider.class);
99+
100+
assertThat(awsCredentialsProvider).isNotNull();
101+
assertThat(awsRegionProvider).isNotNull();
102+
103+
assertThat(awsCredentialsProvider).isInstanceOf(ProfileCredentialsProvider.class);
104+
// aws sdk2.x does not provide method to get profileName, use reflection
105+
// to get
106+
Field field = ProfileCredentialsProvider.class.getDeclaredField("profileName");
107+
field.setAccessible(true);
108+
assertThat(field.get(awsCredentialsProvider)).isEqualTo("CUSTOM_PROFILE_NAME");
109+
110+
assertThat(awsRegionProvider.getRegion()).isEqualTo(Region.AWS_GLOBAL);
111+
});
112+
}
113+
83114
@EnableConfigurationProperties(BedrockAwsConnectionProperties.class)
84115
@Import(BedrockAwsConnectionConfiguration.class)
85116
static class TestAutoConfiguration {
86117

87118
}
88119

89120
@AutoConfiguration
90-
static class CustomAwsCredentialsProviderAndAwsRegionProviderAutoConfiguration {
121+
static class CustomAwsProfileCredentialsProviderAutoConfiguration {
122+
123+
@Bean
124+
@ConditionalOnMissingBean
125+
public AwsCredentialsProvider credentialsProvider() {
126+
String credentialsPath = "CUSTOM_CREDENTIALS_PATH";
127+
String configurationPath = "CUSTOM_CONFIGURATION_PATH";
128+
boolean hasCredentials = Files.exists(Paths.get(credentialsPath));
129+
boolean hasConfig = Files.exists(Paths.get(configurationPath));
130+
ProfileCredentialsProvider.Builder providerBuilder = ProfileCredentialsProvider.builder();
131+
if (hasCredentials || hasConfig) {
132+
ProfileFile.Aggregator aggregator = ProfileFile.aggregator();
133+
if (hasCredentials) {
134+
ProfileFile profileFile = ProfileFile.builder()
135+
.content(Paths.get(credentialsPath))
136+
.type(ProfileFile.Type.CREDENTIALS)
137+
.build();
138+
aggregator.addFile(profileFile);
139+
}
140+
if (hasConfig) {
141+
ProfileFile configFile = ProfileFile.builder()
142+
.content(Paths.get(configurationPath))
143+
.type(ProfileFile.Type.CONFIGURATION)
144+
.build();
145+
aggregator.addFile(configFile);
146+
}
147+
ProfileFile aggregatedProfileFile = aggregator.build();
148+
providerBuilder.profileFile(aggregatedProfileFile);
149+
}
150+
return providerBuilder.profileName("CUSTOM_PROFILE_NAME").build();
151+
}
152+
153+
}
154+
155+
@AutoConfiguration
156+
static class CustomAwsCredentialsProviderAutoConfiguration {
91157

92158
@Bean
93159
@ConditionalOnMissingBean
@@ -114,6 +180,11 @@ public String secretAccessKey() {
114180
};
115181
}
116182

183+
}
184+
185+
@AutoConfiguration
186+
static class CustomAwsRegionProviderAutoConfiguration {
187+
117188
@Bean
118189
@ConditionalOnMissingBean
119190
public AwsRegionProvider regionProvider() {

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/bedrock.adoc

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ spring.ai.bedrock.aws.region=us-east-1
6464
spring.ai.bedrock.aws.access-key=YOUR_ACCESS_KEY
6565
spring.ai.bedrock.aws.secret-key=YOUR_SECRET_KEY
6666
67+
spring.ai.bedrock.aws.profile.name=YOUR_PROFILE_NAME
68+
spring.ai.bedrock.aws.profile.credentials-path=YOUR_CREDENTIALS_PATH
69+
spring.ai.bedrock.aws.profile.configuration-path=YOUR_CONFIGURATION_PATH
70+
6771
spring.ai.bedrock.aws.timeout=10m
6872
----
6973

@@ -72,12 +76,13 @@ The `region` property is compulsory.
7276
AWS credentials are resolved in the following order:
7377

7478
1. Spring-AI Bedrock `spring.ai.bedrock.aws.access-key` and `spring.ai.bedrock.aws.secret-key` properties.
75-
2. Java System Properties - `aws.accessKeyId` and `aws.secretAccessKey`.
76-
3. Environment Variables - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
77-
4. Web Identity Token credentials from system properties or environment variables.
78-
5. Credential profiles file at the default location (`~/.aws/credentials`) shared by all AWS SDKs and the AWS CLI.
79-
6. Credentials delivered through the Amazon EC2 container service if the `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` environment variable is set and the security manager has permission to access the variable.
80-
7. Instance profile credentials delivered through the Amazon EC2 metadata service or set the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
79+
2. Spring-AI Bedrock `spring.ai.bedrock.aws.profile.name`, If `spring.ai.bedrock.aws.profile.credentials-path` and `spring.ai.bedrock.aws.profile.configuration-path` are not specified, Spring AI use the standard AWS shared files: `~/.aws/credentials` for credentials and `~/.aws/config` for configuration.
80+
3. Java System Properties - `aws.accessKeyId` and `aws.secretAccessKey`.
81+
4. Environment Variables - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
82+
5. Web Identity Token credentials from system properties or environment variables.
83+
6. Credential profiles file at the default location (`~/.aws/credentials`) shared by all AWS SDKs and the AWS CLI.
84+
7. Credentials delivered through the Amazon EC2 container service if the `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` environment variable is set and the security manager has permission to access the variable.
85+
8. Instance profile credentials delivered through the Amazon EC2 metadata service or set the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
8186

8287
AWS region is resolved in the following order:
8388

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock-converse.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ The prefix `spring.ai.bedrock.aws` is the property prefix to configure the conne
8181
| spring.ai.bedrock.aws.access-key | AWS access key | -
8282
| spring.ai.bedrock.aws.secret-key | AWS secret key | -
8383
| spring.ai.bedrock.aws.session-token | AWS session token for temporary credentials | -
84+
| spring.ai.bedrock.aws.profile.name | AWS profile name. | -
85+
| spring.ai.bedrock.aws.profile.credentials-path | AWS credentials file path. | -
86+
| spring.ai.bedrock.aws.profile.configuration-path | AWS config file path. | -
8487
|====
8588

8689
[NOTE]

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/embeddings/bedrock-cohere-embedding.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ The prefix `spring.ai.bedrock.aws` is the property prefix to configure the conne
9090
| spring.ai.bedrock.aws.region | AWS region to use. | us-east-1
9191
| spring.ai.bedrock.aws.access-key | AWS access key. | -
9292
| spring.ai.bedrock.aws.secret-key | AWS secret key. | -
93+
| spring.ai.bedrock.aws.profile.name | AWS profile name. | -
94+
| spring.ai.bedrock.aws.profile.credentials-path | AWS credentials file path. | -
95+
| spring.ai.bedrock.aws.profile.configuration-path | AWS config file path. | -
9396
|====
9497

9598
[NOTE]

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/embeddings/bedrock-titan-embedding.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ The prefix `spring.ai.bedrock.aws` is the property prefix to configure the conne
9797
| spring.ai.bedrock.aws.region | AWS region to use. | us-east-1
9898
| spring.ai.bedrock.aws.access-key | AWS access key. | -
9999
| spring.ai.bedrock.aws.secret-key | AWS secret key. | -
100+
| spring.ai.bedrock.aws.profile.name | AWS profile name. | -
101+
| spring.ai.bedrock.aws.profile.credentials-path | AWS credentials file path. | -
102+
| spring.ai.bedrock.aws.profile.configuration-path | AWS config file path. | -
100103
|====
101104

102105
[NOTE]

0 commit comments

Comments
 (0)