By Iheanyi Onwubiko
Enhancing Helm chart security and policy compliance with OPA
Managing Kubernetes applications correctly is as crucial as their development. Helm charts are a pivotal tool for deploying and managing these applications efficiently.
However, ensuring that these deployments are secure and adhere to best practices requires robust oversight. This is where the Open Policy Agent (OPA) plays a vital role by enforcing a set of standardised rules.
Leveraging Conftest for OPA policy enforcement
Conftest is a tool that supports DevOps teams by testing structured configuration data against predefined policies, ensuring configurations are correct prior to deployment. These policies, written in the Rego language from OPA, consist of rules that define the necessary logic to enforce desired behaviours. Together, Conftest and OPA create a powerful ecosystem for automating and managing policy enforcement effectively.
The benefits of integrating OPA with Helm
Integrating OPA with Helm chart development enhances Kubernetes management by automating the validation of the Helm templates. This approach not only addresses the challenges of manual checks, but also mitigates potential inconsistencies as Kubernetes environments scale. OPA's policy-as-code model assures uniform policy application across clusters.
Preparing your environment
To integrate Open Policy Agent (OPA) with Helm, you will need several tools and a basic understanding of key technologies:
Helm: Helm installation guide.
Conftest: Conftest installation guide.
Local Kubernetes cluster: Optionally, use Minikube or Kind for realistic testing and validation of Helm charts.
Additionally, familiarity with writing OPA policies in Rego, understanding Helm chart structures and Kubernetes resource management is important. In essence, what we are trying to achieve with this is to validate the final Kubernetes manifests; thus knowledge of the chart will help to fix issues.
For practical demonstrations, I'll reference the helm-OPA-policy-testing-templates repository on GitHub, which showcases example policies to maintain standards and recommended practices in Kubernetes.
Repository structure
mars/: Contains the Helm chart that will be tested — “mars” is just a random name for the chart to be tested.
templates/: Includes Kubernetes resource templates such as ConfigMaps and Ingresses.
chart.yaml: Details the chart version and metadata.
values.yaml: Holds default configuration values.
policy/: Includes OPA policies structured by enforcement type:
deny/: Policies that block deployments under specific conditions.
violation/: Policies that identify non-adherence to best practices.
warn/: Policies that issue warnings for potential issues.
helpers/: Common functions used across various policies.
Leveraging helper functions in Conftest
Helper functions in Conftest streamline policy management by consolidating common logic into reusable components. It simplifies policy creation, enhancing clarity and manageability. The helper functions we will use in the upcoming example scenario are in the kubernetes.rego file in the repository. For detailed examples and guidelines on using these functions, please see the helper functions documentation.
Scenario: Enforcing key policies with Conftest
In this example scenario, we'll use Conftest to enforce two key policies for developing our Helm charts. Firstly, we prohibit the use of the 'latest' image tag for all containers to prevent unpredictability in deployments. Secondly, we mandate that all Kubernetes deployments include specific labels to improve management, visibility and recommended best practices.
Prohibiting 'latest' tag policy*:*
package main
import data.kubernetes
name := input.metadata.name
violation[msg] {
kubernetes.containers[container]
[image_name, "latest"] = kubernetes.split_image(container.image)
msg = kubernetes.format(sprintf("%s in the %s %s has an image, %s, using the latest tag", [container.name, kubernetes.kind, image_name, kubernetes.name]))
}
This policy achieves the following:
kubernetes.containers[container]
: Iterates over each container.[imagename, "latest"] = kubernetes.splitimage(container.image)
: Splits the container image string to check if it uses the "latest" tag.msg = kubernetes.format(sprintf(...))
: Generates a standardised error message if a container uses the "latest" tag, detailing the container's name and the type of Kubernetes object it belongs to.
Enforce recommended labels policy:
package main
import data.kubernetes
name := input.metadata.name
deny[msg] {
kubernetes.is_deployment
not kubernetes.required_deployment_labels
msg = sprintf("%s must include Kubernetes recommended labels: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/#labels", [name])
}
This policy does the following:
kubernetes.is_deployment
: Confirms the resource is a Kubernetes deployment.not kubernetes.requireddeploymentlabels
: Condition checks whether the deployment is missing the necessary labels. Therequireddeploymentlabels
function, which performs this verification, is defined in the helper functions file.msg = sprintf(...)
: Generates an error message for non-compliant deployments, directing users to a URL with labelling best practices.
How to apply these policies:
Save the policies in a .rego
file within a "policy" folder. Conftest defaults to searching for rules in a directory named "policy." To specify a different location, use the --policy
or -p
flag when running tests.
Run the following command from the root of your repository to test Helm charts against the defined OPA policies:
helm template mars | conftest test -p policy/ -
This command sequence ensures your Helm chart configurations comply with OPA policies before deployment:
helm template mars
: Generates Kubernetes YAML files from themars
Helm chart.|
(pipe): Passes the YAML output to the next command.conftest test
: Uses Conftest to evaluate the YAML files against the policies in thepolicy/
directory.-p policy/
: Specifies the directory where the policy files are located.-
: Indicates that Conftest should read input from the standard input (stdin), provided by the pipe.
You should see an output similar to the screenshot below, indicating policy enforcement failures:
FAIL - - main - release-name-mars must include Kubernetes recommended labels: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/#labels
FAIL - - main - mars in the Deployment nginx has an image, release-name-mars, using the latest tag
This indicates that our Helm charts do not comply with our policies. For example, as highlighted in the _helpers.tpl file
, there are missing deployment labels:
'Fig 1: Missing required labels'
Furthermore, in the values.yml
file, it appears that no specific image tag is defined, which defaults to using the "latest" tag:
'Fig 2: Undefined specific image tag'
To align our Helm charts with the policies, we need to define the deployment labels in accordance to what the policy expects, and specify an image tag. We will now update the respective files, as highlighted in the images below:
‘Fig 3: Defined required labels’
‘Fig 4: Image with a specific tag’
After implementing these fixes, rerunning the command helm template mars | conftest test -p policy/ -
should not yield any policy failures.
Conclusion
This blog has highlighted the benefits of integrating Open Policy Agent (OPA) with Helm chart development to safeguard Kubernetes deployments. By enforcing standardised policies using Conftest and OPA, teams can ensure their Helm charts meet high security and compliant standards. Moreover, DevOps teams can integrate this mechanism into their GitOps workflow to streamline template validation and necessary security checks, embedding them directly into the deployment process.