From fca58f8d0d07988edb5bc0eabd591b5c439af8d1 Mon Sep 17 00:00:00 2001 From: Jeremias Weber Date: Fri, 13 Dec 2024 14:18:45 +0100 Subject: [PATCH] #221 Add seccomp, apparmor and selinux profiles --- api/v2/dogu_types.go | 12 +- api/v2/dogu_types_security.go | 117 ++++++++++++++++-- api/v2/k8s.cloudogu.com_dogus.yaml | 69 ++++++++++- api/v2/zz_generated.deepcopy.go | 70 +++++++++++ .../templates/k8s.cloudogu.com_dogus.yaml | 69 ++++++++++- 5 files changed, 309 insertions(+), 28 deletions(-) diff --git a/api/v2/dogu_types.go b/api/v2/dogu_types.go index 21fbe6fa..bdb13b8c 100644 --- a/api/v2/dogu_types.go +++ b/api/v2/dogu_types.go @@ -51,17 +51,7 @@ type DoguSpec struct { // Resources of the dogu (e.g. dataVolumeSize) Resources DoguResources `json:"resources,omitempty"` // Security overrides security policies defined in the dogu descriptor. These fields can be used to further reduce a dogu's attack surface. - // - // Example: - // - // "Security": { - // "Capabilities": { - // "Drop": ["All"], - // "Add": ["NetBindService", "Kill"] - // }, - // "RunAsNonRoot": true, - // "ReadOnlyRootFileSystem": true - // } + // +optional Security Security `json:"security,omitempty"` // SupportMode indicates whether the dogu should be restarted in the support mode (f. e. to recover manually from // a crash loop). diff --git a/api/v2/dogu_types_security.go b/api/v2/dogu_types_security.go index 4a16514b..1d295751 100644 --- a/api/v2/dogu_types_security.go +++ b/api/v2/dogu_types_security.go @@ -26,33 +26,124 @@ type Capability string // } type Capabilities struct { // Add contains the capabilities that should be allowed to be used in a container. This list is optional. + // +optional + // +listType=atomic Add []Capability `json:"add,omitempty"` // Drop contains the capabilities that should be blocked from being used in a container. This list is optional. + // +optional + // +listType=atomic Drop []Capability `json:"drop,omitempty"` } -// Security overrides security policies defined in the dogu descriptor. These fields can be used to further reduce a dogu's attack surface. -// -// Example: -// -// "Security": { -// "Capabilities": { -// "Drop": ["All"], -// "Add": ["NetBindService", "Kill"] -// }, -// "RunAsNonRoot": true, -// "ReadOnlyRootFileSystem": true -// } +// SELinuxOptions are the labels to be applied to the container +type SELinuxOptions struct { + // User is a SELinux user label that applies to the container. + // +optional + User string `json:"user,omitempty" protobuf:"bytes,1,opt,name=user"` + // Role is a SELinux role label that applies to the container. + // +optional + Role string `json:"role,omitempty" protobuf:"bytes,2,opt,name=role"` + // Type is a SELinux type label that applies to the container. + // +optional + Type string `json:"type,omitempty" protobuf:"bytes,3,opt,name=type"` + // Level is SELinux level label that applies to the container. + // +optional + Level string `json:"level,omitempty" protobuf:"bytes,4,opt,name=level"` +} + +// SeccompProfile defines a pod/container's seccomp profile settings. +// Only one profile source may be set. +// +union +type SeccompProfile struct { + // type indicates which kind of seccomp profile will be applied. + // Valid options are: + // + // Localhost - a profile defined in a file on the node should be used. + // RuntimeDefault - the container runtime default profile should be used. + // Unconfined - no profile should be applied. + // +unionDiscriminator + Type SeccompProfileType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=SeccompProfileType"` + // localhostProfile indicates a profile defined in a file on the node should be used. + // The profile must be preconfigured on the node to work. + // Must be a descending path, relative to the kubelet's configured seccomp profile location. + // Must be set if type is "Localhost". Must NOT be set for any other type. + // +optional + LocalhostProfile *string `json:"localhostProfile,omitempty" protobuf:"bytes,2,opt,name=localhostProfile"` +} + +// SeccompProfileType defines the supported seccomp profile types. +// +enum +type SeccompProfileType string + +const ( + // SeccompProfileTypeUnconfined indicates no seccomp profile is applied (A.K.A. unconfined). + SeccompProfileTypeUnconfined SeccompProfileType = "Unconfined" + // SeccompProfileTypeRuntimeDefault represents the default container runtime seccomp profile. + SeccompProfileTypeRuntimeDefault SeccompProfileType = "RuntimeDefault" + // SeccompProfileTypeLocalhost indicates a profile defined in a file on the node should be used. + // The file's location relative to /seccomp. + SeccompProfileTypeLocalhost SeccompProfileType = "Localhost" +) + +// AppArmorProfile defines a pod or container's AppArmor settings. +// +union +type AppArmorProfile struct { + // type indicates which kind of AppArmor profile will be applied. + // Valid options are: + // Localhost - a profile pre-loaded on the node. + // RuntimeDefault - the container runtime's default profile. + // Unconfined - no AppArmor enforcement. + // +unionDiscriminator + Type AppArmorProfileType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=AppArmorProfileType"` + + // localhostProfile indicates a profile loaded on the node that should be used. + // The profile must be preconfigured on the node to work. + // Must match the loaded name of the profile. + // Must be set if and only if type is "Localhost". + // +optional + LocalhostProfile *string `json:"localhostProfile,omitempty" protobuf:"bytes,2,opt,name=localhostProfile"` +} + +// AppArmorProfileType references which type of AppArmor profile should be used. +// +enum +type AppArmorProfileType string + +const ( + // AppArmorProfileTypeUnconfined indicates that no AppArmor profile should be enforced. + AppArmorProfileTypeUnconfined AppArmorProfileType = "Unconfined" + // AppArmorProfileTypeRuntimeDefault indicates that the container runtime's default AppArmor + // profile should be used. + AppArmorProfileTypeRuntimeDefault AppArmorProfileType = "RuntimeDefault" + // AppArmorProfileTypeLocalhost indicates that a profile pre-loaded on the node should be used. + AppArmorProfileTypeLocalhost AppArmorProfileType = "Localhost" +) + +// Security overrides security policies defined in the dogu descriptor. +// These fields can be used to further reduce a dogu's attack surface. type Security struct { // Capabilities sets the allowed and dropped capabilities for the dogu. The dogu should not use more than the - // configured capabilities here, otherwise failure may occur at start-up or at run-time. This list is optional. + // configured capabilities here, otherwise failure may occur at start-up or at run-time. + // +optional Capabilities Capabilities `json:"capabilities,omitempty"` // RunAsNonRoot indicates that the container must run as a non-root user. The dogu must support running as non-root // user otherwise the dogu start may fail. This flag is optional and defaults to nil. // If nil, the value defined in the dogu descriptor is used. + // +optional RunAsNonRoot *bool `json:"runAsNonRoot,omitempty"` // ReadOnlyRootFileSystem mounts the container's root filesystem as read-only. The dogu must support accessing the // root file system by only reading otherwise the dogu start may fail. This flag is optional and defaults to nil. // If nil, the value defined in the dogu descriptor is used. + // +optional ReadOnlyRootFileSystem *bool `json:"readOnlyRootFileSystem,omitempty"` + // The SELinux context to be applied to the container. + // If unspecified, the container runtime will allocate a random SELinux context for each + // container, which is kubernetes default behaviour. + // +optional + SELinuxOptions *SELinuxOptions `json:"seLinuxOptions,omitempty"` + // The seccomp options to use by this container. + // +optional + SeccompProfile *SeccompProfile `json:"seccompProfile,omitempty"` + // appArmorProfile is the AppArmor options to use by this container. + // +optional + AppArmorProfile *AppArmorProfile `json:"appArmorProfile,omitempty"` } diff --git a/api/v2/k8s.cloudogu.com_dogus.yaml b/api/v2/k8s.cloudogu.com_dogus.yaml index 7c745fff..419dc306 100644 --- a/api/v2/k8s.cloudogu.com_dogus.yaml +++ b/api/v2/k8s.cloudogu.com_dogus.yaml @@ -62,12 +62,33 @@ spec: type: string type: object security: - description: "Security overrides security policies defined in the dogu descriptor. These fields can be used to further reduce a dogu's attack surface.\n\n\nExample:\n\n\n\t\"Security\": {\n\t \"Capabilities\": {\n\t \"Drop\": [\"All\"],\n\t \"Add\": [\"NetBindService\", \"Kill\"]\n\t },\n\t \"RunAsNonRoot\": true,\n\t \"ReadOnlyRootFileSystem\": true\n\t}" + description: Security overrides security policies defined in the dogu descriptor. These fields can be used to further reduce a dogu's attack surface. properties: + appArmorProfile: + description: appArmorProfile is the AppArmor options to use by this container. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object capabilities: description: |- Capabilities sets the allowed and dropped capabilities for the dogu. The dogu should not use more than the - configured capabilities here, otherwise failure may occur at start-up or at run-time. This list is optional. + configured capabilities here, otherwise failure may occur at start-up or at run-time. properties: add: description: Add contains the capabilities that should be allowed to be used in a container. This list is optional. @@ -79,6 +100,7 @@ spec: See docs at https://manned.org/capabilities.7 type: string type: array + x-kubernetes-list-type: atomic drop: description: Drop contains the capabilities that should be blocked from being used in a container. This list is optional. items: @@ -89,6 +111,7 @@ spec: See docs at https://manned.org/capabilities.7 type: string type: array + x-kubernetes-list-type: atomic type: object readOnlyRootFileSystem: description: |- @@ -102,6 +125,48 @@ spec: user otherwise the dogu start may fail. This flag is optional and defaults to nil. If nil, the value defined in the dogu descriptor is used. type: boolean + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container, which is kubernetes default behaviour. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object type: object stopped: description: Stopped indicates whether the dogu should be running (stopped=false) or not (stopped=true). diff --git a/api/v2/zz_generated.deepcopy.go b/api/v2/zz_generated.deepcopy.go index e8084b84..a531280e 100644 --- a/api/v2/zz_generated.deepcopy.go +++ b/api/v2/zz_generated.deepcopy.go @@ -12,6 +12,26 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AppArmorProfile) DeepCopyInto(out *AppArmorProfile) { + *out = *in + if in.LocalhostProfile != nil { + in, out := &in.LocalhostProfile, &out.LocalhostProfile + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppArmorProfile. +func (in *AppArmorProfile) DeepCopy() *AppArmorProfile { + if in == nil { + return nil + } + out := new(AppArmorProfile) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Capabilities) DeepCopyInto(out *Capabilities) { *out = *in @@ -327,6 +347,41 @@ func (in IngressAnnotations) DeepCopy() IngressAnnotations { return *out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SELinuxOptions) DeepCopyInto(out *SELinuxOptions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SELinuxOptions. +func (in *SELinuxOptions) DeepCopy() *SELinuxOptions { + if in == nil { + return nil + } + out := new(SELinuxOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SeccompProfile) DeepCopyInto(out *SeccompProfile) { + *out = *in + if in.LocalhostProfile != nil { + in, out := &in.LocalhostProfile, &out.LocalhostProfile + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeccompProfile. +func (in *SeccompProfile) DeepCopy() *SeccompProfile { + if in == nil { + return nil + } + out := new(SeccompProfile) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Security) DeepCopyInto(out *Security) { *out = *in @@ -341,6 +396,21 @@ func (in *Security) DeepCopyInto(out *Security) { *out = new(bool) **out = **in } + if in.SELinuxOptions != nil { + in, out := &in.SELinuxOptions, &out.SELinuxOptions + *out = new(SELinuxOptions) + **out = **in + } + if in.SeccompProfile != nil { + in, out := &in.SeccompProfile, &out.SeccompProfile + *out = new(SeccompProfile) + (*in).DeepCopyInto(*out) + } + if in.AppArmorProfile != nil { + in, out := &in.AppArmorProfile, &out.AppArmorProfile + *out = new(AppArmorProfile) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Security. diff --git a/k8s/helm-crd/templates/k8s.cloudogu.com_dogus.yaml b/k8s/helm-crd/templates/k8s.cloudogu.com_dogus.yaml index 7c745fff..419dc306 100644 --- a/k8s/helm-crd/templates/k8s.cloudogu.com_dogus.yaml +++ b/k8s/helm-crd/templates/k8s.cloudogu.com_dogus.yaml @@ -62,12 +62,33 @@ spec: type: string type: object security: - description: "Security overrides security policies defined in the dogu descriptor. These fields can be used to further reduce a dogu's attack surface.\n\n\nExample:\n\n\n\t\"Security\": {\n\t \"Capabilities\": {\n\t \"Drop\": [\"All\"],\n\t \"Add\": [\"NetBindService\", \"Kill\"]\n\t },\n\t \"RunAsNonRoot\": true,\n\t \"ReadOnlyRootFileSystem\": true\n\t}" + description: Security overrides security policies defined in the dogu descriptor. These fields can be used to further reduce a dogu's attack surface. properties: + appArmorProfile: + description: appArmorProfile is the AppArmor options to use by this container. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object capabilities: description: |- Capabilities sets the allowed and dropped capabilities for the dogu. The dogu should not use more than the - configured capabilities here, otherwise failure may occur at start-up or at run-time. This list is optional. + configured capabilities here, otherwise failure may occur at start-up or at run-time. properties: add: description: Add contains the capabilities that should be allowed to be used in a container. This list is optional. @@ -79,6 +100,7 @@ spec: See docs at https://manned.org/capabilities.7 type: string type: array + x-kubernetes-list-type: atomic drop: description: Drop contains the capabilities that should be blocked from being used in a container. This list is optional. items: @@ -89,6 +111,7 @@ spec: See docs at https://manned.org/capabilities.7 type: string type: array + x-kubernetes-list-type: atomic type: object readOnlyRootFileSystem: description: |- @@ -102,6 +125,48 @@ spec: user otherwise the dogu start may fail. This flag is optional and defaults to nil. If nil, the value defined in the dogu descriptor is used. type: boolean + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container, which is kubernetes default behaviour. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object type: object stopped: description: Stopped indicates whether the dogu should be running (stopped=false) or not (stopped=true).