amazon-web-servicesmicronautaws-ssmaws-parameter-store

Unable to Represent Micronaut Application Properties with Array of Object in AWS Parameter Store


How do I store a Micronaut application properties with array of object in AWS Parameter Store since we can't have square brackets in the parameter name of AWS Parameter Store?

Here's a snippet of properties that need to be stored in AWS Parameter Store,

micronaut:
  security:
    intercept-url-map:
      - pattern: /hello
        http-method: GET
        access:
          - isAnonymous()
      - pattern: /bye
        http-method: GET
        access:
          - isAnonymous()

Solution

  • I managed to solve this issue by decorating AWSParameterStoreConfigClient, bean that responsible to orchestrating the properties reading from AWS Parameter Store. Before implementing the solution please be aware that,

    1. AWSParameterStoreConfigClient bean will still be loaded and perform the properties reading, including the API call to the cloud. Make sure that your app won't be disrupted by such behavior.
    2. I chose to decorate the config-client instead of replace it because the constructor is protected by package-private access modifier. Also I wan't to avoid rewriting the whole implementation to make the solution is more future-proof and avoid wrong implementation.
    3. This issue showing that AWS Parameter Store might not be the best solution to store your app configuration, considering its incompatibility to the common application configuration format. Even when you get creative maybe by storing the configuration as JSON in a single parameter, the stored configuration itself would be limited to the parameter size limitation.

    Here's the solution code,

    import io.micronaut.context.annotation.BootstrapContextCompatible
    import io.micronaut.context.annotation.Factory
    import io.micronaut.context.annotation.Requirements
    import io.micronaut.context.annotation.Requires
    import io.micronaut.context.env.Environment
    import io.micronaut.context.env.MapPropertySource
    import io.micronaut.context.env.PropertySource
    import io.micronaut.discovery.aws.parameterstore.AWSParameterStoreConfigClient
    import io.micronaut.discovery.config.ConfigurationClient
    import jakarta.inject.Singleton
    import reactor.core.publisher.Flux
    
    @Factory
    @Requirements(
        Requires(env = ["ec2"]),
        Requires(beans = [AWSParameterStoreConfigClient::class])
    )
    @BootstrapContextCompatible
    class ConfigurationClientConfiguration {
        @Singleton
        fun enhancedAWSParameterStoreConfigurationClient(
            delegate: AWSParameterStoreConfigClient,
        ) = object : ConfigurationClient {
            override fun getDescription() = "Decorated AWS Parameter Store"
    
            override fun getPropertySources(environment: Environment) = Flux.from(delegate.getPropertySources(environment))
                .map { propertySource ->
                    var newPropertySource = (propertySource as MapPropertySource).asMap().toMutableMap()
    
                    newPropertySource = newPropertySource.mapKeys { (key) ->
                        key.replace("\\.\\d+\\.".toRegex()) { matchResult ->
                            matchResult.value.replaceFirst(".", "[").replaceFirst(".", "].")
                        }
                    }.toMutableMap()
    
                    PropertySource.of(newPropertySource)
                }
    
        }
    }