AWS AppConfig and Lambda: Power in the hands of the business

Sjoerd
PostNL Engineering
Published in
5 min readApr 2, 2024

As PostNL engineers we get frequent requests from our business consultants to change certain configurations in our applications, for example adding an entry to a filter list or change the ratio of an A/B test. This usually came with the overhead of creating user stories, capacity planning and cumbersome deployment procedures. We wanted to get rid of the overhead and transfer the power to the hands of the business, allowing our business consultants to change configurations whenever they needed in a safe and practical way.

Problem established….

Now to the solution! The search for a solution was quick and easy, AWS AppConfig promised to fulfil all our wishes. AWS AppConfig is a service that enables you to manage, deploy, and scale application configurations dynamically. It allows for separation between your application code and configuration settings, reducing the need for redeployments. Quick roll outs of changes without disrupting your application’s performance were promised. It is a service that is meant to be used in the AWS Management Console, decreasing the barrier for our business consultants to use the service without the need of an engineer.

Now that we are actively working with AppConfig and our business consultants deployed several critical configurations successfully we can safely say that all parties involved are very much enthused about the capabilities. The configuration changes and subsequent deployments are all done in the AWS console. According to our business consultants the AppConfig console UI is user friendly. So, all our business acceptance criteria are met!

But what about integration with other AWS services, CDK and perhaps most important: validation strategies.

Aside from quick deployments and clever rollout strategies we required a safety net. Handing over power to the business also meant that malformed configurations could be passed to our caller. As much as we trust our business consultants we didn’t want our application to break in case a String was passed while we expect an Integer.
Luckily AppConfig provides custom validation for your configurations to an impressive extent. You can either provide a Json schema or a custom build lambda that will be triggered whenever you change a configuration.
For us the Json schema validation was powerful enough to at least enforce some basic rules.

{
"properties": {
"depotList": {
"type": "array",
"items": {
"type": "integer",
"minimum": 100000,
"maximum": 999999
}
},
"clientName": {
"type": "string",
"pattern": "[A-Za-z0-9]"
},
"required": ["depotList", "clientName"]
}
}

Since we define our infrastructure as code through CDK we wanted to deploy the AppConfig along side our caller application stack. At the time of our first implementation there wasn’t an L2 construct available so we had to work with L1 construct making our declarations a lot more verbose than we would have liked. Fortunately now the L2 constructs are released and added to the following lib (aws-cdk-lib/aws_appconfig). You can even create the JSON Schema validator through CDK.

Lambda integration

Like any other team in PostNL our stack mainly consists of serverless solutions, meaning we had to integrate AWS AppConfig with AWS Lambda.
Luckily enough AWS provides you with descriptive documentation to integrate both services. Based on the documentation we could take one of the two available approaches:

  • AWS AppConfig Agent Lambda Extension
  • Custom build solution

Lambda Extension

A Lambda extension is a client-like tool that runs concurrently with a Lambda function invocation. This parallel client can interface with your function at any point during its lifecycle, as per the AWS documentation. AWS made a AppConfig Lamda extension available to the public in 2020. If you can, then it is recommended to use this approach as it abstracts away the polling mechanism to AppConfig. The configuration is done in a few seconds as AWS provides you with default values out of the box. For example the polling interval to AppConfig is defaulted to 45 seconds. You can install the layer on the lambda by providing the ‘layers’ array to the Lambda function construct:

layers: [
lambda.LayerVersion.fromLayerVersionArn(
this,
'AppConfigLayer',
'arn:aws:lambda:eu-west-1:434848589818:layer:AWS-AppConfig-Extension:125'
)
]

Within the Lambda code you can then query the provide localhost url in order to retrieve the configuration. Easy does it:

final String configurationEndpoint = "http://localhost:2772/applications/" + this.applicationName + "/environments/" + this.environmentName + "/configurations/" + this.configName;
return OBJECT_MAPPER.readValue(HttpClient.newHttpClient().send(HttpRequest.newBuilder()
.GET()
.uri(URI.create(configurationEndpoint))
.build(),
HttpResponse.BodyHandlers.ofString()).body(), ConfigurationRecord.class);

Custom build solution

Unfortunately, since our calling lambda resides in a VPC (in order to connect to a Database) we weren’t able to reach the AppConfig through the extension, meaning we had to build our own caller and implement our own polling interval mechanism. This is the ‘not-so-recommended’ route as it is far less plug-and-play and requires a lot more overhead. First of all you have to create a VPC endpoint for the AppConfig and make sure that all encompassing security groups allow access. Secondly you have to get familiar with a poorly documented AWS SDK library to build your own AppConfig Client to be able to replace the url with that of your VPC Endpoint. Thirdly this approach also means you are in the lead to handle the Time-To-Live of the AppConfig configuration values.

private static AppConfig getAppConfig() {
try {
var awsAppConfigClient = AWSAppConfigDataClient.builder()
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(APPCONFIG_URL, AWS_REGION))
.build();

var configRequest = new StartConfigurationSessionRequest()
.withApplicationIdentifier(APPCONFIG_APPLICATION_ID)
.withEnvironmentIdentifier(APPCONFIG_ENVIRONMENT_ID)
.withConfigurationProfileIdentifier(APPCONFIG_CONFIGURATION_ID);

var sessionToken = awsAppConfigClient.startConfigurationSession(configRequest).getInitialConfigurationToken();

var latestConfiguration = awsAppConfigClient.getLatestConfiguration(
new GetLatestConfigurationRequest().withConfigurationToken(sessionToken));

return ObjectMapperFactory.getMapper().readValue(latestConfiguration.getConfiguration().array(), ImmutableAppConfig.class);
} catch (Exception e) {
LOGGER.error("Exception in getting AppConfig: {}, {}", e.getClass().getName(), e.getMessage());
return App.getDefaultConfig();
}
}

For either two approaches you of course have to be mindful of how to execute the HTTP call efficiently. In case of working with Lambda you would want to put the call in the constructor of the Handler class meaning the AppConfig values are immediately available to all running lambdas once a Lambda container is spun up.

Conclusion

Both developers and business consultants very much like AWS AppConfig and the amount of features, validators and deployment strategies that were available to us to build a custom solution that suits us best.
Configuration changes no longer requires an engineer’s effort and the time between business request and live in production is significantly sped up.

Nevertheless, combining L2 constructs together with Lambda extensions will yield the quickest results in case your Lambda is outside of a VPC. We will continue adopting AppConfig in other parts of our application making use of the L2 constructs where possible.

We are curious what you think of the premise of AppConfig. What do you think of enabling the business to make configuration changes to applications? To what extent would you go to prevent misconfiguration of application configurations?

Let us know in the comments

A topic that wasn’t discussed in the article is the various deployment strategies and CloudWatch alarm integrations. If you want to learn more, it is best to consult the official AWS Documentation: https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-creating-deployment-strategy.html

Sources:

https://aws.amazon.com/about-aws/whats-new/2024/02/aws-appconfig-l2-constructs-cdk/
https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-lambda-extensions.html
https://docs.aws.amazon.com/appconfig/latest/userguide/creating-feature-flags-and-configuration-data.html

--

--