Leverage Systemic Thinking for Developing Security Patterns

Mehran Koushkebaghi
Nationwide Technology
8 min readOct 4, 2021

Patterns are reusable packages incorporating expert knowledge. It describes a frequently recurring problem and outlines a reusable solution to the problem. There are many reasons that reusability is desirable in an enterprise. To name a few, it reduces costs, ensures consistency and increases the pace of delivery.

My previous article introduced a security engineering manifesto highlighting the fundamental principles and beliefs that define how we deliver security solutions within Nationwide Technology. In this article, I’ll focus on the following tenet and propose Design Pattern Instances that support the development of context-aware security patterns.

Security solutions are context-sensitive; therefore, we value design pattern instances over high-level design patterns.

I’ll propose a methodology for developing design pattern instances and present an example to clarify the approach in the following sections.

Introduction

In the security engineering manifesto, we discussed that security is a systemic matter, and we should consider the environment in which the security problem exists. In this article, I will explain how design pattern instances will assist us in developing context-aware security patterns.

Reductionist Thinking vs Holistic Thinking

Christopher Alexander — who is an influential architect and design theorist — describes patterns as below.

“Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.”

He talks about patterns in building towns and civil structures, but, considering that systems thinking principles are reflected in the building architects practices (watch this if you disagree with me!), it will assist us in gaining a better understanding of a pattern through systems thinking lens.

In essence, he defines a pattern as the core of a solution to a repeating problem in an environment. Therefore there are three high-level steps involved in

  1. Find out a security problem
  2. Design a solution for the particular problem in its environment
  3. Identify the repeating problems and take out the core of the solution

In the next section, I’ll introduce a structured method to implement the above steps.

Methodology

In this section, I’ll introduce a systemic approach to develop security patterns. The process implements the high-level steps described above, starts with creating design pattern instances, and enables us to develop patterns and internal technical standards.

The process includes:

  1. Engaging with the development team (who are building an application) and identify a security problem.
  2. Collaboratively perform threat modelling and obtain a deeper understanding of the data flow between the system components. In this article, I walked through an example of a systemic approach to perform threat modelling.
  3. Design a solution for the specific problem. The solution should be considering the threat model and include the mitigation controls based on the organisation’s risk appetite and environment. It should contain all the necessary implementation details and shouldn’t leave the security-critical decisions to non-security specialists.
  4. Record the solution in a central repository following a peer review from security specialists in relevant domains (application security, cryptography, cloud security, etc.) depending on the security problem. I call these solutions Design Pattern Instances.
  5. Once we have a repository of repeated design pattern instances, we can take out the solution’s core and develop a pattern.

Let’s zoom out for a moment and take a look at the broader picture. The proposed design pattern instance is a specific solution to a particular problem. The design pattern instances lie on the lowest level of abstraction (or no abstraction at all!) and provide all the implementation details required.

As we move down in the diagram, we’re abstracting away some of the details and develop re-usable components that can be utilised across the organisation. The proposed method ensures that the artefacts in the higher level of abstractions(patterns, standards, etc.) contain specific elements of our organisation (environment) and work in various configurations across multiple development teams.

Layers of Abstraction

It is worth noting that, If we were to intervene at a higher level, we might develop patterns (or standards) at a higher pace. However, as those artefacts didn’t consider the environment and didn’t prove their practicality, they will be abandoned by the consumers or become complicated (hence costly) to consume. Although applying changes to higher abstraction levels will lead to a more significant impact, it will only be effective when those constructs are harmonised with our environment and adopted readily.

It is also essential to bear in mind that the security specialists engaged with the development team to build the design instances will utilise the generic industry-standard best practices and guidelines. Still, the final design certainly has some elements that are specific to our environment.

Once we have enough design pattern instances, we can take out the solution’s core and develop a pattern. The derived pattern contains some bespoke elements of our environment. For example, once we have a collection of instances about granting access to AWS S3, AWS SQS, etc., it will enable us to extract the core of the solution and develop a pattern for giving external users access to an AWS resource. Subsequently, a collection of patterns for giving external/internal access to multiple cloud services can contribute to developing a technical standard for IAM in the cloud.

I’ll explore the path to creating design patterns and technical standards in a separate future article. In the next section, I’ll walk you through producing one design pattern instance by giving an example.

Design Pattern Instances

In this section, I’ll explain how to develop a design pattern instance. It is broadly split into three general steps as follows.

  1. Problem Structuring: We’ll use the following subsections to develop the problem context
  • Use Case: background and introduction to the use case
  • Problem Definition: precisely and accurately define the problem that we’re dealing with
  • Assumptions: a list that assists in narrowing down the scope
  • High-level steps: This will explain the sequence of the required steps to accomplish the user story and will be helpful for the creation of the data flow diagrams.

2. Solution Details
In this section, we will develop a design to fulfil the requirement of the problem while considering the existing threats. The design should include high-level diagrams and necessary implementation details.

3. Test
This section should explain how a security engineer will validate the design after the implementation is completed.

An Example

This section will go through an example and demonstrate how to implement the above methodology to develop a design pattern instance. To reuse the threat model, I used the same example I gave in the threat modelling article. As mentioned above, although the design instance will use some of the AWS best practices and guidelines, it contains some unique elements of our environment.

1. Problem Structuring

1.1. Use Case: An external third party platform is being used in building a payment platform. Several microservices are interacting with external service API for processing a transaction. The 3rd party offers a notification mechanism to inform us of events in the system(such as the arrival of an inbound payment, the successful submission of an outbound payment, etc.). The notification mechanism allows us to use an Amazon SQS queue to receive notifications.

1.2. Problem Definition: Enabling an external party to push notifications to an SQS queue deployed in our AWS Account

1.3. Assumptions: The external platform cryptographically signs the messages before publishing them to the queue to ensure their integrity and authenticity. The details of the message signing and the verification are beyond the scope of this design.

1.4. High-level steps

  • Provisioning a queue in our AWS Account.
  • Configuring SQS queue policy to grant required access to the external party principles.
  • Enabling server-side encryption for the SQS queue.
  • Configuring the KMS key policy to allow SQS to encrypt the published messages

2. Solution Design

The below diagram shows the main components of the system. This section includes all the necessary details to implement the solution.

SQS 3rd party access

2.1. Provisioning a standard queue in our AWS Account

2.2. Configuration of the queue resourced-based policy

  • Attaching the following policy to the SQS queue will give the <EXT_ROLE_NAME> role the required level of permissions to publish messages to the queue.
{      
"Version": "2012-10-17",
"Statement": [{
"Sid":"Allow the external party to send messages",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam:<EXT_AWS_ACC_ID>:role/<EXT_ROLE>"
] },
"Action": "sqs:SendMessage",
"Resource":
"arn:aws:sqs:<AWS_REGION>:<OUR_AWS_ACC_ID>:<QUENE_NAME>"
}]
}
  • In order to allow only encrypted connection over TLS, the following condition should be added to the queue policy.
"Condition" : {
"Bool" : {
"aws:SecureTransport":"true"
}
}
  • To create another layer of protection, we can whitelist the external party CIDR via condition policies.
"Condition" : {      
"IpAddress" : {
"aws:SourceIp":"<EXT_CIDR_RANGE>"
}
}

2.3. Enabling Server-Side Encryption for the deployed queue

  • AWS SQS can use both AWS managed CMK and Customer managed CMK from the KMS to encrypt the messages in the queue. As we need cross-account access to the KMS key (to enable the external party to publish messages to the queue), the Customer managed CMK should be used as it gives us the ability to define our Key policy.
  • The SQS allows the publisher to include structured metadata with messages using message attributes. SQS doesn’t encrypt message attributes, so it is crucial to bear in mind that the encryption of the queue doesn’t protect the message metadata.

2.4. Configuration of the KMS key policy

  • The KMS key policy should be configured — as below — to only allow IAM role in the external platform AWS account to call Decrypt & GenerateDataKey API.
{     
"Sid": "Enable the external party",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::EXT_AWS_ACC_ID:role/<EXT_ROLE_NAME>"
},
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "*"
}
  • Adding this condition the policy ensures that the external principle can’t directly call KMS API and the request should always come through SQS.
"Condition" : {
"StringEquals" : {
"kms:ViaService":"sqs.<AWS_REGION>.amazonaws.com"
}
}

3. Test

Assuming the engineering team utilises infrastructure-as-code to implement the design, a security engineer can review the code changes before integration to the code repository. Automated tools — embedded in the CI/CD pipeline — can be used to verify the changes. I’ll write about utilising policy-as-code for this purpose in a later post.

Conclusion

In this article, I introduced a systemic approach for developing security patterns by walking through an example.

The design pattern instances are solutions to specific problems in our environment; therefore, the emerged patterns are suitable for our organisation and will willingly be consumed by the development teams. The approach takes advantage of systems thinking, appreciates the context-sensitivity of security problems and enables the security specialists to deliver security pattern that works perfectly for the organisation.

In the following articles, I’ll present an example of creating design patterns from various design pattern instances. If you’re interested to know how we solve security problems, watch this space.

References

Christopher Alexander (1978) A Pattern Language: Towns, Buildings, Construction.Berkeley: Center for Environmental Structure

Russell L. Ackoff. Systems Thinking. https://youtu.be/OqEeIG8aPPk?t=425

--

--