diff --git a/apparmor/gen.go b/apparmor/gen.go new file mode 100644 index 0000000..bf9be2a --- /dev/null +++ b/apparmor/gen.go @@ -0,0 +1,92 @@ +package apparmor + +import ( + "io" + "os" + "text/template" +) + +type data struct { + Name string + Imports []string + InnerImports []string +} + +const baseTemplate = ` +{{range $value := .Imports}} +{{$value}} +{{end}} + +profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { +{{range $value := .InnerImports}} + {{$value}} +{{end}} + + network, + capability, + file, + umount, + + mount fstype=tmpfs, + mount fstype=mqueue, + mount fstype=fuse.*, + mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/, + mount fstype=efivarfs -> /sys/firmware/efi/efivars/, + mount fstype=fusectl -> /sys/fs/fuse/connections/, + mount fstype=securityfs -> /sys/kernel/security/, + mount fstype=debugfs -> /sys/kernel/debug/, + mount fstype=proc -> /proc/, + mount fstype=sysfs -> /sys/, + + deny @{PROC}/sys/fs/** wklx, + deny @{PROC}/sysrq-trigger rwklx, + deny @{PROC}/mem rwklx, + deny @{PROC}/kmem rwklx, + deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx, + deny @{PROC}/sys/kernel/*/** wklx, + + deny mount options=(ro, remount) -> /, + deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/, + deny mount fstype=devpts, + + deny /sys/[^f]*/** wklx, + deny /sys/f[^s]*/** wklx, + deny /sys/fs/[^c]*/** wklx, + deny /sys/fs/c[^g]*/** wklx, + deny /sys/fs/cg[^r]*/** wklx, + deny /sys/firmware/efi/efivars/** rwklx, + deny /sys/kernel/security/** rwklx, +} +` + +func generateProfile(out io.Writer) error { + compiled, err := template.New("apparmor_profile").Parse(baseTemplate) + if err != nil { + return err + } + data := &data{ + Name: "docker-default", + } + if tuntablesExists() { + data.Imports = append(data.Imports, "#include ") + } + if abstrctionsEsists() { + data.InnerImports = append(data.InnerImports, "#include ") + } + if err := compiled.Execute(out, data); err != nil { + return err + } + return nil +} + +// check if the tunables/global exist +func tuntablesExists() bool { + _, err := os.Stat("/etc/apparmor.d/tunables/global") + return err == nil +} + +// check if abstractions/base exist +func abstrctionsEsists() bool { + _, err := os.Stat("/etc/apparmor.d/abstractions/base") + return err == nil +} diff --git a/apparmor/setup.go b/apparmor/setup.go index 3494762..2401f63 100644 --- a/apparmor/setup.go +++ b/apparmor/setup.go @@ -3,7 +3,6 @@ package apparmor import ( "fmt" "io" - "io/ioutil" "os" "os/exec" "path" @@ -13,47 +12,6 @@ const ( DefaultProfilePath = "/etc/apparmor.d/docker" ) -const DefaultProfile = ` -#include -profile docker-default flags=(attach_disconnected,mediate_deleted) { - #include - network, - capability, - file, - umount, - - mount fstype=tmpfs, - mount fstype=mqueue, - mount fstype=fuse.*, - mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/, - mount fstype=efivarfs -> /sys/firmware/efi/efivars/, - mount fstype=fusectl -> /sys/fs/fuse/connections/, - mount fstype=securityfs -> /sys/kernel/security/, - mount fstype=debugfs -> /sys/kernel/debug/, - mount fstype=proc -> /proc/, - mount fstype=sysfs -> /sys/, - - deny @{PROC}/sys/fs/** wklx, - deny @{PROC}/sysrq-trigger rwklx, - deny @{PROC}/mem rwklx, - deny @{PROC}/kmem rwklx, - deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx, - deny @{PROC}/sys/kernel/*/** wklx, - - deny mount options=(ro, remount) -> /, - deny mount fstype=debugfs -> /var/lib/ureadahead/debugfs/, - deny mount fstype=devpts, - - deny /sys/[^f]*/** wklx, - deny /sys/f[^s]*/** wklx, - deny /sys/fs/[^c]*/** wklx, - deny /sys/fs/c[^g]*/** wklx, - deny /sys/fs/cg[^r]*/** wklx, - deny /sys/firmware/efi/efivars/** rwklx, - deny /sys/kernel/security/** rwklx, -} -` - func InstallDefaultProfile(backupPath string) error { if !IsEnabled() { return nil @@ -95,15 +53,26 @@ func InstallDefaultProfile(backupPath string) error { return err } - if err := ioutil.WriteFile(DefaultProfilePath, []byte(DefaultProfile), 0644); err != nil { + f, err := os.OpenFile(DefaultProfilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { return err } + if err := generateProfile(f); err != nil { + f.Close() + return err + } + f.Close() - output, err := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker").CombinedOutput() + cmd := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker") + // to use the parser directly we have to make sure we are in the correct + // dir with the profile + cmd.Dir = "/etc/apparmor.d" + + output, err := cmd.CombinedOutput() if err != nil && !os.IsNotExist(err) { if e, ok := err.(*exec.Error); ok { - // keeping with the current profile load code, if the parser does not exist then - // just return + // keeping with the current profile load code, if the parser does not + // exist then just return if e.Err == exec.ErrNotFound || os.IsNotExist(e.Err) { return nil }