@@ -29,6 +29,8 @@ type AppArmorEnforcer struct {
29
29
30
30
// default profile
31
31
ApparmorDefault string
32
+ // default privileged profile
33
+ ApparmorDefaultPrivileged string
32
34
33
35
// host profile
34
36
HostProfile string
@@ -37,6 +39,10 @@ type AppArmorEnforcer struct {
37
39
AppArmorProfiles map [string ][]string
38
40
AppArmorProfilesLock * sync.RWMutex
39
41
42
+ // to keep track of privileged profiles for clean deletion
43
+ AppArmorPrivilegedProfiles map [string ]struct {}
44
+ AppArmorPrivilegedProfilesLock * sync.RWMutex
45
+
40
46
// Regex used to get profile Names
41
47
rgx * regexp.Regexp
42
48
}
@@ -50,38 +56,39 @@ func NewAppArmorEnforcer(node tp.Node, logger *fd.Feeder) *AppArmorEnforcer {
50
56
51
57
// default profile
52
58
ae .ApparmorDefault = `## == Managed by KubeArmor == ##
53
-
54
59
#include <tunables/global>
60
+
55
61
profile apparmor-default flags=(attach_disconnected,mediate_deleted) {
56
- ## == PRE START == ##
57
- #include <abstractions/base>
58
- umount,
59
- file,
60
- network,
61
- capability,
62
+ ## == PRE START == ##
63
+ ` + AppArmorDefaultPreStart +
64
+ `
65
+ ## == PRE END == ##
66
+
67
+ ## == POLICY START == ##
68
+ ## == POLICY END == ##
69
+
70
+ ## == POST START == ##
71
+ ` + AppArmorDefaultPostStart +
72
+ `
73
+ ## == POST END == ##
74
+ }
75
+ `
76
+
77
+ ae .ApparmorDefaultPrivileged = `## == Managed by KubeArmor == ##
78
+ #include <tunables/global>
79
+
80
+ profile apparmor-default flags=(attach_disconnected,mediate_deleted) {
81
+ ## == PRE START == ##
82
+ ` + AppArmorPrivilegedPreStart +
83
+ `
62
84
## == PRE END == ##
63
85
64
86
## == POLICY START == ##
65
87
## == POLICY END == ##
66
88
67
89
## == POST START == ##
68
- /lib/x86_64-linux-gnu/{*,**} rm,
69
-
70
- deny @{PROC}/{*,**^[0-9*],sys/kernel/shm*} wkx,
71
- deny @{PROC}/sysrq-trigger rwklx,
72
- deny @{PROC}/mem rwklx,
73
- deny @{PROC}/kmem rwklx,
74
- deny @{PROC}/kcore rwklx,
75
-
76
- deny mount,
77
-
78
- deny /sys/[^f]*/** wklx,
79
- deny /sys/f[^s]*/** wklx,
80
- deny /sys/fs/[^c]*/** wklx,
81
- deny /sys/fs/c[^g]*/** wklx,
82
- deny /sys/fs/cg[^r]*/** wklx,
83
- deny /sys/firmware/efi/efivars/** rwklx,
84
- deny /sys/kernel/security/** rwklx,
90
+ ` + AppArmorPrivilegedPostStart +
91
+ `
85
92
## == POST END == ##
86
93
}
87
94
`
@@ -96,6 +103,9 @@ deny /sys/kernel/security/** rwklx,
96
103
ae .AppArmorProfiles = map [string ][]string {}
97
104
ae .AppArmorProfilesLock = & sync.RWMutex {}
98
105
106
+ ae .AppArmorPrivilegedProfiles = map [string ]struct {}{}
107
+ ae .AppArmorPrivilegedProfilesLock = new (sync.RWMutex )
108
+
99
109
files , err := os .ReadDir ("/etc/apparmor.d" )
100
110
if err != nil {
101
111
ae .Logger .Errf ("Failed to read /etc/apparmor.d (%s)" , err .Error ())
@@ -173,7 +183,8 @@ func (ae *AppArmorEnforcer) DestroyAppArmorEnforcer() error {
173
183
}
174
184
175
185
for profile := range ae .AppArmorProfiles {
176
- ae .UnregisterAppArmorProfile ("" , profile )
186
+ _ , privileged := ae .AppArmorPrivilegedProfiles [profile ]
187
+ ae .UnregisterAppArmorProfile ("" , profile , privileged )
177
188
}
178
189
179
190
if cfg .GlobalCfg .HostPolicy {
@@ -190,7 +201,7 @@ func (ae *AppArmorEnforcer) DestroyAppArmorEnforcer() error {
190
201
// ================================= //
191
202
192
203
// RegisterAppArmorProfile Function
193
- func (ae * AppArmorEnforcer ) RegisterAppArmorProfile (podName , profileName string ) bool {
204
+ func (ae * AppArmorEnforcer ) RegisterAppArmorProfile (podName , profileName string , privileged bool ) bool {
194
205
// skip if AppArmorEnforcer is not active
195
206
if ae == nil {
196
207
return true
@@ -216,7 +227,15 @@ func (ae *AppArmorEnforcer) RegisterAppArmorProfile(podName, profileName string)
216
227
return true
217
228
}
218
229
219
- newProfile := strings .Replace (ae .ApparmorDefault , "apparmor-default" , profileName , - 1 )
230
+ // generate a profile with basic allows if a privileged container
231
+ var newProfile string
232
+ if privileged {
233
+ newProfile = strings .Replace (ae .ApparmorDefaultPrivileged , "apparmor-default" , profileName , - 1 )
234
+ ae .AppArmorPrivilegedProfiles [profileName ] = struct {}{}
235
+ ae .Logger .Printf ("Added an AppArmor profile for a privileged container (%s, %s)" , podName , profileName )
236
+ } else {
237
+ newProfile = strings .Replace (ae .ApparmorDefault , "apparmor-default" , profileName , - 1 )
238
+ }
220
239
221
240
newFile , err := os .Create (filepath .Clean ("/etc/apparmor.d/" + profileName ))
222
241
if err != nil {
@@ -247,7 +266,7 @@ func (ae *AppArmorEnforcer) RegisterAppArmorProfile(podName, profileName string)
247
266
}
248
267
249
268
// UnregisterAppArmorProfile Function
250
- func (ae * AppArmorEnforcer ) UnregisterAppArmorProfile (podName , profileName string ) bool {
269
+ func (ae * AppArmorEnforcer ) UnregisterAppArmorProfile (podName , profileName string , privileged bool ) bool {
251
270
// skip if AppArmorEnforcer is not active
252
271
if ae == nil {
253
272
return true
@@ -285,7 +304,12 @@ func (ae *AppArmorEnforcer) UnregisterAppArmorProfile(podName, profileName strin
285
304
return false
286
305
}
287
306
288
- newProfile := strings .Replace (ae .ApparmorDefault , "apparmor-default" , profileName , - 1 )
307
+ var newProfile string
308
+ if privileged {
309
+ newProfile = strings .Replace (ae .ApparmorDefaultPrivileged , "apparmor-default" , profileName , - 1 )
310
+ } else {
311
+ newProfile = strings .Replace (ae .ApparmorDefault , "apparmor-default" , profileName , - 1 )
312
+ }
289
313
290
314
newFile , err := os .Create (filepath .Clean ("/etc/apparmor.d/" + profileName ))
291
315
if err != nil {
@@ -454,7 +478,15 @@ func (ae *AppArmorEnforcer) UnregisterAppArmorHostProfile() bool {
454
478
455
479
// UpdateAppArmorProfile Function
456
480
func (ae * AppArmorEnforcer ) UpdateAppArmorProfile (endPoint tp.EndPoint , appArmorProfile string , securityPolicies []tp.SecurityPolicy ) {
457
- if policyCount , newProfile , ok := ae .GenerateAppArmorProfile (appArmorProfile , securityPolicies , endPoint .DefaultPosture ); ok {
481
+
482
+ /* For privileged profiles, we maintain a separate map so that privileged pods
483
+ are identified separately and their profiles are generated accordingly
484
+ */
485
+ ae .AppArmorPrivilegedProfilesLock .Lock ()
486
+ _ , privileged := ae .AppArmorPrivilegedProfiles [appArmorProfile ]
487
+ ae .AppArmorPrivilegedProfilesLock .Unlock ()
488
+
489
+ if policyCount , newProfile , ok := ae .GenerateAppArmorProfile (appArmorProfile , securityPolicies , endPoint .DefaultPosture , privileged ); ok {
458
490
newfile , err := os .Create (filepath .Clean ("/etc/apparmor.d/" + appArmorProfile ))
459
491
if err != nil {
460
492
ae .Logger .Warnf ("Unable to open an AppArmor profile (%s, %s)" , appArmorProfile , err .Error ())
0 commit comments