SethuNagaKarthik
SethuNagaKarthik

Reputation: 409

update the IAM password less authentication token before it get expired

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

Answers (1)

SethuNagaKarthik
SethuNagaKarthik

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

Related Questions