Reputation: 409
My spring service is written in reactive way and because of that we are using r2dbc to establish database connection. Now I want to enable IAM password less authentication with AWS RDS.
@Bean
public ConnectionFactory connectionFactory() {
// Assume IAM role
StsClient stsClient = StsClient.builder().region(Region.EU_WEST_1).build();
AssumeRoleRequest assumeRoleRequest = AssumeRoleRequest.builder()
.roleArn("arn")
.roleSessionName("CrossAccountDbSession")
.build();
AssumeRoleResponse assumeRoleResponse = stsClient.assumeRole(assumeRoleRequest);
Credentials assumedCredentials = assumeRoleResponse.credentials();
// Create AWS credentials provider with assumed role
AwsCredentialsProvider credentialsProvider = () -> software.amazon.awssdk.auth.credentials.AwsSessionCredentials.create(
assumedCredentials.accessKeyId(),
assumedCredentials.secretAccessKey(),
assumedCredentials.sessionToken()
);
// Generate IAM authentication token
RdsUtilities rdsUtilities = RdsUtilities.builder().region(Region.EU_WEST_1).build();
String authToken = rdsUtilities.generateAuthenticationToken(builder -> builder
.hostname("host-name")
.port(5432)
.username("username")
.credentialsProvider(credentialsProvider)
);
PostgresqlConnectionConfiguration postgresConfig = PostgresqlConnectionConfiguration.builder()
.host("hostname")
.port(5432)
.username("username")
.password(authToken)
.database("databasename")
.build();
ConnectionPoolConfiguration poolConfig = ConnectionPoolConfiguration.builder(new PostgresqlConnectionFactory(postgresConfig))
.maxIdleTime(Duration.ofMinutes(15)) // Connection will be closed after 30 minutes of inactivity
.maxSize(20) // Maximum number of connections in the pool
.initialSize(5) // Initial number of connections in the pool
.build();
return new ConnectionPool(poolConfig);
}
Now the IAM auth is working fine but the token is active for only for 15mins and it got expired and the connection is getting closed. So I tried implementing @Scheduled annotation and RefreshingConnectionFactory but still no success.
application-dev.property
server.port=8114
######### Configuration for PostgreSQL database #########
aws.rds.region=eu-west-1
aws.rds.host=host
aws.rds.port=5432
aws.rds.dbname=dbname
spring.r2dbc.username=username
spring.r2dbc.password=
spring.r2dbc.url= r2dbc:postgresql://rds/dbname
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database-platform=org.hibesrnate.dialect.PostgreSQL9Dialect
Upvotes: 1
Views: 94
Reputation: 409
Create a new Class and import ConnectionFactory interface. After creating the postgressqlconnection object pass the object to DelegatingConnectionFactory to update the bean during runtime.
import io.r2dbc.spi.Connection;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.ConnectionFactoryMetadata;
import reactor.core.publisher.Mono;
/**
* A delegating ConnectionFactory that allows dynamic swapping of the underlying
* ConnectionFactory at runtime.
*/
public class DelegatingConnectionFactory implements ConnectionFactory {
// The underlying connection factory that this class delegates to.
private volatile ConnectionFactory targetConnectionFactory;
// Constructor to initialize the class with a target ConnectionFactory.
public DelegatingConnectionFactory(ConnectionFactory targetConnectionFactory) {
this.targetConnectionFactory = targetConnectionFactory;
}
// Method to update the target ConnectionFactory at runtime.
public void setTargetConnectionFactory(ConnectionFactory targetConnectionFactory) {
this.targetConnectionFactory = targetConnectionFactory; // Swap the underlying factory
}
// Delegating the create method to the target ConnectionFactory.
@Override
public Mono<? extends Connection> create() {
return (Mono<? extends Connection>) this.targetConnectionFactory.create();
}
// Delegating metadata retrieval to the target ConnectionFactory.
@Override
public ConnectionFactoryMetadata getMetadata() {
return this.targetConnectionFactory.getMetadata();
}
}
Upvotes: 0