Earlier this month President Biden issued an executive order on cybersecurity following the Colonial Pipeline Hack. It outlines several actions that government departments must take, and requires them to adopt modern software development and security best practices. This post will explore several of these best practices and explain how Armory’s policy engine addresses them. We will also explore how Armory’s approach differs from other available solutions.
Compliance Checks for Deployed Infrastructure
A major theme in the executive order is ensuring that deployed infrastructure complies with policies. There are three ways companies enforce policies for deployed infrastructure today. Sometimes companies only adopt one of these approaches but ideally, they should utilize a multi-layered approach to security. Leveraging multiple types of controls maximizes the likelihood that even if one control fails, another will still keep your systems safe. An additional layer of security is offered by each of these three approaches, and they are best combined.
Written Policies
The first thing most companies do is to create a formal policy. It will be written down, staff will be trained, and the policy will be audited.
Consider an example policy requiring encryption for data at rest. The auditor selects a random set of data volumes, and checks to see whether or not they are encrypted. While this type of audit is a great backup plan, it is not sufficient to ensure the policy is never violated. In between the audit periods your data may be sitting unencrypted. When the audit does arrive only a subset of data volumes are typically audited, so the unencrypted data may fail to be identified.
While written policies and audits are important, they are inadequate on their own to keep your information secure. However, they serve as a safety net in case other controls break.
Security Scanners
Many companies run security scanning software. This software runs on a schedule (often nightly) and automatically performs an audit. Typically these scanners check specific things, such as volume encryption, or the presence of common vulnerabilities.
Scanners improve on a manual audit process by allowing the audit to happen more frequently, and against all resources instead of just a subset. However, these scanners merely decrease the time to detect a vulnerability, they do not prevent it from being introduced in the first place. Many security scanners also lack automated remediation, further increasing the amount of time during which the vulnerability exists.
Deploy-Time Policy Enforcement
There are a small number of tools (Such as Armory Policy Engine, or Amazon Config Rules) that actively enforce your policy at deploy time. In the case of Armory’s policy engine, the policy will prevent the deployment entirely if it violates policy. In the case of an Amazon Config Rule, a check is run immediately after a configuration change, and an automated remediation action can be triggered.
Policy engine allows your deployment pipeline to check automated rules at deploy time. If any of these rules fail, the deployment will be rejected. With Policy Engine the insecure software never enters production. Of the options discussed this is the only option that keeps the security vulnerability from ever being deployed. This approach also pairs well with your existing security scanners. The security scanners can monitor for new vulnerabilities after deploy (Such as newly identified CVEs), while Policy Engine prevents code with known vulnerabilities from being deployed in the first place. Armory can also provision test environments, and require a pass of the security scanner as part of your deployment pipeline. We’ll talk more about this in the ‘Run Security Scans Before Deployment’ section.
Here are some examples of deployed infrastructure policies required by Biden’s executive order, and how Policy Engine can enforce them.
Section 4.e.i.E: requires employing encryption for data at rest.
In Kubernetes, persistent volume claims can specify what storage class they want to use. Whether or not data in encrypted will typically vary by storage class. For example, here is how you create a new encrypted storage class for Amazon EKS.
The policy below prevents application developers from deploying on any storage class that has not been approved. It also prevents infrastructure engineers from provisioning a storage class that is unencrypted. These two separate layers of enforcement provide a multi-layered approach to ensuring data is always on encrypted volumes. Both controls would need to fail before data could be deployed on an unencrypted volume. This policy expects the list of approved storage classes to be loaded into OPA’s data document, in an array named ‘approvedStorageClasses’:
package spinnaker.execution.stages.before.deployManifest
deny [“You cannot create unencrypted storage classes”] {
some i
input.stage.context.manifests[i].kind==”StorageClass”
params := object.get(input.stage.context.manifests[i],”parameters”,null)
object.get(params,”encrypted”,”false”)!=”true”
}deny [“You must use an approved encrypted storage class”]{
some i
input.stage.context.manifests[i].kind=”PersistentVolumeClaim”
storageClass := object.get(input.stage.context.manifests[i].spec,”storageClassName”,null)
not isApprovedStorageClass(storageClass)
}isApprovedStorageClass(storageClass){
(storageClass == data.approvedStorageClasses[_])
}
Section 3.d: requires encryption of data in transit.
Whether or not data is encrypted in transit depends on what network protocols are used. For example, HTTP is not encrypted, but HTTPS offers the same functionality in an encrypted form. Different protocols use different network ports, and Policy Engine can enforce policies that regulate what network ports can be exposed. For example, here is a policy that prevents exposing the following protocols while allowing their more secure equivalents: HTTP, FTP, TELNET, POP3, NNTP, IMAP, LDAP, SMTP. This example prevents both pods and services from being deployed that expose these ports:
package spinnaker.deployment.tasks.before.deployManifest
blockedPorts :=[20,21,23,80,110,119,143,389,587,8080,8088,8888]
deny[“You cannot leverage unencrypted network protocols. A port typically used by an unencrypted protocol was detected.”] {
check if it is a service with either an insecure port or target port.
manifest := input.deploy.manifests[_]
manifest.kind == “Service”
port := manifest.spec.ports[_]
any([object.get(port,”port”,null) == blockedPorts[_],
object.get(port,”targetPort”,null) == blockedPorts[_]])
} {check if it is a pod exposing an insecure port.
input.deploy.manifests[_].spec.containers[_].ports[_].containerPort=blockedPorts[_]
} {Check if it contains a pod template exposing an insecure port.
input.deploy.manifests[_].spec.template.spec.containers[_].ports[_].containerPort=blockedPorts[_]
}
Run Security Scans Before Deployment
President Biden’s Executive Order requires “employing automated tools, or comparable processes, that check for known and potential vulnerabilities and remediates them…at a minimum prior to product, version, or update release.” Many companies execute security scanners against deployed code prior to releasing it, but this is often manual, and rarely done with enough control to ensure it happens every time code ships. Because it is a manual process companies sometimes only enforce the scan for a subset of releases, which creates a security hole.
Analyze Pipeline Structure
Armory allows your application delivery teams to automate your software delivery pipeline. While doing so, Policy Engine can analyze the pipeline steps to ensure that necessary process checks take place. This allow you to, for example, write a policy that prohibits deploying to a production account unless your security scans have already been run in a staging environment. Here is an example policy that simply requires a manual approval prior to any deployment to a production account:
package opa.pipelines
production_accounts := [“prod1″,”prod2”]
deny[“production deploy stage must follow a manual judgement stage”] {
some j
input.pipeline.stages[j].type==”deployManifest”
input.pipeline.stages[j].account==production_accounts[_]
approvers := [i | input.pipeline.stages[i].type==”manualJudgment”; i<j]
count(approvers)==0
}
Role based access control can also be leveraged to restrict who can provide the approval. This ensures that the personnel responsible for each control have signed off before deployment.
Alternately the manual approval stage can be replaced with any other pipeline stage, for example a stage that automates the security check. Some of our customers require all pipelines to have security scanning stages prior to any production deployment stage. In this way they require application developers to deploy their application to staging, and run a security scanner before deploying it to production. However, for the application developers it is a single automated deployment pipeline that they can control. The pipeline deploys to staging, scans, and finally deploys to production if everything looks good.
Integrate with External Systems
If your security scanners provides a list of scanned and approved images, Policy Engine can also be configured to prohibit deployment of any images that are not on the list. Policy Engine Policies are executed by Open Policy Agent (OPA). OPA allows external systems to load such data into its data document, and also allows policies to invoke APIs to retrieve such data. This example assumes that you have loaded an array named ‘approvedImages’ into the OPA data document, and it will reject manifests that leverage images that are not in the approved list:
package spinnaker.deployment.tasks.before.deployManifest
deny[“Your manifest creates a pod from an image that has not been approved by the security scanning process.”] {
Check pod templates
isImageUnApproved(input.deploy.manifests[_].spec.template.spec.containers[_].image)
} {check pods
isImageUnApproved(input.deploy.manifests[_].spec.containers[_].image)
}
{check pod template initContainers
isImageUnApproved(input.deploy.manifests[_].spec.template.spec.initContainers[_].image)
}
{check pod initContainers
isImageUnApproved(input.deploy.manifests[_].spec.initContainers[_].image)
}isImageUnApproved(image){
not isImageApproved(image)
}isImageApproved(image){
image==data.approvedImages[_]
}
Reporting Requirements
While details about the reporting requirements are not in the executive order, the executive order makes it clear that there will be reporting requirements for national security systems. Agencies will also need to establish log management practices that provide visibility to the highest level security operations center in each agency.
Armory policy engine allows you to easily assemble a history of all changes to your production environment. Anytime Armory deploys code, it will perform a policy check. The policy check logs details of what is being deployed, who triggered the deploy, as well as the results of evaluating the policy. This information is logged in Open Policy Agent’s Decision logs which can be collected in a log analytics tool to enable easy auditing of historic changes to production.
Wrapping Up
This executive order requires improvement in all government agencies and contractors. It acknowledges that the security of our nation is only as good as the security of our software supply chain.
However, this should be a wake up call to corporate America as well. Colonial Pipeline was a private company, not a government agency. This hack massively disrupted their business, and our country. We all have a duty to maintain the security of our critical systems, and for software this starts by securing our software delivery pipelines. If you are not confident in the security of your software delivery pipeline, request a demo of how Armory can improve your security by automating your policy as code.
The post How Armory’s Policy Engine can Improve our Nation’s Cybersecurity appeared first on Armory.
Top comments (0)