The 5 Pillars of Good Solution Architecture: Security
A lot of fanfare has been made about the Twelve-Factor App methodology and how it is becoming the best way to approach building a SaaS based application that makes use of microservices. I am one of those fans. When designing a new solution, or upgrading an existing one, having a simple set of guiding principles can be invaluable. And of course, non-functional requirements. But if I look at the Twelve-Factor App methodology, it speaks a lot to the “how”, but not to the “what”. I may very well build a solution that adheres to all Twelve Factors but fail in meeting the non-functional requirements of the desired solution. By definition, I would have delivered a bad Solution Architecture.
Every good Solution Architecture should have a plan for the following 5 things, within which non-functional requirements can be grouped and addressed:
Designing for Security requires a “Defence in Depth” approach. This means that every solution should be continually validating trust as it is executing code and accessing system resources. Commonly referred to as a Zero Trust model, the solution should not make any assumptions about the privileges that the user or system account executing code and accessing system resources has. Trust should be validated at each layer in the solution stack, from the physical layer, through the perimeter and network, all the way down to the compute, application, and data layers.
Be explicit about the requirements at each layer, i.e. what are the Authentication rules (which user accounts and how do they authenticate themselves) and Authorization rules (what do the user accounts have access to) at each layer. There are many tools that can be leveraged to implement and manage these rules so that you do not have to write code to do this from scratch. Most of these tools implement widely accepted standards and best practices, so make use of those. Identity Management systems like KeyCloak implement OpenID Connect standards, provide single sign-on capabilities, and can be extended to support multi-factor authentication very easily.
Security is ultimately about data, and it needs to be clear at each layer what aspect of your data you are securing. There are three options here, Confidentiality, Integrity and Availability, commonly referred to as the CIA principles. At the data layer for example, you would have a requirement to encrypt the data at rest to preserve the Integrity of the data. At the perimeter layer for example, you would have a requirement to prevent DDoS attacks to preserve the Availability of the data. And at the physical layer for example, you would have a requirement to implement biometrics as an additional authentication factor to preserve the Confidentiality of the data.
At any point in time, the data generated and managed by your solution is either at rest, or in transit on some piece of hardware infrastructure. That means that you need to protect the infrastructure your solution is deployed to, apply the best network security you can, and implement the most robust encryption algorithms and techniques. In terms of infrastructure, make sure you have adequate Identity Access Management and role-based security that can access the underlying infrastructure, and that you have adequate failover (more on this later) in place. For Network Security, implement DDoS protection, Firewalls, Gateways and Load Balancers and constantly monitor traffic, limiting resource exposure/access via IP address, port, and protocol restrictions. Be especially careful when deploying microservices to orchestration systems like Kubernetes, and ensure you are not making assumptions about the execution privileges inside a cluster. Encrypt data in transit and at rest, and be explicit about the encryption algorithms that you are using, and how you are using them. Encryption is a massive topic so to do it justice in a small paragraph is impossible, but pay particular attention to Symmetric vs Asymmetric techniques, one-way vs. two-way encryption, and the difference between encryption and hashing of data. Classify data as Public, Private or Restricted, and take action to make sure that Private and Restricted data is always encrypted at rest and in transit and that Restricted data can only be accessed by the owner of the data (like in the case of regulatory requirements like POPIA, PCI, GDPR)
As the last point on Security, none of the above can be effective if you do not have a security mindset when developing the solution. Some refer to this as a ‘culture of security’ within dev teams and organizations. This means that at every stage in the development of your solution, you are validating the solution against your security requirement. Initially with core security training when onboarding developers into your teams, then while developing each feature of your solution evaluating the impact of the security requirements of the solution against that feature. Design for these security requirements by using thread modelling and attack surface analysis, implement the code according to them, verify that the implementation meets the success criteria, release the feature after final security review with an incident and response plan and then implement feedback loops from your monitoring data in your production environment. This the Security Development Lifecyle, and the most important plan you need in place to meet the non-functional requirements grouped in the Security pillar.
In summary, it is useful with each of these pillars to have a baseline or standard that you work from and then evolve and improve. In the next post we take a look at the second pillar, Performance and Scalability, so stay tuned…