Cloud security has become increasingly complex, with organizations often managing fragmented tool stacks. This can easily create blind spots, increase operational overhead, and make it harder for your teams to maintain a consistent security posture.
Cloud-native application protection platforms (CNAPPs) unify cloud security capabilities in a single platform, offering visibility and protection from development to deployment. With CNAPP, you don’t need to run a separate cloud security posture management (CSPM) solution, a cloud workload protection platform (CWPP), and CI/CD security scanning tools, as it consolidates all these functions.
This post explores the core concepts of CNAPP and demonstrates how they work together using a practical example.
CNAPP integrates several security methodologies that are traditionally operated in silos.
CSPM continuously checks for misconfigurations in your cloud infrastructure, e.g., whether your S3 buckets can be accessed publicly or your security groups allow unrestricted access to certain ports.
With CSPM, you gain the visibility you need into your cloud provider to see where attackers can exploit your services.
CWPP protects workloads running in your cloud environment via, for example:
CWPP helps you secure everything you deploy and ensures it stays secure during execution.
In CNAPP, shifting left is paramount. This means integrating all security checks into your pipelines, e.g., IaC, container security, and policy-as-code (PaC) scans, to catch issues before they reach your environments.
Infrastructure drift refers to a discrepancy between a desired and actual state.
When someone makes a manual change to your infrastructure outside of your infrastructure deployment process, they enable drift.
In some cases, you may introduce drift to fix a high-severity issue affecting customers, manually doing so to speed up resolution. But as soon as everything is up and running, you should include that change into your code to ensure the drift is resolved.
Unfortunately, engineers often forget to do this, which is why drift detection is so important. It easily detects discrepancies between your desired and actual infrastructure states. Once notified, you can restore the intended state.
To implement a proper CNAPP, you must map your security controls to recognized compliance frameworks, as this will provide both the required protection and audit evidence.
The Center for Internet Security (CIS) publishes benchmarks that can easily translate directly to CNAPP capabilities:
NIST 800-53 provides a comprehensive security control catalog that also maps to CNAPP:
Now that we’ve explored what CNAPP is and explored the CIS and NIST compliance frameworks, let’s take a look at an example setup of a unified CNAPP.
Let’s take a look at a practical CNAPP implementation. To do this, we’ll start by creating vulnerable IaC in Terraform, and then apply security controls at each layer.
Here’s the Terraform code that creates an EC2 instance and an overpermissive security group:
resource "aws_instance" "this" {
ami = "this_ami"
instance_type = "t2.micro"
}
resource "aws_security_group" "this" {
name = "my-vulnerable-sg"
description = "Vulnerable SG"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = "0.0.0.0/0"
}
}
At a glance, we can see that there are two big issues:
There are several tools for IaC vulnerability scanning. Checkov, an open-source static code analysis tool, performs software composition analysis (SCA) on images and package files.
Let’s run Checkov against this code and see what kind of security vulnerabilities we have:
terraform scan results:
Passed checks: 7, Failed checks: 6, Skipped checks: 0
We have six failed checks. Checkov offers explanations of all checks here, while its output includes fixes for any failed ones. The corrected code is as follows:
resource "aws_instance" "this" {
ami = "this_ami"
instance_type = "t2.micro"
monitoring = true
ebs_optimized = true
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
}
root_block_device {
encrypted = true
}
}
resource "aws_security_group" "this" {
name = "my-vulnerable-sg"
description = "Vulnerable SG"
ingress {
description = "Enable SSH"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = "10.0.2.0/24"
}
}
After running another check, we can see that all the issues were fixed:
Passed checks: 13, Failed checks: 0, Skipped checks: 0
You can see other Checkov scan examples here.
Prowler, which you can easily run with the CIS AWS Foundations benchmark, helps you scan your live AWS environment for misconfigurations. The following command will execute over 73 checks for different services in AWS:
prowler aws --compliance cis_2.0_aws
But let’s make it more specific:
prowler aws -c s3_bucket_default_encryption \
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22
This will check only the EC2 service for security groups, and the S3 service to verify whether S3 buckets have default encryption enabled.
With Prowler, you can see all your security issues at a glance. It also saves detailed results in different formats:
We can see that our AWS account failed a single EC2 check: a security group that has port 22 open.
What about container vulnerabilities? Let’s now take a look at how to scan for those
Let’s build a simple Dockerfile that runs a Python application:
FROM python:3.12 RUN apt-get update && apt-get install -y curl wgetRUN pip install flask requests boto3EXPOSE 8080CMD ["python", "app.py"]
Now, run Trivy on the Dockerfile directly to check for any misconfigurations:
trivy config ./Dockerfile
This is the output we get from Trivy:
Dockerfile (dockerfile)Tests: 27 (SUCCESSES: 24, FAILURES: 3, EXCEPTIONS: 0)Failures: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 2, CRITICAL: 0) HIGH: Specify at least 1 USER command in Dockerfile with non-root user as argumentLOW: Add HEALTHCHECK instruction in your DockerfileHIGH: '--no-install-recommends' flag is missed:
As you can see, we have only three failures, and only two are high severity. Let’s build the image as it is, and then use Trivy to scan it for vulnerabilities:
trivy image your_image_id --severity HIGH,CRITICAL > trivy_result
The results for this example are as follows:
Total: 57 (HIGH: 53, CRITICAL: 4)
Our base image has over 57 High and Critical vulnerabilities. As a best practice, always scan the base images you plan to use before building your Dockerfiles.
A successful Trivy run that shows vulnerabilities (even critical ones) will always have an exit code of 0. So, to fail runs in a CI/CD pipeline when you get High or Critical issues, you could run your scan like this:
trivy image your_image_id --exit-code 1 --severity HIGH,CRITICAL
In a UNIX system, a 0 exit code means that your command has run successfully, while anything non-zero means there was an error.
Now that you’ve scanned your images for vulnerabilities, you need to make sure you’re not deploying containers that introduce issues in your Kubernetes clusters. This is where PaC comes in, helping you block deployments containing certain resources or resource parameters.
PaC isn’t limited to just Kubernetes. It can be used in IaC as well.
Let’s look at a simple deployment for an Nginx application that uses the latest image tag, doesn’t define any resource requests or limits, and adds privileged capabilities:
apiVersion: apps/v1
kind: Deployment
metadata:
name: vulnerable-app
spec:
replicas: 2
selector:
matchLabels:
app: vulnerable-app
template:
metadata:
labels:
app: vulnerable-app
spec:
containers:
- name: vulnerable-app
image: nginx/nginx:latest
ports:
- containerPort: 8080
securityContext:
privileged: true
Now, we can create a Kyverno policy that blocks deployments and other Kubernetes resources that don’t have resource requests and limits:
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata:name: require-resource-limitsannotations:policies.kyverno.io/title: Require Limitspolicies.kyverno.io/category: Limitspolicies.kyverno.io/severity: highspec:background: truerules:- name: require-limitsmatch:any:- resources:kinds:- Pod- Deployment- StatefulSet- DaemonSet- Job- CronJobvalidate:message: >-Resource limits are requiredpattern:spec:=(template):spec:containers:- resources:limits:memory: "?*"cpu: "?*"
Next, run the above policy against the Nginx deployment code:
kyverno apply policy.yaml --resource nginx-deployment.yaml
This is the command output, successfully showing us that there is a problem with the deployment:
policy require-resource-limits -> resource default/Deployment/vulnerable-app failed:1 - require-limits validation error: Resource limitsare required. rule require-limits failed…
To fix the issue, add limits to the resources field:
resources:limits:memory: "256Mi"cpu: "500m"requests:memory: "128Mi"cpu: "250m"
Now, if we re-run Kyverno, the policy will pass:
pass: 1, fail: 0, warn: 0, error: 0, skip: 0
You will need to define separate policies for checking both the latest image tag and privileged capabilities.
Kyverno doesn’t have to run from your CLI; you can deploy all your policies in your Kubernetes cluster, and whenever someone tries to deploy a resource that violates any of these policies, the Admission Controller will deny their creation and explain why this is happening.
Alternatively, you can use Open Policy Agent (OPA), which uses the Rego language. OPA has a steeper learning curve than Kyverno, but can be used for both Kubernetes resources and IaC. Kyverno is also an option for IaC if you build your infrastructure by using Crossplane or Kubernetes operators.
Choosing between the two depends on your tech stack, but in either case, as a best practice in CNAPP, you should implement PaC for all your resources.
In addition to policy as code for Kubernetes, you can use Falco for runtime anomaly detection. By combining Falco with Prometheus, Grafana, and Alertmanager, you can build sophisticated alerts for runtime anomalies and be notified when issues occur.
The next step to implementing CNAPP is to integrate all these security checks into your CI/CD pipeline.
All of the above scans can be easily integrated into your CI/CD pipeline, regardless of whether it uses GitHub Actions, GitLab CI/CD, Jenkins, or another platform. Doing so creates a complete CNAPP implementation by covering all security pillars:
You can also implement drift detection for your IaC code by simply running plans on a schedule and alerting when any changes are detected. There are even dedicated platforms for more sophisticated drift detection, such as Spacelift, Terraform Cloud, Env0, and Scalr. These also offer out-of-the-box remediation workflows, state locking, and other dedicated IaC features.
A pipeline with integrated checks creates an automated and continuous security posture, which is central to CNAPP.
CNAPP brings together traditionally disconnected security mechanisms into a single platform. By unifying CSPM, CWPP, CI/CD security scanning, and drift detection, you achieve consistent policy enforcement, clear visibility into potential vulnerabilities, and reduced overall operational complexity.
Building a unified approach with these solutions provides a solid foundation, but managing them at scale might require specialized tools and investment in maintenance, integrations, and alert correlation.
Ready to simplify your cloud security? RapidScale can help. We provide 24/7/365 managed cloud services, with solutions that include all CNAPP components.
Get back to building applications instead of wasting time on the complex aspects of cloud security. Send a message to a RapidScale expert today.