AWS Lambda Spring BootにカスタムApplicationContextInitializerをロードする

サンニッシュホセ:

春のブート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]

編集
0

コメントを追加

0

関連記事

分類Dev

AWS Lambdaで実行すると、Spring BootアプリケーションがMultipartExceptionをスローする

分類Dev

AWS Lambda Java function Spring context initialization

分類Dev

AWS LambdaにSpringブートアプリケーションをデプロイする

分類Dev

既存のSpring Bootプロジェクトでaws lambdaをセットアップする方法は?

分類Dev

AWS Lambda関数をローカルでテストする方法

分類Dev

AWS Cognitoを使用してログインしようとすると、カスタムLambdaトリガーに関するAccessDeniedExceptionが発生します

分類Dev

AWS Lambdaでローカルファイルシステムにアクセスする

分類Dev

外部ソースシステムからAWS Lambdaのソースをダウンロードする

分類Dev

AWS Lambda Java、MySQLRDSに接続

分類Dev

AWS Lambda Java、MySQLRDSに接続

分類Dev

AWS Lambda GoLangエラー

分類Dev

AWS API Gatewayを使用しているときに、カスタムLambdaオーソライザーからJWTペイロードを返すことは可能ですか?

分類Dev

AWS API GatewayカスタムオーソライザーにLambdaパーミッションを提供するにはどうすればよいですか?

分類Dev

Will AWS work with Spring Boot and React?

分類Dev

Amazon AWS LambdaでSpringブート/クラウドを使用しても値が挿入されない

分類Dev

AWS Lambda関数をローカルでテストするにはどうすればよいですか?

分類Dev

AWS Lambdaにnpmモジュールをロードする方法は?

分類Dev

aws lambdaにlibフォルダーをロードする方法は?

分類Dev

AWS LambdaとAWS Lambda @ EDGEの違いは何ですか?

分類Dev

AWS Lambdaにphantomjsノードアプリをデプロイする方法は?

分類Dev

AWS Lambda ::ローカルのubuntuマシンでコードをテストするにはどうすればよいですか?

分類Dev

Lambdaを使用したデータのAWSクロスアカウント移動

分類Dev

AWS Lambdaでのみローカルモジュールをロードする際の問題

分類Dev

Spring Boot Javaを介してローカルでアクセスすると、AWS Elastic Cache(Redis)が接続に失敗しました(jedis接続エラー)

分類Dev

AWSでLambda関数を公開する

分類Dev

AWS Lambdaを最適化する方法は?

分類Dev

Lambda(AWS)の構成を取得する方法

分類Dev

AWS Lambda [Nodejs]を停止する方法

分類Dev

AWS Lambdaの回路ブレーカー

Related 関連記事

  1. 1

    AWS Lambdaで実行すると、Spring BootアプリケーションがMultipartExceptionをスローする

  2. 2

    AWS Lambda Java function Spring context initialization

  3. 3

    AWS LambdaにSpringブートアプリケーションをデプロイする

  4. 4

    既存のSpring Bootプロジェクトでaws lambdaをセットアップする方法は?

  5. 5

    AWS Lambda関数をローカルでテストする方法

  6. 6

    AWS Cognitoを使用してログインしようとすると、カスタムLambdaトリガーに関するAccessDeniedExceptionが発生します

  7. 7

    AWS Lambdaでローカルファイルシステムにアクセスする

  8. 8

    外部ソースシステムからAWS Lambdaのソースをダウンロードする

  9. 9

    AWS Lambda Java、MySQLRDSに接続

  10. 10

    AWS Lambda Java、MySQLRDSに接続

  11. 11

    AWS Lambda GoLangエラー

  12. 12

    AWS API Gatewayを使用しているときに、カスタムLambdaオーソライザーからJWTペイロードを返すことは可能ですか?

  13. 13

    AWS API GatewayカスタムオーソライザーにLambdaパーミッションを提供するにはどうすればよいですか?

  14. 14

    Will AWS work with Spring Boot and React?

  15. 15

    Amazon AWS LambdaでSpringブート/クラウドを使用しても値が挿入されない

  16. 16

    AWS Lambda関数をローカルでテストするにはどうすればよいですか?

  17. 17

    AWS Lambdaにnpmモジュールをロードする方法は?

  18. 18

    aws lambdaにlibフォルダーをロードする方法は?

  19. 19

    AWS LambdaとAWS Lambda @ EDGEの違いは何ですか?

  20. 20

    AWS Lambdaにphantomjsノードアプリをデプロイする方法は?

  21. 21

    AWS Lambda ::ローカルのubuntuマシンでコードをテストするにはどうすればよいですか?

  22. 22

    Lambdaを使用したデータのAWSクロスアカウント移動

  23. 23

    AWS Lambdaでのみローカルモジュールをロードする際の問題

  24. 24

    Spring Boot Javaを介してローカルでアクセスすると、AWS Elastic Cache(Redis)が接続に失敗しました(jedis接続エラー)

  25. 25

    AWSでLambda関数を公開する

  26. 26

    AWS Lambdaを最適化する方法は?

  27. 27

    Lambda(AWS)の構成を取得する方法

  28. 28

    AWS Lambda [Nodejs]を停止する方法

  29. 29

    AWS Lambdaの回路ブレーカー

ホットタグ

アーカイブ