mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #105908 from stlaz/ps_annotations
[PodSecurity] Add annotations denoting the exemption reason and the enforcement policy used
This commit is contained in:
commit
ac2d872ed9
@ -286,7 +286,7 @@ func (a *Admission) ValidateNamespace(ctx context.Context, attrs api.Attributes)
|
||||
return sharedAllowedResponse()
|
||||
}
|
||||
if a.exemptNamespace(attrs.GetNamespace()) {
|
||||
return sharedAllowedResponse()
|
||||
return sharedAllowedByNamespaceExemptionResponse()
|
||||
}
|
||||
response := allowedResponse()
|
||||
response.Warnings = a.EvaluatePodsInNamespace(ctx, namespace.Name, newPolicy.Enforce)
|
||||
@ -319,8 +319,12 @@ func (a *Admission) ValidatePod(ctx context.Context, attrs api.Attributes) *admi
|
||||
return sharedAllowedResponse()
|
||||
}
|
||||
// short-circuit on exempt namespaces and users
|
||||
if a.exemptNamespace(attrs.GetNamespace()) || a.exemptUser(attrs.GetUserName()) {
|
||||
return sharedAllowedResponse()
|
||||
if a.exemptNamespace(attrs.GetNamespace()) {
|
||||
return sharedAllowedByNamespaceExemptionResponse()
|
||||
}
|
||||
|
||||
if a.exemptUser(attrs.GetUserName()) {
|
||||
return sharedAllowedByUserExemptionResponse()
|
||||
}
|
||||
|
||||
// short-circuit on privileged enforce+audit+warn namespaces
|
||||
@ -371,8 +375,12 @@ func (a *Admission) ValidatePodController(ctx context.Context, attrs api.Attribu
|
||||
return sharedAllowedResponse()
|
||||
}
|
||||
// short-circuit on exempt namespaces and users
|
||||
if a.exemptNamespace(attrs.GetNamespace()) || a.exemptUser(attrs.GetUserName()) {
|
||||
return sharedAllowedResponse()
|
||||
if a.exemptNamespace(attrs.GetNamespace()) {
|
||||
return sharedAllowedByNamespaceExemptionResponse()
|
||||
}
|
||||
|
||||
if a.exemptUser(attrs.GetUserName()) {
|
||||
return sharedAllowedByUserExemptionResponse()
|
||||
}
|
||||
|
||||
// short-circuit on privileged audit+warn namespaces
|
||||
@ -409,7 +417,7 @@ func (a *Admission) ValidatePodController(ctx context.Context, attrs api.Attribu
|
||||
func (a *Admission) EvaluatePod(ctx context.Context, nsPolicy api.Policy, nsPolicyErr error, podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSpec, attrs api.Attributes, enforce bool) *admissionv1.AdmissionResponse {
|
||||
// short-circuit on exempt runtimeclass
|
||||
if a.exemptRuntimeClass(podSpec.RuntimeClassName) {
|
||||
return sharedAllowedResponse()
|
||||
return sharedAllowedByRuntimeClassExemptionResponse()
|
||||
}
|
||||
|
||||
auditAnnotations := map[string]string{}
|
||||
@ -424,6 +432,8 @@ func (a *Admission) EvaluatePod(ctx context.Context, nsPolicy api.Policy, nsPoli
|
||||
|
||||
response := allowedResponse()
|
||||
if enforce {
|
||||
auditAnnotations[api.EnforcedPolicyAnnotationKey] = nsPolicy.Enforce.String()
|
||||
|
||||
if result := policy.AggregateCheckResults(a.Evaluator.EvaluatePod(nsPolicy.Enforce, podMetadata, podSpec)); !result.Allowed {
|
||||
response = forbiddenResponse(fmt.Sprintf(
|
||||
"pod violates PodSecurity %q: %s",
|
||||
@ -438,7 +448,7 @@ func (a *Admission) EvaluatePod(ctx context.Context, nsPolicy api.Policy, nsPoli
|
||||
|
||||
// TODO: reuse previous evaluation if audit level+version is the same as enforce level+version
|
||||
if result := policy.AggregateCheckResults(a.Evaluator.EvaluatePod(nsPolicy.Audit, podMetadata, podSpec)); !result.Allowed {
|
||||
auditAnnotations["audit"] = fmt.Sprintf(
|
||||
auditAnnotations[api.AuditViolationsAnnotationKey] = fmt.Sprintf(
|
||||
"would violate PodSecurity %q: %s",
|
||||
nsPolicy.Audit.String(),
|
||||
result.ForbiddenDetail(),
|
||||
@ -565,17 +575,41 @@ func (a *Admission) PolicyToEvaluate(labels map[string]string) (api.Policy, fiel
|
||||
return api.PolicyToEvaluate(labels, a.defaultPolicy)
|
||||
}
|
||||
|
||||
var _sharedAllowedResponse = allowedResponse()
|
||||
var (
|
||||
_sharedAllowedResponse = allowedResponse()
|
||||
_sharedAllowedByUserExemptionResponse = allowedByExemptResponse("user")
|
||||
_sharedAllowedByNamespaceExemptionResponse = allowedByExemptResponse("namespace")
|
||||
_sharedAllowedByRuntimeClassExemptionResponse = allowedByExemptResponse("runtimeClass")
|
||||
)
|
||||
|
||||
func sharedAllowedResponse() *admissionv1.AdmissionResponse {
|
||||
return _sharedAllowedResponse
|
||||
}
|
||||
|
||||
func sharedAllowedByUserExemptionResponse() *admissionv1.AdmissionResponse {
|
||||
return _sharedAllowedByUserExemptionResponse
|
||||
}
|
||||
|
||||
func sharedAllowedByNamespaceExemptionResponse() *admissionv1.AdmissionResponse {
|
||||
return _sharedAllowedByNamespaceExemptionResponse
|
||||
}
|
||||
|
||||
func sharedAllowedByRuntimeClassExemptionResponse() *admissionv1.AdmissionResponse {
|
||||
return _sharedAllowedByRuntimeClassExemptionResponse
|
||||
}
|
||||
|
||||
// allowedResponse is the response used when the admission decision is allow.
|
||||
func allowedResponse() *admissionv1.AdmissionResponse {
|
||||
return &admissionv1.AdmissionResponse{Allowed: true}
|
||||
}
|
||||
|
||||
func allowedByExemptResponse(exemptionReason string) *admissionv1.AdmissionResponse {
|
||||
return &admissionv1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
AuditAnnotations: map[string]string{api.ExemptionReasonAnnotationKey: exemptionReason},
|
||||
}
|
||||
}
|
||||
|
||||
func failureResponse(msg string, reason metav1.StatusReason, code int32) *admissionv1.AdmissionResponse {
|
||||
return &admissionv1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
|
@ -609,25 +609,28 @@ func TestValidatePodController(t *testing.T) {
|
||||
gvr: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
},
|
||||
{
|
||||
desc: "namespace in exemptNamespaces will be exempted",
|
||||
newObject: &badDeploy,
|
||||
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
gvr: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
exemptNamespaces: []string{testNamespace},
|
||||
desc: "namespace in exemptNamespaces will be exempted",
|
||||
newObject: &badDeploy,
|
||||
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
gvr: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
exemptNamespaces: []string{testNamespace},
|
||||
expectAuditAnnotations: map[string]string{"exempt": "namespace"},
|
||||
},
|
||||
{
|
||||
desc: "runtimeClass in exemptRuntimeClasses will be exempted",
|
||||
newObject: &badDeploy,
|
||||
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
gvr: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
exemptRuntimeClasses: []string{"containerd"},
|
||||
desc: "runtimeClass in exemptRuntimeClasses will be exempted",
|
||||
newObject: &badDeploy,
|
||||
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
gvr: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
exemptRuntimeClasses: []string{"containerd"},
|
||||
expectAuditAnnotations: map[string]string{"exempt": "runtimeClass"},
|
||||
},
|
||||
{
|
||||
desc: "user in exemptUsers will be exempted",
|
||||
newObject: &badDeploy,
|
||||
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
gvr: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
exemptUsers: []string{"testuser"},
|
||||
desc: "user in exemptUsers will be exempted",
|
||||
newObject: &badDeploy,
|
||||
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
gvr: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
exemptUsers: []string{"testuser"},
|
||||
expectAuditAnnotations: map[string]string{"exempt": "user"},
|
||||
},
|
||||
{
|
||||
desc: "podMetadata == nil && podSpec == nil will skip verification",
|
||||
@ -647,7 +650,7 @@ func TestValidatePodController(t *testing.T) {
|
||||
newObject: &badDeploy,
|
||||
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
gvr: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
expectAuditAnnotations: map[string]string{"audit": "would violate PodSecurity \"baseline:latest\": forbidden sysctls (unknown)"},
|
||||
expectAuditAnnotations: map[string]string{"audit-violations": "would violate PodSecurity \"baseline:latest\": forbidden sysctls (unknown)"},
|
||||
expectWarnings: []string{"would violate PodSecurity \"baseline:latest\": forbidden sysctls (unknown)"},
|
||||
},
|
||||
{
|
||||
@ -656,7 +659,7 @@ func TestValidatePodController(t *testing.T) {
|
||||
oldObject: &goodDeploy,
|
||||
gvk: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
gvr: schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"},
|
||||
expectAuditAnnotations: map[string]string{"audit": "would violate PodSecurity \"baseline:latest\": forbidden sysctls (unknown)"},
|
||||
expectAuditAnnotations: map[string]string{"audit-violations": "would violate PodSecurity \"baseline:latest\": forbidden sysctls (unknown)"},
|
||||
expectWarnings: []string{"would violate PodSecurity \"baseline:latest\": forbidden sysctls (unknown)"},
|
||||
},
|
||||
}
|
||||
|
@ -43,4 +43,8 @@ const (
|
||||
AuditVersionLabel = labelPrefix + "audit-version"
|
||||
WarnLevelLabel = labelPrefix + "warn"
|
||||
WarnVersionLabel = labelPrefix + "warn-version"
|
||||
|
||||
ExemptionReasonAnnotationKey = "exempt"
|
||||
AuditViolationsAnnotationKey = "audit-violations"
|
||||
EnforcedPolicyAnnotationKey = "enforce-policy"
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user