From 2fa4efab750408fc5aa493d1ecf48003af064257 Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Wed, 4 Dec 2024 09:16:49 +0000 Subject: [PATCH 1/7] Add a ComplainMode flag into the apparmor profile This falg will place the apparmor profile into compalin mode, otherwise it defaults to enforce mode. In complain mode, if a given action is not allowed, it will be allowed, but this violation will be logged with a tag of access being "ALLOWED unconfined". Change-Id: I597883a528edf60f05f1cb7914429b3c5b05b2cd Signed-off-by: Cosmin Cojocar --- api/apparmorprofile/v1alpha1/apparmorprofile_types.go | 6 ++++++ .../security-profiles-operator.clusterserviceversion.yaml | 2 +- ...urity-profiles-operator.x-k8s.io_apparmorprofiles.yaml | 8 ++++++++ deploy/base-crds/crds/apparmorprofile.yaml | 8 ++++++++ deploy/helm/crds/crds.yaml | 8 ++++++++ deploy/namespace-operator.yaml | 8 ++++++++ deploy/openshift-dev.yaml | 8 ++++++++ deploy/openshift-downstream.yaml | 8 ++++++++ deploy/operator.yaml | 8 ++++++++ deploy/webhook-operator.yaml | 8 ++++++++ 10 files changed, 71 insertions(+), 1 deletion(-) diff --git a/api/apparmorprofile/v1alpha1/apparmorprofile_types.go b/api/apparmorprofile/v1alpha1/apparmorprofile_types.go index 577e30cc90..1987efffe5 100644 --- a/api/apparmorprofile/v1alpha1/apparmorprofile_types.go +++ b/api/apparmorprofile/v1alpha1/apparmorprofile_types.go @@ -68,7 +68,13 @@ type AppArmorProfileSpec struct { // Common spec fields for all profiles. profilebasev1alpha1.SpecBase `json:",inline"` + // Abstract stores the apparmor profile allow lists for executable, file, network and capabilities access. Abstract AppArmorAbstract `json:"abstract,omitempty"` + + // ComplainMode places the apparmor profile into "complain" mode, by default is placed in "enforce" mode. + // In complain mode, if a given action is not allowed, it will be allowed, but this violation will be + // logged with a tag of access being "ALLOWED unconfined". + ComplainMode bool `json:"complainMode,omitempty"` } // AppArmorProfileStatus defines the observed state of AppArmorProfile. diff --git a/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml b/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml index 88fd2ab7db..6e22440719 100644 --- a/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml +++ b/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml @@ -248,7 +248,7 @@ metadata: capabilities: Basic Install categories: Security containerImage: registry.k8s.io/security-profiles-operator/security-profiles-operator:v0.8.4 - createdAt: "2024-12-03T12:04:53Z" + createdAt: "2024-12-04T09:14:26Z" olm.skipRange: '>=0.4.1 <0.8.5-dev' operatorframework.io/cluster-monitoring: "true" operatorframework.io/suggested-namespace: security-profiles-operator diff --git a/bundle/manifests/security-profiles-operator.x-k8s.io_apparmorprofiles.yaml b/bundle/manifests/security-profiles-operator.x-k8s.io_apparmorprofiles.yaml index ee9b484291..46c3b5daf8 100644 --- a/bundle/manifests/security-profiles-operator.x-k8s.io_apparmorprofiles.yaml +++ b/bundle/manifests/security-profiles-operator.x-k8s.io_apparmorprofiles.yaml @@ -49,6 +49,8 @@ spec: description: AppArmorProfileSpec defines the desired state of AppArmorProfile. properties: abstract: + description: Abstract stores the apparmor profile allow lists for + executable, file, network and capabilities access. properties: capability: properties: @@ -96,6 +98,12 @@ spec: type: object type: object type: object + complainMode: + description: |- + ComplainMode places the apparmor profile into "complain" mode, by default is placed in "enforce" mode. + In complain mode, if a given action is not allowed, it will be allowed, but this violation will be + logged with a tag of access being "ALLOWED unconfined". + type: boolean disabled: default: false description: Whether the profile is disabled and should be skipped diff --git a/deploy/base-crds/crds/apparmorprofile.yaml b/deploy/base-crds/crds/apparmorprofile.yaml index e8103ea915..91099cafa2 100644 --- a/deploy/base-crds/crds/apparmorprofile.yaml +++ b/deploy/base-crds/crds/apparmorprofile.yaml @@ -46,6 +46,8 @@ spec: description: AppArmorProfileSpec defines the desired state of AppArmorProfile. properties: abstract: + description: Abstract stores the apparmor profile allow lists for + executable, file, network and capabilities access. properties: capability: properties: @@ -93,6 +95,12 @@ spec: type: object type: object type: object + complainMode: + description: |- + ComplainMode places the apparmor profile into "complain" mode, by default is placed in "enforce" mode. + In complain mode, if a given action is not allowed, it will be allowed, but this violation will be + logged with a tag of access being "ALLOWED unconfined". + type: boolean disabled: default: false description: Whether the profile is disabled and should be skipped diff --git a/deploy/helm/crds/crds.yaml b/deploy/helm/crds/crds.yaml index 652a387333..f4264f2f1a 100644 --- a/deploy/helm/crds/crds.yaml +++ b/deploy/helm/crds/crds.yaml @@ -2236,6 +2236,8 @@ spec: description: AppArmorProfileSpec defines the desired state of AppArmorProfile. properties: abstract: + description: Abstract stores the apparmor profile allow lists for + executable, file, network and capabilities access. properties: capability: properties: @@ -2283,6 +2285,12 @@ spec: type: object type: object type: object + complainMode: + description: |- + ComplainMode places the apparmor profile into "complain" mode, by default is placed in "enforce" mode. + In complain mode, if a given action is not allowed, it will be allowed, but this violation will be + logged with a tag of access being "ALLOWED unconfined". + type: boolean disabled: default: false description: Whether the profile is disabled and should be skipped diff --git a/deploy/namespace-operator.yaml b/deploy/namespace-operator.yaml index 216471abe1..e39fe17d90 100644 --- a/deploy/namespace-operator.yaml +++ b/deploy/namespace-operator.yaml @@ -2236,6 +2236,8 @@ spec: description: AppArmorProfileSpec defines the desired state of AppArmorProfile. properties: abstract: + description: Abstract stores the apparmor profile allow lists for + executable, file, network and capabilities access. properties: capability: properties: @@ -2283,6 +2285,12 @@ spec: type: object type: object type: object + complainMode: + description: |- + ComplainMode places the apparmor profile into "complain" mode, by default is placed in "enforce" mode. + In complain mode, if a given action is not allowed, it will be allowed, but this violation will be + logged with a tag of access being "ALLOWED unconfined". + type: boolean disabled: default: false description: Whether the profile is disabled and should be skipped diff --git a/deploy/openshift-dev.yaml b/deploy/openshift-dev.yaml index fdb29ca6a0..e1776a226b 100644 --- a/deploy/openshift-dev.yaml +++ b/deploy/openshift-dev.yaml @@ -59,6 +59,8 @@ spec: description: AppArmorProfileSpec defines the desired state of AppArmorProfile. properties: abstract: + description: Abstract stores the apparmor profile allow lists for + executable, file, network and capabilities access. properties: capability: properties: @@ -106,6 +108,12 @@ spec: type: object type: object type: object + complainMode: + description: |- + ComplainMode places the apparmor profile into "complain" mode, by default is placed in "enforce" mode. + In complain mode, if a given action is not allowed, it will be allowed, but this violation will be + logged with a tag of access being "ALLOWED unconfined". + type: boolean disabled: default: false description: Whether the profile is disabled and should be skipped diff --git a/deploy/openshift-downstream.yaml b/deploy/openshift-downstream.yaml index 91f7f456a8..aaef6deba1 100644 --- a/deploy/openshift-downstream.yaml +++ b/deploy/openshift-downstream.yaml @@ -2236,6 +2236,8 @@ spec: description: AppArmorProfileSpec defines the desired state of AppArmorProfile. properties: abstract: + description: Abstract stores the apparmor profile allow lists for + executable, file, network and capabilities access. properties: capability: properties: @@ -2283,6 +2285,12 @@ spec: type: object type: object type: object + complainMode: + description: |- + ComplainMode places the apparmor profile into "complain" mode, by default is placed in "enforce" mode. + In complain mode, if a given action is not allowed, it will be allowed, but this violation will be + logged with a tag of access being "ALLOWED unconfined". + type: boolean disabled: default: false description: Whether the profile is disabled and should be skipped diff --git a/deploy/operator.yaml b/deploy/operator.yaml index acdd13ca96..ee67c50264 100644 --- a/deploy/operator.yaml +++ b/deploy/operator.yaml @@ -2236,6 +2236,8 @@ spec: description: AppArmorProfileSpec defines the desired state of AppArmorProfile. properties: abstract: + description: Abstract stores the apparmor profile allow lists for + executable, file, network and capabilities access. properties: capability: properties: @@ -2283,6 +2285,12 @@ spec: type: object type: object type: object + complainMode: + description: |- + ComplainMode places the apparmor profile into "complain" mode, by default is placed in "enforce" mode. + In complain mode, if a given action is not allowed, it will be allowed, but this violation will be + logged with a tag of access being "ALLOWED unconfined". + type: boolean disabled: default: false description: Whether the profile is disabled and should be skipped diff --git a/deploy/webhook-operator.yaml b/deploy/webhook-operator.yaml index 6587b25efc..6f8df04eea 100644 --- a/deploy/webhook-operator.yaml +++ b/deploy/webhook-operator.yaml @@ -59,6 +59,8 @@ spec: description: AppArmorProfileSpec defines the desired state of AppArmorProfile. properties: abstract: + description: Abstract stores the apparmor profile allow lists for + executable, file, network and capabilities access. properties: capability: properties: @@ -106,6 +108,12 @@ spec: type: object type: object type: object + complainMode: + description: |- + ComplainMode places the apparmor profile into "complain" mode, by default is placed in "enforce" mode. + In complain mode, if a given action is not allowed, it will be allowed, but this violation will be + logged with a tag of access being "ALLOWED unconfined". + type: boolean disabled: default: false description: Whether the profile is disabled and should be skipped From 400f4c474392193eb1baa7da801d12a4f19040a2 Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Wed, 4 Dec 2024 09:30:20 +0000 Subject: [PATCH 2/7] Document the apparmor profile type API Change-Id: Id5272f5ba5b6858e3d620718964e4798f75bec6d Signed-off-by: Cosmin Cojocar --- .../v1alpha1/apparmorprofile_types.go | 33 +++++++++++++++---- ...ofiles-operator.clusterserviceversion.yaml | 2 +- ...es-operator.x-k8s.io_apparmorprofiles.yaml | 17 ++++++++++ deploy/base-crds/crds/apparmorprofile.yaml | 17 ++++++++++ deploy/helm/crds/crds.yaml | 17 ++++++++++ deploy/namespace-operator.yaml | 17 ++++++++++ deploy/openshift-dev.yaml | 17 ++++++++++ deploy/openshift-downstream.yaml | 17 ++++++++++ deploy/operator.yaml | 17 ++++++++++ deploy/webhook-operator.yaml | 17 ++++++++++ 10 files changed, 164 insertions(+), 7 deletions(-) diff --git a/api/apparmorprofile/v1alpha1/apparmorprofile_types.go b/api/apparmorprofile/v1alpha1/apparmorprofile_types.go index 1987efffe5..2295d01b91 100644 --- a/api/apparmorprofile/v1alpha1/apparmorprofile_types.go +++ b/api/apparmorprofile/v1alpha1/apparmorprofile_types.go @@ -31,36 +31,57 @@ var ( _ profilebasev1alpha1.SecurityProfileBase = &AppArmorProfile{} ) +// AppArmorExecutablesRules stores the rules for allowed executable. type AppArmorExecutablesRules struct { + // AllowedExecutables list of allowed executables. AllowedExecutables *[]string `json:"allowedExecutables,omitempty"` - AllowedLibraries *[]string `json:"allowedLibraries,omitempty"` + // AllowedLibraries list of allowed libraries. + AllowedLibraries *[]string `json:"allowedLibraries,omitempty"` } +// AppArmorFsRules stores the rules for file system access. type AppArmorFsRules struct { - ReadOnlyPaths *[]string `json:"readOnlyPaths,omitempty"` + // ReadOnlyPaths list of allowed read only file paths. + ReadOnlyPaths *[]string `json:"readOnlyPaths,omitempty"` + // WriteOnlyPaths list of allowed write only file paths. WriteOnlyPaths *[]string `json:"writeOnlyPaths,omitempty"` + // ReadWritePaths list of allowed read write file paths. ReadWritePaths *[]string `json:"readWritePaths,omitempty"` } +// AppArmorAllowedProtocols stores the rules for allowed networking protocols. type AppArmorAllowedProtocols struct { + // AllowTCP allows TCP socket connections. AllowTCP *bool `json:"allowTcp,omitempty"` + // AllowUDP allows UDP sockets connections. AllowUDP *bool `json:"allowUdp,omitempty"` } +// AppArmorNetworkRules stores the rules for network access. type AppArmorNetworkRules struct { - AllowRaw *bool `json:"allowRaw,omitempty"` + // AllowRaw allows raw sockets. + AllowRaw *bool `json:"allowRaw,omitempty"` + // Protocols keeps the allowed networking protocols. Protocols *AppArmorAllowedProtocols `json:"allowedProtocols,omitempty"` } +// AllowedCapabilities stores the rules of allowed Linux capabilities. type AppArmorCapabilityRules struct { + // AllowedCapabilities lost of allowed capabilities. AllowedCapabilities []string `json:"allowedCapabilities,omitempty"` } +// AppArmorAbstract AppArmor profile which stores various allowed list for +// executable, file, network, capabilities access. type AppArmorAbstract struct { + // Executable rules for allowed executables. Executable *AppArmorExecutablesRules `json:"executable,omitempty"` - Filesystem *AppArmorFsRules `json:"filesystem,omitempty"` - Network *AppArmorNetworkRules `json:"network,omitempty"` - Capability *AppArmorCapabilityRules `json:"capability,omitempty"` + // Filesystem rules for filesystem access. + Filesystem *AppArmorFsRules `json:"filesystem,omitempty"` + // Network rules for network access. + Network *AppArmorNetworkRules `json:"network,omitempty"` + // Capability rules for Linux capabilities. + Capability *AppArmorCapabilityRules `json:"capability,omitempty"` } // AppArmorProfileSpec defines the desired state of AppArmorProfile. diff --git a/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml b/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml index 6e22440719..e6360da25e 100644 --- a/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml +++ b/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml @@ -248,7 +248,7 @@ metadata: capabilities: Basic Install categories: Security containerImage: registry.k8s.io/security-profiles-operator/security-profiles-operator:v0.8.4 - createdAt: "2024-12-04T09:14:26Z" + createdAt: "2024-12-04T09:25:56Z" olm.skipRange: '>=0.4.1 <0.8.5-dev' operatorframework.io/cluster-monitoring: "true" operatorframework.io/suggested-namespace: security-profiles-operator diff --git a/bundle/manifests/security-profiles-operator.x-k8s.io_apparmorprofiles.yaml b/bundle/manifests/security-profiles-operator.x-k8s.io_apparmorprofiles.yaml index 46c3b5daf8..bac33bfc1b 100644 --- a/bundle/manifests/security-profiles-operator.x-k8s.io_apparmorprofiles.yaml +++ b/bundle/manifests/security-profiles-operator.x-k8s.io_apparmorprofiles.yaml @@ -53,47 +53,64 @@ spec: executable, file, network and capabilities access. properties: capability: + description: Capability rules for Linux capabilities. properties: allowedCapabilities: + description: AllowedCapabilities lost of allowed capabilities. items: type: string type: array type: object executable: + description: Executable rules for allowed executables. properties: allowedExecutables: + description: AllowedExecutables list of allowed executables. items: type: string type: array allowedLibraries: + description: AllowedLibraries list of allowed libraries. items: type: string type: array type: object filesystem: + description: Filesystem rules for filesystem access. properties: readOnlyPaths: + description: ReadOnlyPaths list of allowed read only file + paths. items: type: string type: array readWritePaths: + description: ReadWritePaths list of allowed read write file + paths. items: type: string type: array writeOnlyPaths: + description: WriteOnlyPaths list of allowed write only file + paths. items: type: string type: array type: object network: + description: Network rules for network access. properties: allowRaw: + description: AllowRaw allows raw sockets. type: boolean allowedProtocols: + description: Protocols keeps the allowed networking protocols. properties: allowTcp: + description: AllowTCP allows TCP socket connections. type: boolean allowUdp: + description: AllowUDP allows UDP sockets connections. type: boolean type: object type: object diff --git a/deploy/base-crds/crds/apparmorprofile.yaml b/deploy/base-crds/crds/apparmorprofile.yaml index 91099cafa2..7832ae77b5 100644 --- a/deploy/base-crds/crds/apparmorprofile.yaml +++ b/deploy/base-crds/crds/apparmorprofile.yaml @@ -50,47 +50,64 @@ spec: executable, file, network and capabilities access. properties: capability: + description: Capability rules for Linux capabilities. properties: allowedCapabilities: + description: AllowedCapabilities lost of allowed capabilities. items: type: string type: array type: object executable: + description: Executable rules for allowed executables. properties: allowedExecutables: + description: AllowedExecutables list of allowed executables. items: type: string type: array allowedLibraries: + description: AllowedLibraries list of allowed libraries. items: type: string type: array type: object filesystem: + description: Filesystem rules for filesystem access. properties: readOnlyPaths: + description: ReadOnlyPaths list of allowed read only file + paths. items: type: string type: array readWritePaths: + description: ReadWritePaths list of allowed read write file + paths. items: type: string type: array writeOnlyPaths: + description: WriteOnlyPaths list of allowed write only file + paths. items: type: string type: array type: object network: + description: Network rules for network access. properties: allowRaw: + description: AllowRaw allows raw sockets. type: boolean allowedProtocols: + description: Protocols keeps the allowed networking protocols. properties: allowTcp: + description: AllowTCP allows TCP socket connections. type: boolean allowUdp: + description: AllowUDP allows UDP sockets connections. type: boolean type: object type: object diff --git a/deploy/helm/crds/crds.yaml b/deploy/helm/crds/crds.yaml index f4264f2f1a..07a17ba90f 100644 --- a/deploy/helm/crds/crds.yaml +++ b/deploy/helm/crds/crds.yaml @@ -2240,47 +2240,64 @@ spec: executable, file, network and capabilities access. properties: capability: + description: Capability rules for Linux capabilities. properties: allowedCapabilities: + description: AllowedCapabilities lost of allowed capabilities. items: type: string type: array type: object executable: + description: Executable rules for allowed executables. properties: allowedExecutables: + description: AllowedExecutables list of allowed executables. items: type: string type: array allowedLibraries: + description: AllowedLibraries list of allowed libraries. items: type: string type: array type: object filesystem: + description: Filesystem rules for filesystem access. properties: readOnlyPaths: + description: ReadOnlyPaths list of allowed read only file + paths. items: type: string type: array readWritePaths: + description: ReadWritePaths list of allowed read write file + paths. items: type: string type: array writeOnlyPaths: + description: WriteOnlyPaths list of allowed write only file + paths. items: type: string type: array type: object network: + description: Network rules for network access. properties: allowRaw: + description: AllowRaw allows raw sockets. type: boolean allowedProtocols: + description: Protocols keeps the allowed networking protocols. properties: allowTcp: + description: AllowTCP allows TCP socket connections. type: boolean allowUdp: + description: AllowUDP allows UDP sockets connections. type: boolean type: object type: object diff --git a/deploy/namespace-operator.yaml b/deploy/namespace-operator.yaml index e39fe17d90..589f9ebfd8 100644 --- a/deploy/namespace-operator.yaml +++ b/deploy/namespace-operator.yaml @@ -2240,47 +2240,64 @@ spec: executable, file, network and capabilities access. properties: capability: + description: Capability rules for Linux capabilities. properties: allowedCapabilities: + description: AllowedCapabilities lost of allowed capabilities. items: type: string type: array type: object executable: + description: Executable rules for allowed executables. properties: allowedExecutables: + description: AllowedExecutables list of allowed executables. items: type: string type: array allowedLibraries: + description: AllowedLibraries list of allowed libraries. items: type: string type: array type: object filesystem: + description: Filesystem rules for filesystem access. properties: readOnlyPaths: + description: ReadOnlyPaths list of allowed read only file + paths. items: type: string type: array readWritePaths: + description: ReadWritePaths list of allowed read write file + paths. items: type: string type: array writeOnlyPaths: + description: WriteOnlyPaths list of allowed write only file + paths. items: type: string type: array type: object network: + description: Network rules for network access. properties: allowRaw: + description: AllowRaw allows raw sockets. type: boolean allowedProtocols: + description: Protocols keeps the allowed networking protocols. properties: allowTcp: + description: AllowTCP allows TCP socket connections. type: boolean allowUdp: + description: AllowUDP allows UDP sockets connections. type: boolean type: object type: object diff --git a/deploy/openshift-dev.yaml b/deploy/openshift-dev.yaml index e1776a226b..413e044a21 100644 --- a/deploy/openshift-dev.yaml +++ b/deploy/openshift-dev.yaml @@ -63,47 +63,64 @@ spec: executable, file, network and capabilities access. properties: capability: + description: Capability rules for Linux capabilities. properties: allowedCapabilities: + description: AllowedCapabilities lost of allowed capabilities. items: type: string type: array type: object executable: + description: Executable rules for allowed executables. properties: allowedExecutables: + description: AllowedExecutables list of allowed executables. items: type: string type: array allowedLibraries: + description: AllowedLibraries list of allowed libraries. items: type: string type: array type: object filesystem: + description: Filesystem rules for filesystem access. properties: readOnlyPaths: + description: ReadOnlyPaths list of allowed read only file + paths. items: type: string type: array readWritePaths: + description: ReadWritePaths list of allowed read write file + paths. items: type: string type: array writeOnlyPaths: + description: WriteOnlyPaths list of allowed write only file + paths. items: type: string type: array type: object network: + description: Network rules for network access. properties: allowRaw: + description: AllowRaw allows raw sockets. type: boolean allowedProtocols: + description: Protocols keeps the allowed networking protocols. properties: allowTcp: + description: AllowTCP allows TCP socket connections. type: boolean allowUdp: + description: AllowUDP allows UDP sockets connections. type: boolean type: object type: object diff --git a/deploy/openshift-downstream.yaml b/deploy/openshift-downstream.yaml index aaef6deba1..7b4cfe27a6 100644 --- a/deploy/openshift-downstream.yaml +++ b/deploy/openshift-downstream.yaml @@ -2240,47 +2240,64 @@ spec: executable, file, network and capabilities access. properties: capability: + description: Capability rules for Linux capabilities. properties: allowedCapabilities: + description: AllowedCapabilities lost of allowed capabilities. items: type: string type: array type: object executable: + description: Executable rules for allowed executables. properties: allowedExecutables: + description: AllowedExecutables list of allowed executables. items: type: string type: array allowedLibraries: + description: AllowedLibraries list of allowed libraries. items: type: string type: array type: object filesystem: + description: Filesystem rules for filesystem access. properties: readOnlyPaths: + description: ReadOnlyPaths list of allowed read only file + paths. items: type: string type: array readWritePaths: + description: ReadWritePaths list of allowed read write file + paths. items: type: string type: array writeOnlyPaths: + description: WriteOnlyPaths list of allowed write only file + paths. items: type: string type: array type: object network: + description: Network rules for network access. properties: allowRaw: + description: AllowRaw allows raw sockets. type: boolean allowedProtocols: + description: Protocols keeps the allowed networking protocols. properties: allowTcp: + description: AllowTCP allows TCP socket connections. type: boolean allowUdp: + description: AllowUDP allows UDP sockets connections. type: boolean type: object type: object diff --git a/deploy/operator.yaml b/deploy/operator.yaml index ee67c50264..ef918b7769 100644 --- a/deploy/operator.yaml +++ b/deploy/operator.yaml @@ -2240,47 +2240,64 @@ spec: executable, file, network and capabilities access. properties: capability: + description: Capability rules for Linux capabilities. properties: allowedCapabilities: + description: AllowedCapabilities lost of allowed capabilities. items: type: string type: array type: object executable: + description: Executable rules for allowed executables. properties: allowedExecutables: + description: AllowedExecutables list of allowed executables. items: type: string type: array allowedLibraries: + description: AllowedLibraries list of allowed libraries. items: type: string type: array type: object filesystem: + description: Filesystem rules for filesystem access. properties: readOnlyPaths: + description: ReadOnlyPaths list of allowed read only file + paths. items: type: string type: array readWritePaths: + description: ReadWritePaths list of allowed read write file + paths. items: type: string type: array writeOnlyPaths: + description: WriteOnlyPaths list of allowed write only file + paths. items: type: string type: array type: object network: + description: Network rules for network access. properties: allowRaw: + description: AllowRaw allows raw sockets. type: boolean allowedProtocols: + description: Protocols keeps the allowed networking protocols. properties: allowTcp: + description: AllowTCP allows TCP socket connections. type: boolean allowUdp: + description: AllowUDP allows UDP sockets connections. type: boolean type: object type: object diff --git a/deploy/webhook-operator.yaml b/deploy/webhook-operator.yaml index 6f8df04eea..cf92014dd2 100644 --- a/deploy/webhook-operator.yaml +++ b/deploy/webhook-operator.yaml @@ -63,47 +63,64 @@ spec: executable, file, network and capabilities access. properties: capability: + description: Capability rules for Linux capabilities. properties: allowedCapabilities: + description: AllowedCapabilities lost of allowed capabilities. items: type: string type: array type: object executable: + description: Executable rules for allowed executables. properties: allowedExecutables: + description: AllowedExecutables list of allowed executables. items: type: string type: array allowedLibraries: + description: AllowedLibraries list of allowed libraries. items: type: string type: array type: object filesystem: + description: Filesystem rules for filesystem access. properties: readOnlyPaths: + description: ReadOnlyPaths list of allowed read only file + paths. items: type: string type: array readWritePaths: + description: ReadWritePaths list of allowed read write file + paths. items: type: string type: array writeOnlyPaths: + description: WriteOnlyPaths list of allowed write only file + paths. items: type: string type: array type: object network: + description: Network rules for network access. properties: allowRaw: + description: AllowRaw allows raw sockets. type: boolean allowedProtocols: + description: Protocols keeps the allowed networking protocols. properties: allowTcp: + description: AllowTCP allows TCP socket connections. type: boolean allowUdp: + description: AllowUDP allows UDP sockets connections. type: boolean type: object type: object From 54ca1e6c241a737940f49346b40a02ec6d607db8 Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Wed, 4 Dec 2024 09:59:27 +0000 Subject: [PATCH 3/7] Extend the apparmor profile template with profile mode flag and adapt the generate profile Change-Id: If59b953c69e48e68b2bb56198567342ca9483170 Signed-off-by: Cosmin Cojocar --- internal/pkg/cli/converter/converter.go | 2 +- internal/pkg/cli/converter/converter_test.go | 40 ++++++++++++++++--- internal/pkg/cli/recorder/recorder.go | 2 +- .../apparmorprofile/apparmor_supported.go | 2 +- .../apparmorprofile/crd2armor/crd2armor.go | 21 +++++++--- 5 files changed, 53 insertions(+), 14 deletions(-) diff --git a/internal/pkg/cli/converter/converter.go b/internal/pkg/cli/converter/converter.go index 309ad10887..af30a9a6c7 100644 --- a/internal/pkg/cli/converter/converter.go +++ b/internal/pkg/cli/converter/converter.go @@ -70,7 +70,7 @@ func (p *Converter) Run() error { programName = obj.Name } - outStr, err := crd2armor.GenerateProfile(programName, &obj.Spec.Abstract) + outStr, err := crd2armor.GenerateProfile(programName, obj.Spec.ComplainMode, &obj.Spec.Abstract) if err != nil { return fmt.Errorf("build raw apparmor profile: %w", err) } diff --git a/internal/pkg/cli/converter/converter_test.go b/internal/pkg/cli/converter/converter_test.go index c2283e3de4..4df59876eb 100644 --- a/internal/pkg/cli/converter/converter_test.go +++ b/internal/pkg/cli/converter/converter_test.go @@ -40,10 +40,10 @@ func TestRun(t *testing.T) { for _, tc := range []struct { name string input string - outputContains string + outputContains []string }{ { - name: "AppArmor CRD", + name: "AppArmor CRD in enforce mode by default", input: ` apiVersion: security-profiles-operator.x-k8s.io/v1alpha1 kind: AppArmorProfile @@ -53,7 +53,35 @@ spec: readOnlyPaths: - /dev/null `, - outputContains: `deny /dev/null wl`, + outputContains: []string{`deny /dev/null wl`, `flags=(enforce,attach_disconnected,mediate_deleted)`}, + }, + { + name: "AppArmor CRD in enforce mode", + input: ` +apiVersion: security-profiles-operator.x-k8s.io/v1alpha1 +kind: AppArmorProfile +spec: + complainMode: false + abstract: + filesystem: + readOnlyPaths: + - /dev/null +`, + outputContains: []string{`deny /dev/null wl`, `flags=(enforce,attach_disconnected,mediate_deleted)`}, + }, + { + name: "AppArmor CRD in complain mode", + input: ` +apiVersion: security-profiles-operator.x-k8s.io/v1alpha1 +kind: AppArmorProfile +spec: + complainMode: true + abstract: + filesystem: + readOnlyPaths: + - /dev/null +`, + outputContains: []string{`deny /dev/null wl`, `flags=(complain,attach_disconnected,mediate_deleted)`}, }, { name: "seccomp", @@ -67,7 +95,7 @@ spec: names: - foo `, - outputContains: `"defaultAction": "SCMP_ACT_ERRNO"`, + outputContains: []string{`"defaultAction": "SCMP_ACT_ERRNO"`}, }, } { input := tc.input @@ -83,7 +111,9 @@ spec: err := sut.Run() require.NoError(t, err) _, actual, _ := mock.WriteFileArgsForCall(0) - require.Contains(t, string(actual), outputContains) + for _, contain := range outputContains { + require.Contains(t, string(actual), contain) + } }) } diff --git a/internal/pkg/cli/recorder/recorder.go b/internal/pkg/cli/recorder/recorder.go index eeb7e5d409..e71f565277 100644 --- a/internal/pkg/cli/recorder/recorder.go +++ b/internal/pkg/cli/recorder/recorder.go @@ -432,7 +432,7 @@ func (r *Recorder) buildAppArmorProfileRaw(writer io.Writer, spec *apparmorprofi } abstract := spec.Abstract - raw, err := crd2armor.GenerateProfile(programName, &abstract) + raw, err := crd2armor.GenerateProfile(programName, spec.ComplainMode, &abstract) if err != nil { return fmt.Errorf("build raw apparmor profile: %w", err) } diff --git a/internal/pkg/daemon/apparmorprofile/apparmor_supported.go b/internal/pkg/daemon/apparmorprofile/apparmor_supported.go index b041e190d1..762a476a75 100644 --- a/internal/pkg/daemon/apparmorprofile/apparmor_supported.go +++ b/internal/pkg/daemon/apparmorprofile/apparmor_supported.go @@ -79,7 +79,7 @@ func (a *aaProfileManager) InstallProfile(bp profilebasev1alpha1.StatusBaseUser) return false, errors.New(errInvalidCustomResourceType) } - policy, err := crd2armor.GenerateProfile(profile.GetProfileName(), &profile.Spec.Abstract) + policy, err := crd2armor.GenerateProfile(profile.GetProfileName(), profile.Spec.ComplainMode, &profile.Spec.Abstract) if err != nil { return false, fmt.Errorf("generating raw apparmor profile: %w", err) } diff --git a/internal/pkg/daemon/apparmorprofile/crd2armor/crd2armor.go b/internal/pkg/daemon/apparmorprofile/crd2armor/crd2armor.go index 3ad8d1c2cf..40f359310a 100644 --- a/internal/pkg/daemon/apparmorprofile/crd2armor/crd2armor.go +++ b/internal/pkg/daemon/apparmorprofile/crd2armor/crd2armor.go @@ -27,7 +27,7 @@ import ( var appArmorTemplate = ` # Generated by https://github.com/kubernetes-sigs/security-profiles-operator, do not edit by hand. #include -profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { +profile {{.Name}} flags=({{.ProfileMode}},attach_disconnected,mediate_deleted) { #include # Executable rules @@ -91,18 +91,20 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { ` type apparmorTemplateArgs struct { - Name string - Abstract *apparmorprofileapi.AppArmorAbstract + Name string + ProfileMode string + Abstract *apparmorprofileapi.AppArmorAbstract } // GenerateProfile uses the CRD representation of an abstracted profile to generate a // full AppArmor profile. -func GenerateProfile(name string, abstract *apparmorprofileapi.AppArmorAbstract) (string, error) { +func GenerateProfile(name string, complainMode bool, abstract *apparmorprofileapi.AppArmorAbstract) (string, error) { var generated bytes.Buffer templateArgs := apparmorTemplateArgs{ - Name: name, - Abstract: abstract, + Name: name, + ProfileMode: profileMode(complainMode), + Abstract: abstract, } if abstract == nil { @@ -118,3 +120,10 @@ func GenerateProfile(name string, abstract *apparmorprofileapi.AppArmorAbstract) } return generated.String(), nil } + +func profileMode(complainMode bool) string { + if complainMode { + return "complain" + } + return "enforce" +} From e8d21055571c5ff0bf79bddf828f0740dc616ce6 Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Wed, 4 Dec 2024 11:00:14 +0000 Subject: [PATCH 4/7] Add e2e test for apparmor complain mode Change-Id: I8a676faa5ccfbfe409905c5d10ade66a591e542d Signed-off-by: Cosmin Cojocar --- .../apparmorprofile-sleep-complain-mode.yaml | 17 +++++ hack/ci/e2e-apparmor.sh | 68 ++++++++++++++++--- 2 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 examples/apparmorprofile-sleep-complain-mode.yaml diff --git a/examples/apparmorprofile-sleep-complain-mode.yaml b/examples/apparmorprofile-sleep-complain-mode.yaml new file mode 100644 index 0000000000..07213b17b7 --- /dev/null +++ b/examples/apparmorprofile-sleep-complain-mode.yaml @@ -0,0 +1,17 @@ +apiVersion: security-profiles-operator.x-k8s.io/v1alpha1 +kind: AppArmorProfile +metadata: + labels: + spo.x-k8s.io/container-id: test-pod + spo.x-k8s.io/profile-id: AppArmorProfile-test-recording-test-pod + spo.x-k8s.io/recording-id: test-recording + name: test-recording-test-pod + namespace: security-profiles-operator +spec: + # Deny all file access to check if the pod stats in complain mode. + complainMode: true + abstract: + readOnlyPaths: [] + readWritePaths: [] + writeOnlyPaths: [] + disabled: false diff --git a/hack/ci/e2e-apparmor.sh b/hack/ci/e2e-apparmor.sh index d41e8131f7..2e0c89bdea 100755 --- a/hack/ci/e2e-apparmor.sh +++ b/hack/ci/e2e-apparmor.sh @@ -22,6 +22,7 @@ APPARMOR_PROFILE_NAME="test-recording-$PODNAME" APPARMOR_PROFILE_FILE="/tmp/apparmorprofile-sleep.yaml" APPARMOR_REFERENCE_PROFILE_FILE="examples/apparmorprofile-sleep.yaml" APPARMOR_REFERENCE_TMP_PROFILE_FILE="/tmp/apparmorprofile-sleep-reference.yaml" +APPARMOR_PROFILE_FILE_COMPLAIN_MODE="examples/apparmorprofile-sleep-complain-mode.yaml" SLEEP_INTERVAL_RECORDING="30" # 30s sleep interval during recording. SLEEP_INTERVAL_VERIFICATION="300" # 5min to make sure that the enforcement check finds a running PID. @@ -85,25 +86,32 @@ wait_for_pod_status() { done } -check_profile_enforcement() { +check_profile_mode() { local command="$1" local apparmor_profile="$2" + local apparmor_profile_mode="$3" local pid="$(pidof $command)" - local enforce="$(cat /proc/${pid}/attr/current)" - local reference="$apparmor_profile (enforce)" - if [[ "$reference" != "$enforce" ]]; then - echo "Apparmor profile $apparmor_profile not enforced: $enforce" + local mode="$(cat /proc/${pid}/attr/current)" + local reference="$apparmor_profile ($apparmor_profile_mode)" + if [[ "$reference" != "$mode" ]]; then + echo "Apparmor profile $apparmor_profile not in $apparmor_profile_mode mode: $mode" exit 1 fi - echo "Apparmor profile successfully enforced: $enforce" + echo "Apparmor profile mode: $mode" } -record_apparmor_profile() { +# Records and checks if the profile is properly installed by default in enforce mode. +check_apparmor_profile_recording() { + echo "--------------------------------------------------------------------" + echo "Checking apparmor profile recording and installation in enforce mode" + echo "--------------------------------------------------------------------" + echo "Enable Apparmor profile" k patch spod spod --type=merge -p '{"spec":{"enableAppArmor":true}}' k rollout status ds spod --timeout 360s k_wait spod spod + echo "--------------------------" echo "Recording apparmor profile" echo "--------------------------" @@ -125,6 +133,7 @@ record_apparmor_profile() { wait_for apparmorprofile $APPARMOR_PROFILE_NAME + echo "-------------------------" echo "Verifying apparmor profile" echo "-------------------------" @@ -137,7 +146,46 @@ record_apparmor_profile() { wait_for_pod_status "$PODNAME" "Running" echo "Checking apparmor profile enforcement on container" - check_profile_enforcement "sleep" $APPARMOR_PROFILE_NAME + check_profile_mode "sleep" $APPARMOR_PROFILE_NAME "enforce" + + echo "Deleting pod $PODNAME" + k delete -f "$sec_pod_file" + + echo "Deleting apparmor profile $APPARMOR_PROFILE_NAME" + k delete apparmorprofile $APPARMOR_PROFILE_NAME +} + +# Install a profile in complain mode, and checks if the pod properly starts +# even though all access is denied. +check_apparmor_complain_mode() { + echo "-------------------------------------------------------" + echo "Checking apparmor profile installation in complain mode" + echo "-------------------------------------------------------" + + echo "Enable Apparmor profile" + k patch spod spod --type=merge -p '{"spec":{"enableAppArmor":true}}' + k rollout status ds spod --timeout 360s + k_wait spod spod + + echo "--------------------------" + echo "Installing apparmor profile" + echo "--------------------------" + + echo "Install apparmor profile in complain mode $APPARMOR_PROFILE_FILE_COMPLAIN_MODE" + k apply -f $APPARMOR_PROFILE_FILE_COMPLAIN_MODE + wait_for apparmorprofile $APPARMOR_PROFILE_NAME + + echo "-------------------------" + echo "Verifying apparmor profile" + echo "-------------------------" + + echo "Creating pod $PODNAME with apparmor profile in complain mode in security context" + sec_pod_file="${TMP_DIR}/${PODNAME}-apparmor.yml" + create_pod $PODNAME $sec_pod_file $SLEEP_INTERVAL_VERIFICATION $APPARMOR_PROFILE_NAME + wait_for_pod_status "$PODNAME" "Running" + + echo "Checking apparmor profile is in complain mode on container" + check_profile_mode "sleep" $APPARMOR_PROFILE_NAME "complain" echo "Deleting pod $PODNAME" k delete -f "$sec_pod_file" @@ -151,4 +199,6 @@ record_apparmor_profile() { install_yq install_operator -record_apparmor_profile + +check_apparmor_profile_recording +check_apparmor_complain_mode From 94ca3cd692c7035adedc2db08521bb43dc90787e Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Wed, 4 Dec 2024 11:01:48 +0000 Subject: [PATCH 5/7] Fix the apparmor e2e test for complain mode Change-Id: Idd9ac0c6d409293f905df44df974646f0c48b3fb Signed-off-by: Cosmin Cojocar --- examples/apparmorprofile-sleep-complain-mode.yaml | 1 + hack/ci/e2e-apparmor.sh | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/apparmorprofile-sleep-complain-mode.yaml b/examples/apparmorprofile-sleep-complain-mode.yaml index 07213b17b7..31d64d5a14 100644 --- a/examples/apparmorprofile-sleep-complain-mode.yaml +++ b/examples/apparmorprofile-sleep-complain-mode.yaml @@ -11,6 +11,7 @@ spec: # Deny all file access to check if the pod stats in complain mode. complainMode: true abstract: + filesystem: readOnlyPaths: [] readWritePaths: [] writeOnlyPaths: [] diff --git a/hack/ci/e2e-apparmor.sh b/hack/ci/e2e-apparmor.sh index 2e0c89bdea..ac901ad3f1 100755 --- a/hack/ci/e2e-apparmor.sh +++ b/hack/ci/e2e-apparmor.sh @@ -133,9 +133,9 @@ check_apparmor_profile_recording() { wait_for apparmorprofile $APPARMOR_PROFILE_NAME - echo "-------------------------" + echo "--------------------------" echo "Verifying apparmor profile" - echo "-------------------------" + echo "--------------------------" echo "Checking the recorded appamror profile matches the reference" check_apparmor_profile @@ -167,17 +167,20 @@ check_apparmor_complain_mode() { k rollout status ds spod --timeout 360s k_wait spod spod - echo "--------------------------" + echo "---------------------------" echo "Installing apparmor profile" - echo "--------------------------" + echo "---------------------------" echo "Install apparmor profile in complain mode $APPARMOR_PROFILE_FILE_COMPLAIN_MODE" k apply -f $APPARMOR_PROFILE_FILE_COMPLAIN_MODE wait_for apparmorprofile $APPARMOR_PROFILE_NAME - echo "-------------------------" + echo "--------------------------" echo "Verifying apparmor profile" - echo "-------------------------" + echo "--------------------------" + + TMP_DIR=$(mktemp -d) + trap 'rm -rf $TMP_DIR' EXIT echo "Creating pod $PODNAME with apparmor profile in complain mode in security context" sec_pod_file="${TMP_DIR}/${PODNAME}-apparmor.yml" From 285f6e21a4ca0d0e7decfc098c369f66eb461f19 Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Wed, 4 Dec 2024 12:34:14 +0000 Subject: [PATCH 6/7] Update the documenation with more details for complain mode Change-Id: I61832a638e8c17cc14175841c8e0d2e3e97bb2ab Signed-off-by: Cosmin Cojocar --- installation-usage.md | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/installation-usage.md b/installation-usage.md index dd36e7f2b7..737d7e44f2 100644 --- a/installation-usage.md +++ b/installation-usage.md @@ -1778,26 +1778,37 @@ metadata: description: Block writing to any files in the disk. spec: abstract: - filesystem: [] + filesystem: + readOnlyPaths: [] + readWritePaths: [] + writeOnlyPaths: [] + complainMode: false + disabled: false ``` Note that the name of the profile inside `spec.policy` matches the `metadata.name`, this is currently a requirement as mentioned within the known limitations below. Based on the policy above, an AppArmor profile `test-profile` will be created and -loaded in all nodes within the cluster. +loaded in all nodes within the cluster. The profile will be placed in `enforce` mode. +If you want to switch it to complain mode, you need to change the `complainMode` flag +to `true`. In this mode, if the profile rules don't grant permissions to an action, +that action will be allowed, but the violation will be logged with a tag of ALLOWED unconfined. ### Apply an AppArmor profile to a pod Once the AppArmor profile is created and loaded in all cluster nodes, -you can restrict Pod's access with the annotation: - -`container.apparmor.security.beta.kubernetes.io/: test-profile` +you can restrict Pod's access in its security context as following: +``` + securityContext: + appArmorProfile: + type: Localhost + localhostProfile: test-profile +``` -When [AppArmor becomes GA](https://github.com/kubernetes/enhancements/pull/3298) a new field within SecurityContext will be created to replace the annotations above. -For up-to-date information on how to use AppArmor in Kubernetes, refer to the [official documentation](https://kubernetes.io/docs/tutorials/security/apparmor/). +You can see more details in the [official documentation](https://kubernetes.io/docs/tutorials/security/apparmor/). -### Record a AppArmor profile +### Record an AppArmor profile The operator is able to record AppArmor profiles for a workload using the build-in eBPF recorder. For more details, please refer to the [eBPF based recording](#ebpf-based-recording)) section. @@ -1808,21 +1819,11 @@ Note that log enricher doesn't support recording of AppArmor profiles. ### Known limitations -- The name set for the AppArmorProfile CRD must match the policy name - defined within `spec.policy`. Otherwise the reconciler will fail as it - won't be able to confirm the policy was correctly loaded. - The reconciler will simply load the profiles across the cluster. If an - existing profile with the same name exists, it will be replaced. -- The SPO does not validate the profile contents. Invalid profiles - will error when loading into the kernel. The error can be found on the spod - pod and the message will roughly look like: - ``` - E1112 08:35:24.072544 8668 controller.go:326] "msg"="Reconciler error" "error"="cannot load profile into node: running action: exit status 1" "appArmorProfile"={"name":"","namespace":"security-profiles-operator"} "controller"="apparmorprofile" "controllerGroup"="security-profiles-operator.x-k8s.io" "controllerKind"="AppArmorProfile" "name"="" "namespace"="security-profiles-operator" "reconcileID"="035a4edd-cdd9-4c35-a1be-924939538ce4" - ``` + existing profile with the same name exists, it will be replaced. This might cause + an existing profile to be overwritten (See [issue 2582](https://github.com/kubernetes-sigs/security-profiles-operator/issues/2582) for details). - Restrictive profiles may block sub processes to be created, or a container from - successfully loading. In such cases, the denied rules may not show up in the - log-enricher logs, as SPO may fail to find the running process to correlate to the - pod information. To work around the issue, set the AppArmor profile to complain mode. + successfully loading. To work around the issue, set the AppArmor profile to complain mode. ## Command Line Interface (CLI) From ceed5712372ae565591a71ef0e580dc1ed837a7d Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Wed, 4 Dec 2024 12:45:42 +0000 Subject: [PATCH 7/7] Udpate docs TOC Change-Id: I2c79838716ddac5a2a0a8f79902599ae590f55b3 Signed-off-by: Cosmin Cojocar --- installation-usage.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/installation-usage.md b/installation-usage.md index 737d7e44f2..b898abfe35 100644 --- a/installation-usage.md +++ b/installation-usage.md @@ -1,7 +1,6 @@ # Installation and Usage - - [Features](#features) - [Architecture](#architecture) - [Tutorials and Demos](#tutorials-and-demos) @@ -54,7 +53,7 @@ - [Replicating controllers and SCCs](#replicating-controllers-and-sccs) - [Create an AppArmor profile](#create-an-apparmor-profile) - [Apply an AppArmor profile to a pod](#apply-an-apparmor-profile-to-a-pod) - - [Record a AppArmor profile](#record-a-apparmor-profile) + - [Record an AppArmor profile](#record-an-apparmor-profile) - [Known limitations](#known-limitations) - [Command Line Interface (CLI)](#command-line-interface-cli) - [Record seccomp profiles for a command](#record-seccomp-profiles-for-a-command)