Kubernetes environments are complex. It's a challenge to keep track of clusters, jobs, namespaces, deployments, nodes, pods, and roles, to ensure everything is configured securely, and to visualize how the parts fit together. The Kubernetes plugin made it possible to write SQL queries to answer questions about your K8s environment. Building on that foundation, the Kubernetes Compliance mod added benchmarks and controls for CIS, NSA, and CISA best practices. Then the Kubernetes Insights mod delivered a wealth of instant answers to common questions, along with powerful relationship graphs to help you visualize the environment.
At first all K8s queries — your own custom ones, and those that power benchmarks and dashboards — fetched data from live clusters. Now we've enhanced the plugin with the ability to query manifests and helm charts too. Let's look at some queries and controls that use the new capability with a simple helm chart example.
Query helm charts and Kubernetes deployments
This query returns two rows from the kubernetes_deployment table.
selectsource_type,name,creation_timestampfromkubernetes_deploymentwherename = 'cherry-chart'order bycreation_timestamp desc
+----------------------+--------------+---------------------------+| source_type | name | creation_timestamp |+----------------------+--------------+---------------------------+| helm_rendered:charts | cherry-chart | <null> || deployed | cherry-chart | 2023-10-03T10:32:09-07:00 |+----------------------+--------------+---------------------------+
Why two rows? We've configured the plugin's source_types
argument as ["deployed", "helm"]
. So we're querying both the rendered helm chart — which doesn't know the creation_timestamp
— and the deployment which does.
Scan helm charts and Kubernetes deployments
The Kubernetes Compliance
mod builds on this foundation. For example, it's a best practice not to use the default namespace for a ServiceAccount
. There's a control to check for that, based on this query.
selectcoalesce(uid, concat(path, ':', start_line)) as resource,casewhen namespace = 'default' then 'alarm'else 'ok'end as status,casewhen namespace = 'default' then name || ' uses default namespace.'else name || ' not using the default namespace.'end as reason,name as service_account_name,coalesce(context_name, '') as context_name,namespace,source_type,coalesce(path || ':' || start_line || '-' || end_line, '') as pathfromkubernetes_service_account;
Running the control shows that the helm chart and deployment are both green: no default namespace.
Now somebody improperly sets the namespace to default
in serviceaccount.yaml
.
{{- if .Values.serviceAccount.create -}}apiVersion: v1kind: ServiceAccountmetadata:namespace: defaultname: {{ include "buildachart.serviceAccountName" . }}labels:{{ include "buildachart.labels" . | nindent 4 }}{{- end -}}
Now the control shows a mismatch between the chart and the deployment.
But we're going to deploy anyway.
helm upgrade my-cherry-chart buildachart/
Now the chart and the deployment are both in the alarm state.
Let's properly set a namespace in the helm chart.
{{- if .Values.serviceAccount.create -}}apiVersion: v1kind: ServiceAccountmetadata:namespace: cherry # must not be default!name: {{ include "buildachart.serviceAccountName" . }}labels:{{ include "buildachart.labels" . | nindent 4 }}{{- end -}}
Now we're back to a mixed result: the chart is green, but the deployment is still red.
After redeploying, we're back to green all around.
See it in action
A wealth of queries and controls
We've looked at just one of the 790 controls provided by the Kubernetes Compliance
mod. Collectively they support best practices defined by CIS Kubernetes v1.20, CIS v1.7.0, and NSA and CISA Kubernetes Hardening Guidance v1.0. Those controls build on 781 queries. Use them out of the box, or reuse and remix to suit your needs. And please do let us know how it goes!