A powerful approach for engineering teams to manage config for web apps that improves your security and engineering team efficiency.
This is the fourth video in our 12-factor Application Modernisation series. In this video, Marc Firth (Managing Director at Firney) explains software engineering best practices around injecting config into the environment using environment variables rather than storing it in your codebase.
See our Application Modernisation with 12-Factor App series and the full App Modernisation playlist on YouTube.
A transcript of the video above is included below.
Drawbacks of committing config
Marc: So back when we started engineering, what we used to do was commit config into our environments. These would be things such as domains, credentials and services that we were using in our solution.
Now, this was very difficult to manage and it caused us lots of challenges that we had to overcome. Such as, it took a long time to spin up new environments because we would then have to add new pieces of config into the code to account for that new environment. Maybe it was working on a new domain or had a new database to work with.
It also meant that we were then locked into using those services on that environment. Unless we made a code change to then point to another service and it made onboarding new engineers very slow because we had to have a different config set up for each engineer.
It also opened up some red flags around security because anybody who was working on the solution knew all of the credentials to every environment because they were committed into the code, but through 12-factor we found a better way. And in this video, I’m going to show you what we did so that you don’t have to deal with any of that.
Marc: Hi, everyone, Great to have you here.
So this is our series on our experiences of application modernisation; what we went through in terms of implementing the 12 factors that led us to better application modernisation; and how that helped us with our scalability, our reliability and the efficiency of working with our code.
We’ve implemented the 12 factor methodology on sites that have millions of visitors, and they’re now very reliable, highly scalable, and they have little to no downtime.
So this is the fourth Video in the series. the third of the 12 factors, because the first video was actually an introduction… so maybe I should have called that a prelude or something.
Other Marc: Marc, they don’t care. Move on.
Marc: So moving on… The third factor is that you should store the application config in the environment.
So why might you want store config in the environment?
Marc: Well, it enables you to swap out backing services very easily.
Say you’re using a Dockerized MySQL instance in your local development environment and you want to use a managed MySQL environment in production. You can quickly swap out those services through use of environment variables.
You don’t need to make any code changes or have any conditionals in the code that say, “use this service if you’re on this environment”. You don’t need any of that. You can just use an environment variable that says, “on this environment, I want to use this service”.
You can do this with all your services. Say you’re using a local file system in development and you’re using an S3 or GCP bucket in production, and you might be doing this with other services such as databases and caching services.
Keep credentials separate from code
Marc: The second benefit is that it enables you to keep credentials separate from code so you don’t actually have to commit any credentials into the code.
Your code base is secure and you don’t have to give credentials to anyone who doesn’t actually need them.
Now, being able to swap out different services between environments very quickly opens doors for us. You can quickly spin up new environments, which means you get fast onboarding and if you want to swap service, you can do so very quickly because you can swap out, say, a MySQL image for Postgres image just by making config change and your framework’s facades and adapter patterns will handle the communication between those services.
If you haven’t seen our video on dependencies, I will link to that here.
Now, traditionally the way to manage that conflict was to commit it into the code, but aside from it being very insecure, it also leads you down the path of having to write these nasty little conditionals in the code.
Now, a better way to manage that, of course, is to use the environment variables and you can put those into a config file. So that you’ve got a different config for every environment you’re working on.
That’s a good first step. But the problem with having loads of config files is that they can quickly add up. So you have too many config files to manage and it becomes inconsistent between the various environments as different people work on the solution.
It’s too easy to commit that config into the version control system, and then you have to change all the credentials or rewrite the history to remove any reference to those credentials, which is very time-consuming.
Use a secrets manager
Marc: So a better way is to actually use a secrets manager or Kubernetes config to inject those environment variables into the environment at runtime. And what you get from this is a very efficient way to manage the various environments and spin up new environments. And you’re not giving those credentials to anybody who doesn’t need access to them.
So I hope that video was useful. Please Like, Subscribe and Share and I’ll see you in the next video.