Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: adding cel for psp-seccomp policy #540

Open
wants to merge 25 commits into
base: master
Choose a base branch
from

Conversation

JaydipGabani
Copy link
Contributor

@JaydipGabani JaydipGabani commented Jun 3, 2024

What this PR does / why we need it:

Which issue(s) does this PR fix (optional, using fixes #<issue number>(, fixes #<issue_number>, ...) format, will close the issue(s) when the PR gets merged):
Fixes #541

Special notes for your reviewer:

@JaydipGabani JaydipGabani requested a review from a team as a code owner June 3, 2024 21:34
Signed-off-by: Jaydip Gabani <[email protected]>
Signed-off-by: Jaydip Gabani <[email protected]>
src/pod-security-policy/seccomp/src.cel Outdated Show resolved Hide resolved
src/pod-security-policy/seccomp/src.cel Outdated Show resolved Hide resolved
src/pod-security-policy/seccomp/src.cel Outdated Show resolved Hide resolved
})
- name: allBadContainerProfiles
expression: |
variables.podAnnotationsProfiles + variables.containerAnnotationsProfiles + variables.podSecurityContextProfiles + variables.containerSecurityContextProfiles + variables.containerProfilesMissing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kubernetes no longer reads security contexts from the annotation, we should give constraint authors the ability to turn off relying on the annotation in order to avoid a security hole where pod runners "pretend" to have the correct security context.

I.e. we should add a parameter to turn off reading from the annotation.

Here is the k8s code for retrieving the seccomp profile:

https://github.com/kubernetes/kubernetes/blob/c6b5191c37f939d2d61e76de222a96ae5f5d9558/pkg/kubelet/kuberuntime/helpers.go#L270-L291

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added v2 for seccomp with a variable to enable/disable reading from annotations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are creating "v2", we should just remove annotations from v2 altogether, since K8s no longer supports seccomp annotations

Signed-off-by: Jaydip Gabani <[email protected]>
Signed-off-by: Jaydip Gabani <[email protected]>
src/pod-security-policy/seccomp/src.rego Show resolved Hide resolved
src/pod-security-policy/seccomp/src.rego Show resolved Hide resolved
@@ -99,7 +70,7 @@ get_allowed_profiles[allowed] {
# The simply translated profiles
get_allowed_profiles[allowed] {
profile := input.parameters.allowedProfiles[_]
not startswith(lower(profile), "localhost")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of keeping naming_translation we can:

  • if there is a "/" in the name, use the name directly (assume its already in annotation format)
  • If there is no "/" in the name, build a profile object (via a function call), then call canonicalize_seccomp_profile

This ensures we use the same translation logic everywhere.

expression: |
(variables.inputAllowedProfiles.filter(profile,
profile != "Localhost").map(profile, profile == "Unconfined" ? "unconfined" : profile)) +
(variables.inputAllowedProfiles.exists(profile, profile == "RuntimeDefault") ? ["runtime/default", "docker/default"] : [])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to do the mapping for the v2 policy, that may simplify the code a bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean we should assume we have only SC style profile names in the input.params.allowedProfile since we are not using annotations in v2?
if that is the case, then we would not need to canonicalize obj.securityContext.seccompProfile.type as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep!

# Seccomp V2

## Description
Controls the seccomp profile used by containers. Corresponds to the `seccomp.security.alpha.kubernetes.io/allowedProfileNames` annotation on a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccompv2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's different between non-v2 and v2?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like difference is the annotation. can we document it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated description.

name: k8spspseccompv2
displayName: Seccomp V2
createdAt: "2024-06-13T18:28:19Z"
description: Controls the seccomp profile used by containers. Corresponds to the `seccomp.security.alpha.kubernetes.io/allowedProfileNames` annotation on a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccompv2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should update the description too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated description.

Copy link
Member

@sozercan sozercan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doc change request, otherwise LGTM

Copy link
Member

@sozercan sozercan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM

@JaydipGabani
Copy link
Contributor Author

@maxsmythe @ritazh PTAL

Copy link
Contributor

@maxsmythe maxsmythe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple comments on v2, have not reviewed v1. Looking close!

description: >-
An array of allowed profile values for seccomp on Pods/Containers.

Can use the annotation naming scheme: `runtime/default`, `docker/default`, `unconfined` and/or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should get rid of mention/use of the annotation naming scheme for V2, since that is no longer a recognized paradigm for K8s

profile := input.parameters.allowedProfiles[_]
profile == "Localhost"
file := object.get(input.parameters, "allowedLocalhostFiles", [])[_]
allowed := sprintf("Localhost/%s", [file])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than attempting string packing/unpacking, we can just mimic the structure of local host profiles, this will simplify comparison later on.

basically, allowed := {"type": allowed, "localHostProfile": file}

Similar for above.

Then get_profile() is also simplified, as is the comparison with localhost. We also are no longer dependent on our scratch string format being invalidated.

- name: inputAllowedProfiles
expression: |
!has(variables.params.allowedProfiles) ? [] : variables.params.allowedProfiles
- name: derivedAllowedLocalhostFiles
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like the Rego code, we should avoid using string transformations here, just structs.

In this case, we can keep the params.allowedLocalhostFiles strings unmodified.

- name: podLocalHostProfile
expression: |
variables.hasPodSeccomp && has(variables.anyObject.spec.securityContext.seccompProfile.localhostProfile) ? variables.anyObject.spec.securityContext.seccompProfile.localhostProfile : ""
- name: podSecurityContextProfile
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: podSecurityContextProfileType, that is what is actually being stored, and otherwise you are relying on users to read a plural (extra "s") to distinguish between two very different bits of data.

variables.allContainerProfiles.filter(badContainerProfile,
badContainerProfile.profile == "Localhost" &&
!variables.allowAllLocalhostFiles &&
!((badContainerProfile.profile + "/" + badContainerProfile.file) in variables.allowedProfiles)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above, prefer field comparison to string manipulation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add CEL code for PSP Policies in library
3 participants