I struggled with writing the title for this post, and I worry that it comes over as clickbait. If you’ve come to read this because it looked like clickbait, then sorry*. I hope you’ll stay anyway: there are lots of fascinating** posts and many*** footnotes. What I didn’t mean to suggest is that microservices cause security problems – though like any component, of course, they can – but that microservices are appropriate objects of interest to those involved with security. I’d go further than that: I think they are an excellent architectural construct for those concerned with security.
And why is that? Well, for those of us with a systems security bent, the world is an interesting place at the moment. We’re seeing a growth in distributed systems as bandwidth is cheap and latency low. Add to this the ease of deploying to the cloud, and more architects are beginning to realise that they can break up applications not just into multiple layers but also into multiple components within the layer. Load-balancers, of course, help with this when the various components in a layer are performing the same job, but the ability to expose different services as small components has led to a growth in the design, implementation and deployment of microservices.
So, what exactly is a microservice? I quite like the definition provided by Wikipedia, though it’s interesting that security isn’t mentioned there****. One of the points that I like about microservices is that, when well-designed, they conform to the first two points of Peter H. Salus’ description of the Unix philosophy:
- Write programs that do one thing and do it well.
- Write programs to work together.
- Write programs to handle text streams, because that is a universal interface.
The last of the three is slightly less relevant, because the Unix philosophy is generally used to refer to standalone applications, which often have a command instantiation. It does, however, encapsulate one of the basic requirements of microservices: that they must have well-defined interfaces.
By “well-defined”, I don’t just mean a description of any externally-accessible APIs’ methods, but also of the normal operation of the microservice: inputs and outputs – and, if there are any, side-effects. As I’ve described in a previous post, Thinking like a (systems) architect, data and entity descriptions are crucial if you’re going to be able to design a system. Here, in our description of microservices, we get to see why these are so important, because for me the key defining feature of a microservices architecture is decomposability. And if you’re going to decompose***** your architecture, you need to be very, very clear which “bits” (components) are going to do what.
And here’s where security starts to come in. A clear description of what a particular component should be doing allows you to:
- check your design;
- ensure that your implementation meets the description;
- come up with reusable unit tests to check functionality;
- track mistakes in implementation and correct them;
- test for unexpected outcomes;
- monitor for misbehaviour;
- audit actual behaviour for future scrutiny.
Now, are all these things possible in a larger architecture? Yes, they are. But they becoming increasingly difficult where entities are chained together – or combined in more complex configurations. Ensuring correct implementation and behaviour is much, much easier when you’ve got smaller pieces to work together. And deriving complex systems behaviours – and misbehaviours – is much more difficult if you can’t be sure that the individual components are doing what they ought to be.
It doesn’t stop here, however. As I’ve mentioned on many previous occasions in this blog, writing good security code is difficult*******. Proving that it does what it should do is even more so. There is every reason, therefore, to restrict code which has particular security requirements – password checking, encryption, cryptographic key management, authorisation, to offer a few examples – to small, well-defined blocks. You can then do all the things that I’ve mentioned above to try to make sure that it’s done correctly.
And yet there’s more. We all know that not everybody is great at writing security-related code. By decomposing your architecture such that all security-sensitive code is restricted to well-defined components, you get the chance to put your best security people on that, and restricting the danger of J. Random Coder******** putting something in which bypasses or downgrades a key security control.
It can also act as an opportunity for learning: it’s always good to be able to point to a design/implementation/test/monitoring tuple and say: “that’s how it should be done. Hear, read, mark, learn and inwardly digest*********.”
Should you go about decomposing all of your legacy applications into microservices? Probably not. But given all of the benefits you can accrue, you might consider starting with your security functions.
*well, a little bit – it’s always nice to have readers.
**I know they are: I wrote them.
***probably less fascinating.
****at the time of writing this article. It’s entirely possible that I – or one of you – may edit the article to change that.
*****this sounds like a gardening term, which is interesting. Not that I really like gardening, but still******.
******amusingly, I first wrote “…if you’re going to decompose your architect…”, which sounds like the strap-line for an IT-themed murder film.
*******regular readers may remember a reference to the excellent film “The Thick of It”.
********other generic personae exist: please take your pick.
*********not a cryptographic digest: I don’t think that’s what the original writers had in mind.