Containers
Policy-based countermeasures for Kubernetes – Part 2
Choosing the Right Policy-As-Code Solution
In Part 1 of this series, we introduced the concept of policy-as-code (PaC), and discussed the following solutions: OPA, OPA/Gatekeeper and MagTape.
In this post (Part 2) we will review the Kyverno and k-rail PaC solutions.
For Kubernetes, there are several PaC solutions available in the open-source software (OSS) community. The following list is of PaC solutions, with their respective Cloud Native Computing Foundation (CNCF) project status (if applicable):
- Open Policy Agent (a.k.a. OPA or OPA/classic) – https://www.openpolicyagent.org/ (covered in Part 1)
- CNCF Project Status – Graduated
- OPA/gatekeeper (a.k.a. Gatekeeper) – https://github.com/open-policy-agent/gatekeeper (covered in Part 1)
- Part of OPA, CNCF Project Status – Graduated
- Kyverno – https://kyverno.io/
- CNCF project status – Sandbox
- k-rail – https://github.com/cruise-automation/k-rail
- MagTape – https://github.com/tmobile/magtape (covered in Part 1)
As we explore the PaC use cases, we will discuss the characteristics of each solution and point out aspects that can help organizations choose the best fit for their requirements.
All of the preceding solutions integrate with the Kubernetes API server using admission controllers and webhooks. These admission controllers are enabled for all Amazon Elastic Kubernetes Service (EKS) clusters; moreover, all of these solutions work well to validate EKS (EC2 and AWS Fargate) inbound Kubernetes API server requests.
Kubernetes integration and operation
In Kubernetes, the control plane is responsible for maintaining the desired state of a cluster. Requests are made to the control plane via calls to the Kubernetes API server. Valid changes are persisted into etcd by the API server. In fact, only the API server interacts directly with etcd. Once the desired state changes are in etcd, the API server, along with controllers and kubelets, ensure that actual cluster state reflects desired cluster state, which is stored in etcd.
Kubernetes admission controllers are a means by which the API server request flow can be intercepted and extended for operational needs, such as enforcing security controls and best practices.
According to Kubernetes documentation:
An admission controller is a piece of code that intercepts requests to the Kubernetes API server prior to persistence of the object, but after the request is authenticated and authorized.
As seen in the flow following diagram, PaC solutions work with the mutating and validating admission controllers in the API server request flow. Every Kubernetes cluster state change request goes through the API server request flow. Successful requests are persisted into etcd in the cluster control plane.
The PaC solutions can mutate inbound API server request JSON payloads, before Kubernetes object schema validation is performed. After Kubernetes object schema validation is performed, the PaC solutions policy engines can validate the inbound request, by matching policies to the request JSON payload, and using the policies to verify correct data in the payload. All of the preceding solutions are installed within the cluster.
Kubernetes API server webhooks for mutating and validating API server requests can be configured to use services outside of the respective Kubernetes cluster, as seen in this blog: https://thinkwithwp.com/blogs/containers/building-serverless-admission-webhooks-for-kubernetes-with-aws-sam/
PaC solutions are integrated to a Kubernetes cluster API server, as an admission webhook target, via the Kubernetes ValidatingWebhookConfiguration resource. The following is an example configuration.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: policy-validating-webhook-cfg
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: <ENCODED_CERTIFICATE_DATA>
service:
name: <SERVICE_NAME>
namespace: <SERVICE_NAMESPACE>
path: /<SERVICE_PATH>
port: <SERVICE_PORT>
failurePolicy: Ignore
matchPolicy: Equivalent
name: <WEBHOOK_NAME>
namespaceSelector: {}
objectSelector: {}
rules:
- apiGroups:
- <KUBERNETES_API_GROUP>
apiVersions:
- <API_VERSION>
operations:
- CREATE
- UPDATE
resources:
- <KUBERNETES_RESOURCE>
scope: '*'
sideEffects: NoneOnDryRun
timeoutSeconds: 3
For the purposes of this post, we will examine validation policies and configurations from multiple solutions.
Guardrails and instant feedback
Using validating admission controllers and PaC solutions allows organizations to erect guardrails that prevent unwanted cluster changes, while still enabling users to move fast. The following example response is from a Kubernetes API server request. The request was a kubectl apply -f ...
request to create a Kubernetes Deployment resource, where the source image registry in the container spec was not on a list of allowed registries.
Error from server ("DEPLOYMENT_INVALID": "BAD_REGISTRY/read-only-container:v0.0.1"
image is not sourced from an authorized registry. Resource ID (ns/name/kind):
"test/test/Deployment"): error when creating "tests/11-dep-reg-allow.yaml":
admission webhook "validating-webhook.openpolicyagent.org" denied the request:
"DEPLOYMENT_INVALID": "BAD_REGISTRY/read-only-container:v0.0.1" image is not
sourced from an authorized registry. Resource ID (ns/name/kind):
"test/test/Deployment"
The API server sent the request payload to a PaC policy engine service installed in the cluster. The policy engine applied a matching policy and determined that the API server request payload was invalid. Matching and validation were based on the rules defined in the policy. The policy engine service responded to the API server with a boolean False, and a message of why the request was invalid. Then the API server (within 1-2 seconds) responded to the requester, in this case, the kubectl
client. The end result was instant feedback from the cluster that (1) the request failed and (2) why it failed. This fast-failure with instant feedback improved the user-experience and helped the user quickly troubleshoot and correct their mistake.
Policy authoring – Kyverno
If you are just not into writing and maintaining Rego for your PaC solution, and would rather work with YAML and other native Kubernetes constructs, then Kyverno may be your choice. When installed, Kyverno includes CRDs that enable authors to create policies that are either scoped to namespaces or cluster-wide.
The following example Kyverno ClusterPolicy resource, backed by a CRD, solves the allowed-registry use case that we have been discussing. This cluster-wide policy contains one rule: validate-registries. According to Kyverno documentation:
Each rule has a match clause, an optional exclude clause, and one of a mutate, validate, or generate clause.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: deployment-pod-valid-registry
annotations:
policies.kyverno.io/category: Security
spec:
background: false
validationFailureAction: enforce
rules:
- name: validate-registries
match:
resources:
kinds:
- Pod
preconditions:
- key: "{{ request.operation }}"
operator: In
value: ["CREATE", "UPDATE"]
validate:
message: "Unknown image registry"
pattern:
spec:
containers:
- image: "GOOD_REGISTRY/* | VERY_GOOD_REGISTRY/*"
The preceding policy validates that when a Pod resource is created or updated, the container images for the pod must include the GOOD_REGISTRY or VERY_GOOD_REGISTRY values.
This policy is written explicitly for a Pod resource and not a Deployment resource. However, this policy does apply to both Pods and Deployments. In fact, “the policy applies to all resources capable of generating Pods.” This is made possible by the Kyverno feature that auto-generates rules for pod controllers. This feature automatically annotates the policy with the pod-policies.kyverno.io/autogen-controllers: DaemonSet,Deployment,Job,StatefulSet,CronJob
annotation, and adds match clauses to the annotated policy for the other resources.
...
- match:
resources:
kinds:
- DaemonSet
- Deployment
- Job
- StatefulSet
name: autogen-validate-registries
validate:
message: Unknown image registry
pattern:
spec:
template:
spec:
containers:
- image: GOOD_REGISTRY/* | VERY_GOOD_REGISTRY/*
- match:
resources:
kinds:
- CronJob
name: autogen-cronjob-validate-registries
validate:
message: Unknown image registry
pattern:
spec:
jobTemplate:
spec:
template:
spec:
containers:
- image: GOOD_REGISTRY/* | VERY_GOOD_REGISTRY/*
...
Besides mutation and validation, Kyverno policies support rules that can generate resources, with the generate clause. This feature solves the use case when additional resources need to be generated based on the creation or update of another resource. For example, a common Kubernetes use case for multi-tenant clusters is to provision namespaces and then create deny-all-in/out network policies to lock-down the namespaces, before any new pods are created. With the generate clause, Kyverno policies can be created that solve for that use case. That use case and others are described in the following document: https://neonmirrors.net/post/2021-01/kyverno-the-swiss-army-knife-of-kubernetes/#resource-padlock
Another use case for the generate clause is a Velero self-service backup solution described in this article: https://nirmata.com/2021/01/24/self-service-velero-backups-with-kyverno/. According to the article:
In order to enable self-service backups with Velero, we will use the “generate” capabilities of Kyverno to automatically generate a schedule to backup the resources and data when a specific label, nirmata.io/auto-backup=enabled is added to a namespace.
For examples of Kyverno policies, please see the following repos:
- EKS Best Practices Guide: https://github.com/aws/aws-eks-best-practices/tree/master/policies/kyverno
- Kyverno Example Policies: https://kyverno.io/policies/
Policy authoring – k-rail
k-rail is described as “workload policy enforcement tool for Kubernetes.” In k-rail, policies are written in Golang, and integrated directly into the policy engine. Installing k-rail via helm installs the policy engine, as well as two ConfigMap resources that contain partially externalized policy configurations and exemptions. Sticking with our theme of allowed-registry policies, the following sample policy validates that images are sourced from allowed registries.
// Copyright 2019 Cruise LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pod
import (
"context"
"regexp"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
"github.com/cruise-automation/k-rail/policies"
"github.com/cruise-automation/k-rail/resource"
)
type PolicyTrustedRepository struct{}
func (p PolicyTrustedRepository) Name() string {
return "pod_trusted_repository"
}
func (p PolicyTrustedRepository) Validate(ctx context.Context, config policies.Config, ar *admissionv1.AdmissionRequest) ([]policies.ResourceViolation, []policies.PatchOperation) {
resourceViolations := []policies.ResourceViolation{}
podResource := resource.GetPodResource(ctx, ar)
if podResource == nil {
return resourceViolations, nil
}
validateContainer := func(container corev1.Container) {
matches := 0
for _, pattern := range config.PolicyTrustedRepositoryRegexes {
if matched, _ := regexp.MatchString(pattern, container.Image); matched {
matches++
}
}
if matches == 0 {
violationText := "Trusted Image Repository: image must be sourced from a trusted repository. Untrusted Images: " + container.Image
resourceViolations = append(resourceViolations, policies.ResourceViolation{
Namespace: ar.Namespace,
ResourceName: podResource.ResourceName,
ResourceKind: podResource.ResourceKind,
Violation: violationText,
Policy: p.Name(),
})
}
}
for _, container := range podResource.PodSpec.Containers {
validateContainer(container)
}
for _, container := range podResource.PodSpec.InitContainers {
validateContainer(container)
}
return resourceViolations, nil
}
While k-rail policies are written in Golang, the policies are configured and enabled via entries in the k-rail-config ConfigMap in the k-rail namespace. The following snippet is used to configure the RegEx settings for the registry matching and enable the policy for validation.
...
policy_config:
...
policy_trusted_repository_regexes:
- '^regsitry.k8s.io/.*' # official k8s GCR repo
- '^[A-Za-z0-9\-:@]+$' # official docker hub images
...
policies:
- name: "pod_trusted_repository"
enabled: True
report_only: False
...
Sample k-rail policies can be had from the k-rail GitHub repo: https://github.com/cruise-automation/k-rail/tree/master/policies
Webhook failure modes (fail open vs. fail closed)
Services that integrate into the Kubernetes API server as validating admission controllers can be configured to fail open or closed. In the fail open scenario, if the API server webhook call to the validation service times out (default 10 secs), changes from the respective API server request are permitted to proceed to etcd. Fail open is used so that clusters are not rendered inoperable when the connected validation services are unavailable. Like OPA and OPA/Gatekeeper, Kyverno is set up, at least currently, to fail open. By default, the MagTape (covered in Part 1) and k-rail solutions are set to fail closed, and run multiple pods to service the calls from the API server.
At the time of this writing, work on a Kyverno fail-closed functionality is in progress.
Failure modes for these solutions are set up in the respective validating webhook configuration resources using the failurePolicy element. The following setting is for a fail closed scenario.
failurePolicy: Fail
Background scanning
Due the prevalence of the fail-open scenario, and the strong desire to not “brick” a cluster (or fleet thereof), solutions have emerged, both open-source and commercial, that provide auditing and background scanning features. These solutions are designed to be compensating controls for the case when preventative validation is not possible and reactive detection is required.
Kyverno offers the background scanning feature (https://kyverno.io/docs/writing-policies/background/) that enables its polices to be used to detect violations in existing resources. According to the documentation:
Kyverno can validate existing resources in the cluster that may have been created before a policy was created. This can be useful when evaluating the potential effects new policies will have on a cluster prior to changing them to enforce mode. The application of policies to existing resources is referred to as background scanning.
On the commercial side, Nirmata, the creators of Kyverno, offer a commercial policy-as-code solution called Continuous Compliance. According to Nirmata, their Continuous Compliance solution provides:
Managed policy groups using a GitOps style workflow and deploy across your fleet of clusters.
In-cluster controls to validate, mutate, and generate resource configurations based on policies.
Automated fine-grained configuration changes to provide self-service and eliminate delays.
Customizable reporting and sharing with workload scorecards, remediation guidelines, and best practice recommendations, along with CI/CD integrations.
Extensibility – programming and data
The Kyverno and k-rail solutions discussed in this series of posts are open-source solutions, primarily written in Golang. Given those characteristics, these solutions can be extended, at a minimum, via their respective policy syntax, or by contributing to the OSS projects. Beyond that, Kyverno also provides the ability to use external data via Kubernetes ConfigMap resources in the following document: https://kyverno.io/docs/writing-policies/variables/.
The following Kyverno example uses config map data. The ns-roles-dictionary config map is used to build a dictionary data structure of allowed roles per environment keys.
kind: ConfigMap
apiVersion: v1
metadata:
name: ns-roles-dictionary
namespace: kyverno
labels:
app: kyverno
owner: jimmy
data:
prod: "arn:aws:iam::123456789012:role/prod"
dev: "arn:aws:iam::123456789012:role/dev"
kyverno-test: "[\"arn:aws:iam::123456789012:role/test\", \"arn:aws:iam::123456789012:role/dev\"]"
The data in the preceding config map is used in the following Kyverno policy to provide the allowed roles per environment that the policy needs to validate.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: deployment-valid-role
labels:
app: kyverno
owner: jimmy
annotations:
policies.kyverno.io/category: Security
policies.kyverno.io/description: Rules to enforce valid roles, based on namespace-role dictionary
spec:
validationFailureAction: enforce
rules:
- name: validate-role-annotation
context:
- name: ns-roles-dictionary
configMap:
name: ns-roles-dictionary
namespace: kyverno
match:
resources:
kinds:
- Deployment
preconditions:
- key: "{{ request.object.metadata.namespace }}"
operator: In
value: ["prod", "dev", "kyverno-test"]
- key: "{{ request.object.spec.template.metadata.annotations.\"iam.amazonaws.com/role\" }}"
operator: NotEquals
value: ""
validate:
message: "Annotation iam.amazonaws.com/role \"{{ request.object.spec.template.metadata.annotations.\"iam.amazonaws.com/role\" }}\" is not allowed for the \"{{ request.object.metadata.namespace }}\" namespace."
deny:
conditions:
- key: "{{ request.object.spec.template.metadata.annotations.\"iam.amazonaws.com/role\" }}"
operator: NotIn
value: "{{ \"ns-roles-dictionary\".data.\"{{ request.object.metadata.namespace }}\" }}"
Kubernetes policy architecture and direction
As discussed in Part 1 one of this series, the future of policy architecture for Kubernetes is being formed in the Kubernetes Policy Working Group. According to the description of the group, their purpose is to:
Provide an overall architecture that describes both the current policy related implementations as well as future policy related proposals in Kubernetes. Through a collaborative method, we want to present both dev and end user a universal view of policy architecture in Kubernetes.
Creators and sustainers of some of the solutions discussed in this series, as well as other interested parties, are engaged in this group. What comes from this group will drive the future directions for policy-as-code solutions. There are several initiatives being considered and underway that might interest users and decision makers, and help cluster admins and security professionals. Two of those initiatives are:
- Report integration to existing security tools like Falco and kube-bench
- Report integration to standards, like NIST Open Security Controls Assessment Language (OSCAL)
An interesting specification from the Policy WG that has made it into Kyverno as a feature is the ability to report on background policy violations. Policy Reports, seen in the following example, are backed by CRDs, and provide insight into policy activity from background scans.
apiVersion: wgpolicyk8s.io/v1alpha1
kind: PolicyReport
...
results:
- category: Security
message: validation rule 'dep-validate-privileged' passed.
policy: deployment-pod-security-context
resources:
- apiVersion: apps/v1
kind: Deployment
name: test
namespace: kyverno-test
uid: b38229d2-a9f1-41b8-ad0e-b0f1a677f0db
rule: dep-validate-privileged
scored: true
status: pass
- category: Security
message: validation rule 'dep-validate-allowPrivilegeEscalation' passed.
policy: deployment-pod-security-context
resources:
- apiVersion: apps/v1
kind: Deployment
name: test
namespace: kyverno-test
uid: b38229d2-a9f1-41b8-ad0e-b0f1a677f0db
rule: dep-validate-allowPrivilegeEscalation
scored: true
status: pass
- category: Security
message: validation rule 'dep-validate-readOnlyRootFilesystem' passed.
policy: deployment-pod-security-context
resources:
- apiVersion: apps/v1
kind: Deployment
name: test
namespace: kyverno-test
uid: b38229d2-a9f1-41b8-ad0e-b0f1a677f0db
rule: dep-validate-readOnlyRootFilesystem
scored: true
status: pass
- category: Security
message: 'validation error: Unknown image registry. Rule autogen-validate-registries
failed at path /spec/template/spec/containers/0/image/'
policy: deployment-pod-valid-registry
resources:
- apiVersion: apps/v1
kind: Deployment
name: test
namespace: kyverno-test
uid: b38229d2-a9f1-41b8-ad0e-b0f1a677f0db
rule: autogen-validate-registries
scored: true
status: fail
- message: validation rule 'deployment-labels' passed.
policy: deployment-require-labels
resources:
- apiVersion: apps/v1
kind: Deployment
name: test
namespace: kyverno-test
uid: b38229d2-a9f1-41b8-ad0e-b0f1a677f0db
rule: deployment-labels
scored: true
status: pass
- category: Security
message: validation rule 'pod-validate-readOnlyRootFilesystem' passed.
policy: deployment-pod-security-context
resources:
- apiVersion: v1
kind: Pod
name: test-68b9dcd84b-98qpt
namespace: kyverno-test
uid: d8b3a0f3-09b5-4ec1-a5a4-76f21b0d174a
rule: pod-validate-readOnlyRootFilesystem
scored: true
status: pass
- message: validation rule 'pod-labels' passed.
policy: deployment-require-labels
resources:
- apiVersion: v1
kind: Pod
name: test-68b9dcd84b-98qpt
namespace: kyverno-test
uid: d8b3a0f3-09b5-4ec1-a5a4-76f21b0d174a
rule: pod-labels
scored: true
status: pass
- category: Security
message: validation rule 'pod-validate-runAsNonRoot' anyPattern[3] passed.
policy: deployment-pod-security-context
resources:
- apiVersion: v1
kind: Pod
name: test-68b9dcd84b-98qpt
namespace: kyverno-test
uid: d8b3a0f3-09b5-4ec1-a5a4-76f21b0d174a
rule: pod-validate-runAsNonRoot
scored: true
status: pass
- category: Security
message: Annotation iam.amazonaws.com/role "arn:aws:iam::123456789012:role/test"
is not allow for the "kyverno-test" namespace.
policy: deployment-valid-role
resources:
- apiVersion: apps/v1
kind: Deployment
name: test
namespace: kyverno-test
uid: b38229d2-a9f1-41b8-ad0e-b0f1a677f0db
rule: validate-role-annotation
scored: true
status: pass
summary:
error: 0
fail: 1
pass: 8
skip: 0
warn: 0
The preceding report shows passes and fails for policies implemented in a test cluster.
Shifting policy enforcement to the left
In the context of DevOps, “shifting left” means that steps or stages that normally take place later in automated CICD pipelines, or even within the Systems Development Life Cycle (SDLC), are moved to earlier steps or stages in the process. The premise is based on the value proposition that it is faster, cheaper, and less complex to identify and remediate issues earlier in the process. Shifting issues identification and remediation to the left can also reduce impact on downstream systems and stakeholders.
Not withstanding the mature integration between Kubernetes and PaC solutions, shifting data mutation and validation decisions to the left is a foundational characteristic of DevOps. To that end, the ability to evaluate policies and structured data in automated DevOps pipelines, or even at the developer desktop, should be considered when evaluating PaC solutions.
Kyverno offers a solution for shifting evaluations to the left. The Kyverno Command-Line Interface (CLI) allows users to validate policies and structured data, outside of Kubernetes clusters. While there are multiple ways to install the CLI, I opted to use krew to install the Kyverno CLI as a kubectl plugin, with the following command:
kubectl krew install kyverno
Using the validate subcommand, the Kyverno CLI can be used to validate policies before they are used to evaluate data.
kubectl kyverno validate 3-dep-pod-valid-registry.yaml
----------------------------------------------------------------------
Policy deployment-pod-valid-registry is valid.
The apply subcommand is used to evaluate structured data using a Kyverno policy written for Kubernetes, with the Kyverno CLI.
kubectl kyverno apply 3-dep-pod-valid-registry.yaml -r ../test/11-dep-reg-allow.yaml
applying 1 policy to 1 resource...
policy deployment-pod-valid-registry -> resource kyverno-test/Deployment/test failed:
1. autogen-validate-registries: validation error: Unknown image registry. Rule autogen-validate-registries failed at path /spec/template/spec/containers/0/image/
pass: 0, fail: 1, warn: 0, error: 0, skip: 0
It’s important to point out that Kyverno auto-gen feature works with the Kyverno CLI on policy evaluations outside of the Kubernetes cluster, like it did earlier, inside the cluster, as an admission controller solution.
The Kyverno CLI also offers the ability to create Policy Reports, an emerging specification from the Kubernetes Policy Working Group. The following example is the same apply command with the —policy-report flag used to generate the policy report for the policy/data evaluation.
kubectl kyverno apply 3-dep-pod-valid-registry.yaml -r ../test/11-dep-reg-allow.yaml --policy-report
applying 1 policy to 1 resource...
----------------------------------------------------------------------
POLICY REPORT:
----------------------------------------------------------------------
apiVersion: wgpolicyk8s.io/v1alpha1
kind: ClusterPolicyReport
metadata:
name: clusterpolicyreport
results:
- message: 'validation error: Unknown image registry. Rule autogen-validate-registries failed at path /spec/template/spec/containers/0/image/'
policy: deployment-pod-valid-registry
resources:
- apiVersion: apps/v1
kind: Deployment
name: test
namespace: kyverno-test
rule: autogen-validate-registries
scored: true
status: fail
summary:
error: 0
fail: 1
pass: 0
skip: 0
warn: 0
Policy reports provide structured report data that can be consumed by downstream processes and systems, such as those used for security information and event management (SIEM).
Being able to reuse these Kubernetes PaC solutions in DevOps pipelines enables organizations to empower their developers to fail, react, and succeed fast, with minimal impact to operating environments. DevOps usage of these PaC solutions can validate both structured data and the policies used for evaluation. The capability to test and validate actual policies before they are used to evaluate data enables organizations to correctly apply traceability and provenance (which is important to audit requirements) to data validation methods used in their processes.
Policy decisions made early in the software lifecycle or container supply chain have the following affects:
- Save both time and resources
- Prevent unwanted behaviors and changes
- Reduce attack surfaces and blast radii
- Minimize impacts to systems and environments
Making the right choice for your use case and organization
Choosing the right policy engine requires that you consider multiple factors. Some of those factors include:
- Community adoption of solution
- Complexity of solution, or conversely, ease-of-use
- Alignment of solution to organizational capabilities
- Alignment of solution to compute strategies
- Use cases that solution will need to satisfy across your enterprise
- Support model (community vs enterprise)
- Solution extensibility
- Integration to existing tooling
Given the preceding factors, organizations should decide on the level of importance (weight) each factor carries within their respective organizations, as well as the level of fit each solution provides for those weighted factors. Organizations may also need to add organization-specific factors not listed. A simple and effective approach towards a data-driven decision is to use a spreadsheet or scorecard, fed by data from solution testing and evaluation.
The sample scorecard illustrates how organizations could choose the right solution for their needs. The weight and fit values are multiplied for each Solution-Factor combination, and those products are summed for an overall solution score. It’s important to understand that, for a data-driven outcome, the “fit” column should be based on criteria determined by the organization, and satisfaction of said criteria, by the solution under evaluation, demonstrated in testing and/or proofs-of-concept. During the evaluation of these solutions, the open-source communities for each project are valuable resources to gain insights about potential use cases, and to help organizations learn more about the individual solutions.
Summary
As more organizations move to containers as a means of delivering applications and solutions, these same organizations must keep up with the never-ending and ever-changing demand on security, compliance, privacy, and best practices. There is no such thing as “secure enough“ or ”good enough.” Application strategies that deliver fast-paced solutions and innovation can use policy-as-code solutions for more secure outcomes and enforcement of best practices.
Policy-as-code solutions provide automated guardrails that both enable users as well as prevent unwanted behaviors. While not a one-way door, choosing the right policy-as-code solution is not a trivial task. Organizations must consider several factors when making the right choice. Making data-driven decisions based on the outcome of testing and proofs-of-concept is a sound approach. Regardless of selected solution, policy-as-code is emerging as a foundational component to DevOps and defense-in-depth strategies.
The Kyverno policies shared in this post are available from the EKS Best Practices Guides GitHub companion repository: https://github.com/aws/aws-eks-best-practices/tree/master/policies