This is a guest post by Chris Tozzi.
Not too long ago, IT security models were relatively straightforward. They were broken into layers—the infrastructure layer, the application layer, sometimes the network layer, and so on. Each layer was associated with different types of risks, and the task of each dedicated security team was to implement the necessary controls within each layer to address those risks.
But those days are over. Thanks to cloud-native architectures and technologies like infrastructure as code (IaC), the lines between application security and infrastructure security are blurring together. As a result, security teams need to develop new types of security models. Instead of thinking in terms of layered security risks and tooling, they must implement protections that can identify and mitigate risks across their entire stack, with the understanding that risks in one layer could exacerbate risks in another layer.
How AppSec and CloudSec have blurred
When we talk about “layers” in a traditional application stack, we’re referring to the distinct types of resources required to deploy and run an application. In a traditional cloud environment, those layers typically included:
- A VM from a public cloud IaaS service, which provided the application’s host server as well as its storage and networking resources
- An application that was deployed on top of the host server
In most cases, that was about it. You had your cloud infrastructure layer, and you had your application layer. Unless you had a complex networking setup, used a scale-out, or used a distributed storage cluster, there really wasn’t much to think about beyond the application and the host server.
Now, compare that to a cloud-native stack, which might look like this:
- VMs from a public cloud IaaS service provide the underlying host infrastructure.
- A Kubernetes control plane manages the VMs as a set of nodes within a cluster.
- Kubernetes is responsible for managing networking and storage, and makes both available to containers with the help of plugins and possibly a service mesh.
- Application binaries are hosted in a container registry as container images.
- Applications are deployed as containers—or, in certain cases, serverless functions—on top of the Kubernetes cluster.
- Auxiliary tooling, such as monitoring and observability services, is provided by sidecar or daemonset containers. They are also deployed on Kubernetes inside containers, even though they are more application management tools than applications.
In this type of environment, where does the infrastructure layer stop and the application layer begin? It’s not exactly an easy question to answer. You could argue that containers are part of the application layer because they contain the code for your application. But you could make an equally valid argument that containers are part of the cloud infrastructure layer because they provide part of the hosting environment in which the application code runs.
Similarly, the Kubernetes orchestration layer doesn’t exist in a conventional cloud environment. But you could argue that Kubernetes is part of the application layer because it also orchestrates applications in the form of containers.
We could continue with this experiment of deconstructing the layers of a cloud-native environment, but you get the point—there are no clear boundaries between the application and infrastructure layers. No matter how you spin it, you can’t neatly categorize each type of resource as falling into one distinct layer or the other.
IaC blurs the lines between AppSec and infrastructure security even further
The lines between applications and infrastructure are hard to define not just because of the complexity and interdependent nature of cloud-native architectures. Part of the issue is also that, in many cases, most of the resources in a cloud-native stack are configured using the same type of tool—IaC.
Let’s look at an example. Containers that could be in either the application layer or the infrastructure layer contain application code and IaC in the form of Dockerfiles. Kubernetes manifests fit the declarative IaC model as well. And the underlying VMs or managed Kubernetes can also be deployed using IaC such as Terraform. All of this code is developed, version controlled, and managed in a CI/CD pipeline, just like application code.
What this means is that, from the perspective of developers, IT engineers, and security teams, the differences between the various components of a cloud-native hosting stack don’t actually matter that much. They’re all defined and provisioned using IaC templates, so from an operational viewpoint, they all end up looking and working the same. This introduces efficiencies, since the same teams can use their existing tools and processes to build both application and infrastructure components. But with those efficiencies come additional security considerations.
Security risks that used to be related only to AppSec now bleed over into infrastructure security. If a Kubernetes manifest pulls a container, that manifest can contain infrastructure misconfigurations—such as allowing users to grant privileged access to the container—and application vulnerabilities in the container image.
Scanning for only one type of issue, or only looking in the traditional spots for vulnerabilities, leaves you blind to the risks that span or are impacted by both domains. In this scenario, only looking for infrastructure misconfigurations will leave you blind to your vulnerabilities. And only looking at vulnerabilities in isolation will mean that you’ll underestimate the risk of a medium severity vulnerability that’s exacerbated by its position in a privileged container.
Why we need a new approach to AppSec
Given that all layers of a cloud-native environment can be defined and managed through IaC, you might think that most teams would be using IaC as the foundation of their security strategy.
But IaC is relatively new in comparison to the security solutions that have cropped up in the past few decades, and most organizations don’t have a consolidated or connected view into their IaC security and all of the components their IaC touches.
Instead, what we see out in the wild is that teams are still thinking in terms of AppSec versus CloudSec and therefore have different tools for each need. Teams use one set of tools to scan their applications for security risks, and another set of tools to validate their infrastructure configurations.
But this approach is no longer enough to maintain complete application and infrastructure security. Not only does it require engineers to juggle disparate tools, it also makes it harder to identify all security risks and take a DevSecOps approach to AppSec and infrastructure security. With a comprehensive DevSecOps approach, risks are found and mitigated using a centralized, consolidated process—no matter which part of the CI/CD process introduced the risks or which team was responsible for them.
Let’s consider how Kubernetes security risks could be overlooked when a team treats AppSec and infrastructure security as separate endeavors. In this scenario, they’d scan their applications and then would scan their underlying cloud infrastructure. But they may forget to scan their Kubernetes deployments, leaving themselves blind to the risks that could exist in that layer of their environment. Even if they scanned each of these layers in isolation, they would still miss the vulnerabilities that span layers or are impacted by other layers.
A cohesive, IaC-based approach to modern, cloud-native security
There is a better way to adapt security to the changing nature of cloud-native security. By leveraging IaC as the foundation for security validation, DevSecOps teams can ensure cohesive, comprehensive scanning of all their resources, no matter how many layers they need to assess or how they choose to define those layers.
In other words, by scanning the IaC templates that are used to configure all components of a cloud-native stack—VMs, cloud access policies, container images, Kubernetes deployments, and beyond—it becomes possible to check for security risks across the entire stack using a single tool. This unified, cohesive approach helps catch issues that would otherwise slip through the cracks if each domain was scanned independently with disparate tools.
With an IaC-based approach, if you detect a vulnerability in application source code, you’ll also know which container images and Kubernetes deployments that vulnerability affects and therefore can easily mitigate the underlying problem. That’s a lot more efficient than the traditional approach to security, where you would know that a source code risk exists but would have no idea what other layers of your stack were affected because you used different tools and processes for identifying and scanning those other layers.
The result of adopting an IaC-based approach is not just fewer tools to manage, but also better prioritization of risks because it’s easier to understand how each risk affects the larger stack—as well as what its root cause is.
We live in a cloud-native, IaC-centric world where it’s much harder to distinguish applications from infrastructure. As a result, we need a new approach to security that treats AppSec and CloudSec as one and the same and also enables teams to completely adopt DevSecOps for their cloud-native apps and infrastructure.