AWS AppConfig Explained
One fateful night I was scrolling through Twitter and caught Corey Quinn's (LastWeekInAWS author) AppConfig review:
As entertaining and sarcastic as it is, his criticisms of the service definitely resonated with me. I can usually use an AWS service's console to get a pretty good idea of how the service expects you to use it, but that understanding is sorely missing from my experience using the AppConfig console. It's not obvious how to actually consume an environment's current configuration - if you take a quick look at the appconfigdata APIs, you'll see
get-latest-configuration. With SSM Parameter Store it's straightforward:
get-parameter is the API to use to consume a parameter. With AppConfig I have to start some nebulous session first? And then after that, I can pull the configuration down? It seems so strange, this seems like a lot of undifferentiated heavy lifting - so I finally decided to do some deep digging to really understand what's going on with this service. Is it a hidden gem? Should more people use it? Let's find out.
There are a few fundamental concepts to understand about the service before we can start understanding more about what the AppConfig team had in mind when they designed this service:
- Application - This is a top-level container that you'll interact with. You can't do anything in AppConfig without an AppConfig Application. This maps to your actual application that will be reading configuration
- Environment - An AppConfig environment represents an environment of your application, like
- Configuration Profile - This is the actual resource that exposes application configuration. It can be of type feature flag or a freeform configuration like JSON, YAML, or an arbitrary string. As of writing, feature flags are an in-preview service feature and subject to change, so I won't dive deep into them here.
- Deployment Strategy - You can define how a change should be rolled out, including the time the deployment should last, how quickly the rate that new configuration is available grows, whether that growth is exponential or linear, and perhaps most confusing: the "bake time." Bake time is how long after a deployment AppConfig will monitor for triggered CloudWatch alarms for rollback.
AppConfig Change Management
Before you can actually consume configuration, you need to deploy your configuration from a ConfigurationProfile into an Environment. This is where some of the power of AppConfig comes into play. You target an Environment for which you want to update the configuration and select the specific version of the configuration you want to deploy. From there you're able to define or use a deployment strategy to gradually roll your configuration change out over time (so X% of your configuration GET requests will receive the new change, others will receive the old version), then you can deploy the change to that environment.
When defining an AppConfig Environment, you can also tell it to keep an eye on a CloudWatch alarm. If that alarm is triggered during a configuration change (during the bake time), a rollback of that change will be initiated, giving you another layer of safety you can implement with AppConfig.
Before you can deploy configurations, you need to define a ConfigurationProfile. Configuration for a ConfigurationProfile can be sourced from several other AWS services:
- S3 Objects - AppConfig will read from an S3 object version to get the configuration
- SSM Parameters - AppConfig will read an SSM parameter version to get the configuration
- AWS CodePipeline - AppConfig will be triggered by a CodePipeline to source configuration
- SSM Document - AppConfig will read from the SSM Document store for the configuration
- AppConfig - AppConfig will host and manage the configuration itself
By default, we recommend using the AppConfig-Hosted configuration source, as it is likely to provide the least friction way to get started.
AWS CloudFormation supports AWS AppConfig, so you'll want to define your AppConfig Applications, Environments, and ConfigurationProfiles via Infrastructure as Code (IaC), usually logically organized with the application that's consuming it. Because your CloudFormation templates get deployed to each environment, this makes the concept of using AppConfig Environments strange. If you were to use them, you'd have an AppConfig Application defined separate from the rest of your infrastructure, and then define the AppConfig Environment with your application. However, this makes it tricky when you're deploying your application environments to different accounts (AppConfig does not support cross-account access).
Because of this complexity, we recommend treating AppConfig Environments similarly to how we (and many others) treat API Gateway stages. Where you'd usually create one API Gateway per application environment (each with one API Gateway stage), create one AppConfig Application per application environment (each with one AppConfig Environment). This simplifies how we manage these resources via IaC and handle breaking environments into their own accounts.
Okay, now how do I actually read configuration?
For a service that's targeted at the application configuration, it's not very obvious how to actually read that configuration. Something I do when I'm learning a new service is to see what kind of API calls there are. Looking at the AWS CLI documentation, I see two "appconfig" API namespaces:
appconfigdata. Since this is going to be a data plane activity, I'm assuming we'll want the
appconfigdata API, which has two actions underneath it:
To explain the need for these things, it's important to understand how AppConfig handles configuration changes - it supports rolling deployments. Because of this, AppConfig wants to make it clear when your configuration could be "expired" - i.e. when your application boots up it needs to continuously poll for new configuration changes over time, not read it once and call it a day.
The way the service makes this clear is that it expects you to start a "configuration session" which will return a token that you can use in the other API call
get-latest-configuration. When you call
get-latest-configuration, you get a few things:
- the configuration as is currently
- how long you should wait until you should query for it again (usually around a minute)
- a new token that you need to use when you call it again
In your application, you should regularly check for configuration changes and update your code's internal configuration store whenever there are changes.
If you're running on Lambda you're not running some long-running compute resource that can support updating internal configuration, so AWS graciously provides you with a Lambda extension that can handle this polling for you automatically. This reduces the complexity of needing to write your own configuration session code. With it all you need to do is call against a local API via
localhost:2772 to get the current configuration which is usually a very fast API call. We've got an example of this in our GitHub here.
This still seems complicated, what gives?
It IS complicated. It's not a very simple AWS service, but it does provide you with the capabilities of safer configuration changes through CloudWatch alarm integrations and automatic rollbacks. Depending on the application you're building it may not be worth it to take on this additional complexity (K.I.S.S.!), but if you have a high volume app, if you're concerned about configuration changes in general, or if and want to stay in an AWS Native architecture, AWS AppConfig might be right for you.