春のブートAWS LambdaにカスタムApplicationContextInitializerを読み込む方法は?スプリングブートを使用するawsラムダアプリケーションがあります。データベースパスワードを復号化するためのApplicationContextInitializerを記述したいと思います。ローカルでSpring Bootアプリケーションとして実行しているときに機能する次のコードがありますが、それをラムダとしてAWSコンソールにデプロイすると機能しません。
これが私のコードです1. applications.properties
spring.datasource.url=url
spring.datasource.username=testuser
CIPHER.spring.datasource.password=encryptedpassword
次のコードはApplicationContextInitializerで、パスワードはテスト用にBase64でエンコードされていると想定しています(実際には、AWM KMSによって暗号化されます)。ここでの考え方は、キーが「CIPHER」で始まるかどうかです。(CIPHER.spring.datasource.passwordのように)値を復号化する必要があると想定し、実際のキー(ここではspring.datasource.password)と別のキー値のペアとその復号化された値がコンテキストの初期化時に追加されます。
のようになります spring.datasource.password=decrypted password
@Component
public class DecryptedPropertyContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final String CIPHER = "CIPHER.";
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySource<?> propertySource : environment.getPropertySources()) {
Map<String, Object> propertyOverrides = new LinkedHashMap<>();
decodePasswords(propertySource, propertyOverrides);
if (!propertyOverrides.isEmpty()) {
PropertySource<?> decodedProperties = new MapPropertySource("decoded "+ propertySource.getName(), propertyOverrides);
environment.getPropertySources().addBefore(propertySource.getName(), decodedProperties);
}
}
}
private void decodePasswords(PropertySource<?> source, Map<String, Object> propertyOverrides) {
if (source instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) source;
for (String key : enumerablePropertySource.getPropertyNames()) {
Object rawValue = source.getProperty(key);
if (rawValue instanceof String && key.startsWith(CIPHER)) {
String cipherRemovedKey = key.substring(CIPHER.length());
String decodedValue = decode((String) rawValue);
propertyOverrides.put(cipherRemovedKey, decodedValue);
}
}
}
}
public String decode(String encodedString) {
byte[] valueDecoded = org.apache.commons.codec.binary.Base64.decodeBase64(encodedString);
return new String(valueDecoded);
}
これがSpring Boot Initializerです
@SpringBootApplication
@ComponentScan(basePackages = "com.amazonaws.serverless.sample.springboot.controller")
public class Application extends SpringBootServletInitializer {
@Bean
public HandlerMapping handlerMapping() {
return new RequestMappingHandlerMapping();
}
@Bean
public HandlerAdapter handlerAdapter() {
return new RequestMappingHandlerAdapter();
}
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
return new HandlerExceptionResolver() {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
return null;
}
};
}
//loading the initializer here
public static void main(String[] args) {
SpringApplication application=new SpringApplication(Application.class);
application.addInitializers(new DecryptedPropertyContextInitializer());
application.run(args);
}
これは、スプリングブートアプリケーションとして実行すると機能しますが、ラムダとしてAWSにデプロイすると、SpringBootServletInitializerのmain()メソッドがラムダによって呼び出されることはありません。これが私のLambdaハンドラです。
public class StreamLambdaHandler implements RequestStreamHandler {
private static Logger LOGGER = LoggerFactory.getLogger(StreamLambdaHandler.class);
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
handler.onStartup(servletContext -> {
FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
});
} catch (ContainerInitializationException e) {
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
@Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
handler.proxyStream(inputStream, outputStream, context);
outputStream.close();
}
}
LambdaによってApplicationContextInitializerをロードするために、コードにどのような変更を加える必要がありますか?どんな助けも高く評価されます。
次のように釘付けできました。
最初に、プレフィックス付きのプレースホルダーを使用してプロパティ値を変更しました。プレフィックスは、値を復号化する必要があることを示します。
spring.datasource.password = $ {MY_PREFIX_placeHolder}
awsラムダ環境変数名はプレースホルダーと一致する必要があります
( 'MY_PREFIX_placeHolder')そしてその値はAWS KMSを使用して暗号化されます(このサンプルはbase64デコードです)。
プロパティ値を復号化するApplicationContextInitializerを作成します
public class DecryptedPropertyContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final String CIPHER = "MY_PREFIX_";
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySource<?> propertySource : environment.getPropertySources()) {
Map<String, Object> propertyOverrides = new LinkedHashMap<>();
decodePasswords(propertySource, propertyOverrides);
if (!propertyOverrides.isEmpty()) {
PropertySource<?> decodedProperties = new MapPropertySource("decoded "+ propertySource.getName(), propertyOverrides);
environment.getPropertySources().addBefore(propertySource.getName(), decodedProperties);
}
}
}
private void decodePasswords(PropertySource<?> source, Map<String, Object> propertyOverrides) {
if (source instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) source;
for (String key : enumerablePropertySource.getPropertyNames()) {
Object rawValue = source.getProperty(key);
if (rawValue instanceof String && key.startsWith(CIPHER)) {
String decodedValue = decode((String) rawValue);
propertyOverrides.put(key, decodedValue);
}
}
}
}
public String decode(String encodedString) {
byte[] valueDecoded = org.apache.commons.codec.binary.Base64.decodeBase64(encodedString);
return new String(valueDecoded);
}
}
上記のコードは、接頭辞がMY_PREFIX_のすべての値を復号化し、プロパティソースの先頭に追加します。
スプリングブートがawsラムダにデプロイされると、ラムダはmain()関数を呼び出さないため、ApplicationContextInitializerがmain()で初期化されると機能しません。これを機能させるには、SpringBootServletInitializerのcreateSpringApplicationBuilder()メソッドをオーバーライドする必要があるため、SpringBootServletInitializerは次のようになります。
@SpringBootApplication
@ComponentScan(basePackages = "com.amazonaws.serverless.sample.springboot.controller")
public class Application extends SpringBootServletInitializer {
@Bean
public HandlerMapping handlerMapping() {
return new RequestMappingHandlerMapping();
}
@Bean
public HandlerAdapter handlerAdapter() {
return new RequestMappingHandlerAdapter();
}
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
return new HandlerExceptionResolver() {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
return null;
}
};
}
@Override
protected SpringApplicationBuilder createSpringApplicationBuilder() {
SpringApplicationBuilder builder = new SpringApplicationBuilder();
builder.initializers(new DecryptedPropertyContextInitializer());
return builder;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
ラムダハンドラーを変更する必要はありません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加