mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-10 01:46:55 +00:00
145 lines
5.1 KiB
Go
145 lines
5.1 KiB
Go
|
package pss
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
|
||
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||
|
"github.com/kyverno/kyverno/pkg/utils"
|
||
|
corev1 "k8s.io/api/core/v1"
|
||
|
"k8s.io/pod-security-admission/policy"
|
||
|
)
|
||
|
|
||
|
func containsContainer(containers interface{}, containerName string) bool {
|
||
|
switch v := containers.(type) {
|
||
|
case []interface{}:
|
||
|
for _, container := range v {
|
||
|
switch v := container.(type) {
|
||
|
case corev1.Container:
|
||
|
if v.Name == containerName {
|
||
|
return true
|
||
|
}
|
||
|
case corev1.EphemeralContainer:
|
||
|
if v.Name == containerName {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
case []corev1.Container:
|
||
|
for _, container := range v {
|
||
|
if container.Name == containerName {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
case []corev1.EphemeralContainer:
|
||
|
for _, container := range v {
|
||
|
if container.Name == containerName {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// Get copy of pod with containers (containers, initContainers, ephemeralContainers) matching the exclude.image
|
||
|
func getPodWithMatchingContainers(exclude []kyvernov1.PodSecurityStandard, pod *corev1.Pod) (podCopy corev1.Pod) {
|
||
|
podCopy = *pod
|
||
|
podCopy.Spec.Containers = []corev1.Container{}
|
||
|
podCopy.Spec.InitContainers = []corev1.Container{}
|
||
|
podCopy.Spec.EphemeralContainers = []corev1.EphemeralContainer{}
|
||
|
|
||
|
for _, container := range pod.Spec.Containers {
|
||
|
for _, excludeRule := range exclude {
|
||
|
// Ignore all restrictedFields when we only specify the `controlName` with no `restrictedField`
|
||
|
controlNameOnly := excludeRule.RestrictedField == ""
|
||
|
if !utils.ContainsString(excludeRule.Images, container.Image) {
|
||
|
continue
|
||
|
}
|
||
|
if strings.Contains(excludeRule.RestrictedField, "spec.containers[*]") || controlNameOnly {
|
||
|
// Add to matchingContainers if either it's empty or is unique
|
||
|
if len(podCopy.Spec.Containers) == 0 || !containsContainer(podCopy.Spec.Containers, container.Name) {
|
||
|
podCopy.Spec.Containers = append(podCopy.Spec.Containers, container)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for _, container := range pod.Spec.InitContainers {
|
||
|
for _, excludeRule := range exclude {
|
||
|
// Ignore all restrictedFields when we only specify the `controlName` with no `restrictedField`
|
||
|
controlNameOnly := excludeRule.RestrictedField == ""
|
||
|
if !utils.ContainsString(excludeRule.Images, container.Image) {
|
||
|
continue
|
||
|
}
|
||
|
if strings.Contains(excludeRule.RestrictedField, "spec.initContainers[*]") || controlNameOnly {
|
||
|
// Add to matchingContainers if either it's empty or is unique
|
||
|
if len(podCopy.Spec.InitContainers) == 0 || !containsContainer(podCopy.Spec.InitContainers, container.Name) {
|
||
|
podCopy.Spec.InitContainers = append(podCopy.Spec.InitContainers, container)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for _, container := range pod.Spec.EphemeralContainers {
|
||
|
for _, excludeRule := range exclude {
|
||
|
// Ignore all restrictedFields when we only specify the `controlName` with no `restrictedField`
|
||
|
controlNameOnly := excludeRule.RestrictedField == ""
|
||
|
if !utils.ContainsString(excludeRule.Images, container.Image) {
|
||
|
continue
|
||
|
}
|
||
|
if strings.Contains(excludeRule.RestrictedField, "spec.ephemeralContainers[*]") || controlNameOnly {
|
||
|
// Add to matchingContainers if either it's empty or is unique
|
||
|
if len(podCopy.Spec.EphemeralContainers) == 0 || !containsContainer(podCopy.Spec.EphemeralContainers, container.Name) {
|
||
|
podCopy.Spec.EphemeralContainers = append(podCopy.Spec.EphemeralContainers, container)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return podCopy
|
||
|
}
|
||
|
|
||
|
// Get containers NOT matching images specified in Exclude values
|
||
|
func getPodWithNotMatchingContainers(exclude []kyvernov1.PodSecurityStandard, pod *corev1.Pod, podWithMatchingContainers *corev1.Pod) (podCopy corev1.Pod) {
|
||
|
// Only copy containers because we have already evaluated the pod-level controls
|
||
|
// e.g.: spec.securityContext.hostProcess
|
||
|
podCopy.Spec.Containers = []corev1.Container{}
|
||
|
podCopy.Spec.InitContainers = []corev1.Container{}
|
||
|
podCopy.Spec.EphemeralContainers = []corev1.EphemeralContainer{}
|
||
|
|
||
|
// Append containers that are not in podWithMatchingContainers already evaluated in EvaluatePod()
|
||
|
for _, container := range pod.Spec.Containers {
|
||
|
if !containsContainer(podWithMatchingContainers.Spec.Containers, container.Name) {
|
||
|
podCopy.Spec.Containers = append(podCopy.Spec.Containers, container)
|
||
|
}
|
||
|
}
|
||
|
for _, container := range pod.Spec.InitContainers {
|
||
|
if !containsContainer(podWithMatchingContainers.Spec.InitContainers, container.Name) {
|
||
|
podCopy.Spec.InitContainers = append(podCopy.Spec.InitContainers, container)
|
||
|
}
|
||
|
}
|
||
|
for _, container := range pod.Spec.EphemeralContainers {
|
||
|
if !containsContainer(podWithMatchingContainers.Spec.EphemeralContainers, container.Name) {
|
||
|
podCopy.Spec.EphemeralContainers = append(podCopy.Spec.EphemeralContainers, container)
|
||
|
}
|
||
|
}
|
||
|
return podCopy
|
||
|
}
|
||
|
|
||
|
// Get restrictedFields from Check.ID
|
||
|
func getRestrictedFields(check policy.Check) []restrictedField {
|
||
|
for _, control := range PSS_controls_to_check_id {
|
||
|
for _, checkID := range control {
|
||
|
if check.ID == checkID {
|
||
|
return PSS_controls[checkID]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func containsContainerLevelControl(restrictedFields []restrictedField) bool {
|
||
|
for _, restrictedField := range restrictedFields {
|
||
|
if strings.Contains(restrictedField.path, "ontainers[*]") {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|