Skip to content

Instantly share code, notes, and snippets.

@jakzal
Last active December 18, 2022 13:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakzal/619ee63d22794615a6ea530cf40d3e3e to your computer and use it in GitHub Desktop.
Save jakzal/619ee63d22794615a6ea530cf40d3e3e to your computer and use it in GitHub Desktop.
Reload AWS RDS/Aurora token every x minutes in Spring Boot
aws.region=eu-west-2
aws.refresh-db-credentials.rate=240000
aws.refresh-db-credentials.initial-delay=240000
package acme.aws;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.services.rds.auth.GetIamAuthTokenRequest;
import com.amazonaws.services.rds.auth.RdsIamAuthTokenGenerator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.stereotype.Component;
@Component
public class AuthTokenProvider {
private final DataSourceProperties properties;
private final String regionName;
public AuthTokenProvider(DataSourceProperties properties, @Value("${aws.region:eu-west-2}") String regionName) {
this.properties = properties;
this.regionName = regionName;
}
public String generateToken() {
RdsIamAuthTokenGenerator generator = RdsIamAuthTokenGenerator.builder()
.credentials(new DefaultAWSCredentialsProviderChain())
.region(regionName)
.build();
String jdbcUrl = properties.getUrl();
return generator.getAuthToken(
GetIamAuthTokenRequest
.builder()
.hostname(jdbcUrl.replaceAll("^jdbc:.*?//(.*?):.*$", "$1"))
.port(Integer.parseInt(jdbcUrl.replaceAll("^jdbc:.*?//.*?:(\\d+).*$", "$1")))
.userName(properties.getUsername())
.build()
);
}
}
package acme.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import acme.aws.AuthTokenProvider;
import javax.sql.DataSource;
@Configuration
public class DatabaseConfig {
@Configuration
@ConfigurationProperties(prefix = "spring.datasource.hikari")
static class EbsaHikariConfig extends HikariConfig {
}
@Bean
public DataSource dataSource(
AuthTokenProvider authTokenProvider,
DataSourceProperties properties,
EbsaHikariConfig hikariConfig
) {
return createDataSource(authTokenProvider, properties, hikariConfig);
}
private HikariDataSource createDataSource(AuthTokenProvider authTokenProvider, DataSourceProperties properties, HikariConfig hikariConfig) {
hikariConfig.addDataSourceProperty("useSSL", true);
hikariConfig.addDataSourceProperty("requireSSL", true);
hikariConfig.addDataSourceProperty("verifyServerCertificate", true);
hikariConfig.setJdbcUrl(properties.getUrl());
hikariConfig.setUsername(properties.getUsername());
hikariConfig.setPassword(authTokenProvider.generateToken());
return new HikariDataSource(hikariConfig);
}
}
package acme.aws;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
@Component
public class RefreshDatabaseCredentialsTask {
private final HikariDataSource dataSource;
private final AuthTokenProvider authTokenProvider;
public RefreshDatabaseCredentialsTask(DataSource dataSource, AuthTokenProvider authTokenProvider) {
this.dataSource = (HikariDataSource) dataSource;
this.authTokenProvider = authTokenProvider;
}
@Scheduled(
fixedRateString = "${aws.refresh-db-credentials.rate:240000}",
initialDelayString = "${aws.refresh-db-credentials.initial-delay:240000}"
)
public void run() {
dataSource.getHikariConfigMXBean().setPassword(authTokenProvider.generateToken());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment