-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Kunal Kushwaha <[email protected]>
- Loading branch information
1 parent
3b3da0f
commit 5ea2f71
Showing
15 changed files
with
3,632 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package apparmor | ||
|
||
import ( | ||
"io" | ||
"os" | ||
"path" | ||
) | ||
|
||
const ( | ||
// defaultProfileDirectory is the apparmor default profile's directory | ||
defaultProfileDirectory = "/etc/apparmor.d" | ||
) | ||
|
||
var ( | ||
// profileDirectory is the file store for apparmor profiles and macros. | ||
profileDirectory = defaultProfileDirectory | ||
) | ||
|
||
type networkRawSetup struct { | ||
Denied bool | ||
} | ||
|
||
/* | ||
NetworkSetup contains flags and data to configure network rules in AppArmor. | ||
See http://manpages.ubuntu.com/manpages/precise/man5/apparmor.d.5.html | ||
for more information regarding supported protocols, network data types | ||
and domains. | ||
*/ | ||
type NetworkSetup struct { | ||
Denied bool | ||
AllowedProtocols []string | ||
Raw networkRawSetup | ||
} | ||
|
||
/* | ||
CapabilitiesSetup contains flags and data to configure capability rules in AppArmor. | ||
See http://manpages.ubuntu.com/manpages/precise/man5/apparmor.d.5.html | ||
for more information regarding supported capabilities. | ||
*/ | ||
type CapabilitiesSetup struct { | ||
Allowed []string | ||
Denied []string | ||
} | ||
|
||
// FilesSetup contains data to configure filesystem access rules in AppArmor. | ||
type FilesSetup struct { | ||
// Denied is a list of filepaths to deny any access to | ||
Denied []string | ||
// ReadOnly is a list of filepaths to restrict to read access only | ||
ReadOnly []string | ||
// NoExec is a list of filepaths for which execution is denied | ||
NoExec []string | ||
} | ||
|
||
// ProfileData holds information about the given profile for generation. | ||
type ProfileData struct { | ||
// Name is profile name. | ||
Name string | ||
// Imports defines the apparmor functions to import, before defining the profile. | ||
Imports []string | ||
// InnerImports defines the apparmor functions to import in the profile. | ||
InnerImports []string | ||
// Version is the {major, minor, patch} version of apparmor_parser as a single number. | ||
Version int | ||
|
||
// Network defines the network setup we want, see NetworkSetup type definition | ||
Network NetworkSetup | ||
|
||
// Capabilities defines the capabilities setup we want, see CapabiltitiesSetup type definition | ||
Capabilities CapabilitiesSetup | ||
|
||
// Files defines the files access setup we want, see FilesSetup type definition | ||
Files FilesSetup | ||
} | ||
|
||
// NewEmptyProfileData creates an empty ProfileData object with its name. | ||
func NewEmptyProfileData(name string) *ProfileData { | ||
return &ProfileData{Name: name} | ||
} | ||
|
||
// macrosExists checks if the passed macro exists. | ||
func macroExists(m string) bool { | ||
_, err := os.Stat(path.Join(profileDirectory, m)) | ||
return err == nil | ||
} | ||
|
||
// SetAppArmorProfileDirectory sets AppArmor's profile directory | ||
func SetAppArmorProfileDirectory(path string) { | ||
profileDirectory = path | ||
} | ||
|
||
// GenerateAppArmorProfile creates an AppArmor profile and writes it to the io.Writer argument | ||
func GenerateAppArmorProfile(p ProfileData, out io.Writer) error { | ||
aaProfile, err := NewParse("apparmor_profile", baseCustomTemplate) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if macroExists("tunables/global") { | ||
p.Imports = append(p.Imports, "#include <tunables/global>") | ||
} else { | ||
p.Imports = append(p.Imports, "@{PROC}=/proc/") | ||
} | ||
|
||
if macroExists("abstractions/base") { | ||
p.InnerImports = append(p.InnerImports, "#include <abstractions/base>") | ||
} | ||
|
||
// FIXME: add `aaparser` pkg | ||
/* | ||
ver, err := aaparser.GetVersion() | ||
if err != nil { | ||
return err | ||
} | ||
*/ | ||
|
||
return aaProfile.Execute(out, p) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package apparmor | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"strings" | ||
"text/template" | ||
) | ||
|
||
/* See profile language http://wiki.apparmor.net/index.php/QuickProfileLanguage | ||
* This profile is the base template of Moby, customized to allow entitlements to configure | ||
* network, capabilities and file accesses | ||
*/ | ||
const baseCustomTemplate = ` | ||
{{range $value := .Imports}} | ||
{{$value}} | ||
{{end}} | ||
profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { | ||
{{range $value := .InnerImports}} | ||
{{$value}} | ||
{{end}} | ||
{{if .Network.Denied}} | ||
deny network, | ||
{{else}} | ||
{{if .Network.AllowedProtocols}} | ||
{{range $value := .Network.AllowedProtocols}} network inet {{$value}}, | ||
{{end}} | ||
{{else}} | ||
network, | ||
{{end}} | ||
{{if .Network.Raw.Denied}} | ||
deny network raw, | ||
{{end}} | ||
{{end}} | ||
{{range $value := .Capabilities.Allowed}} capabilty {{$value}}, | ||
{{end}} | ||
{{range $value := .Capabilities.Denied}} deny capability {{$value}}, | ||
{{end}} | ||
{{range $value := .Files.Denied}} deny {{$value}} rwamklx, | ||
{{end}} | ||
{{range $value := .Files.ReadOnly}} deny {{$value}} wkal, | ||
{{end}} | ||
{{range $value := .Files.NoExec}} deny {{$value}} x, | ||
{{end}} | ||
file, | ||
umount, | ||
deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir) | ||
# deny write to files not in /proc/<number>/** or /proc/sys/** | ||
deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w, | ||
deny @{PROC}/sys/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel) | ||
deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/ | ||
deny @{PROC}/sysrq-trigger rwklx, | ||
deny @{PROC}/mem rwklx, | ||
deny @{PROC}/kmem rwklx, | ||
deny @{PROC}/kcore rwklx, | ||
deny mount, | ||
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/** rwklx, | ||
deny /sys/kernel/security/** rwklx, | ||
{{if ge .Version 208095}} | ||
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container | ||
ptrace (trace,read) peer={{.Name}}, | ||
{{end}} | ||
} | ||
` | ||
|
||
// basicFunctions are the set of initial | ||
// functions provided to every template. | ||
var basicFunctions = template.FuncMap{ | ||
"json": func(v interface{}) string { | ||
buf := &bytes.Buffer{} | ||
enc := json.NewEncoder(buf) | ||
enc.SetEscapeHTML(false) | ||
enc.Encode(v) | ||
// Remove the trailing new line added by the encoder | ||
return strings.TrimSpace(buf.String()) | ||
}, | ||
"split": strings.Split, | ||
"join": strings.Join, | ||
"title": strings.Title, | ||
"lower": strings.ToLower, | ||
"upper": strings.ToUpper, | ||
"pad": padWithSpace, | ||
"truncate": truncateWithLength, | ||
} | ||
|
||
// HeaderFunctions are used to created headers of a table. | ||
// This is a replacement of basicFunctions for header generation | ||
// because we want the header to remain intact. | ||
// Some functions like `split` are irrelevant so not added. | ||
var HeaderFunctions = template.FuncMap{ | ||
"json": func(v string) string { | ||
return v | ||
}, | ||
"title": func(v string) string { | ||
return v | ||
}, | ||
"lower": func(v string) string { | ||
return v | ||
}, | ||
"upper": func(v string) string { | ||
return v | ||
}, | ||
"truncate": func(v string, l int) string { | ||
return v | ||
}, | ||
} | ||
|
||
// Parse creates a new anonymous template with the basic functions | ||
// and parses the given format. | ||
func Parse(format string) (*template.Template, error) { | ||
return NewParse("", format) | ||
} | ||
|
||
// NewParse creates a new tagged template with the basic functions | ||
// and parses the given format. | ||
func NewParse(tag, format string) (*template.Template, error) { | ||
return template.New(tag).Funcs(basicFunctions).Parse(format) | ||
} | ||
|
||
// padWithSpace adds whitespace to the input if the input is non-empty | ||
func padWithSpace(source string, prefix, suffix int) string { | ||
if source == "" { | ||
return source | ||
} | ||
return strings.Repeat(" ", prefix) + source + strings.Repeat(" ", suffix) | ||
} | ||
|
||
// truncateWithLength truncates the source string up to the length provided by the input | ||
func truncateWithLength(source string, length int) string { | ||
if len(source) < length { | ||
return source | ||
} | ||
return source[:length] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package entitlements | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/moby/buildkit/util/entitlements/osdefs" | ||
"github.com/moby/buildkit/util/entitlements/testutils" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestProfileSecurityConfined(t *testing.T) { | ||
testSyscall := osdefs.SysExit | ||
ociProfile := NewOCIProfile(testutils.TestSpec(), "test-profile") | ||
|
||
require.NotNil(t, ociProfile.OCI) | ||
require.NotNil(t, ociProfile.OCI.Linux) | ||
require.NotNil(t, ociProfile.OCI.Linux.Seccomp) | ||
|
||
syscalls := []osdefs.Syscall{testSyscall} | ||
ociProfile.AllowSyscalls(syscalls...) | ||
|
||
seccompProfileWithTestSys := *ociProfile.OCI.Linux.Seccomp | ||
|
||
ociProfile.AllowSyscalls(syscalls...) | ||
didAdd := reflect.DeepEqual(seccompProfileWithTestSys, *ociProfile.OCI.Linux.Seccomp) | ||
require.True(t, didAdd, "Syscall was not already added to the seccomp profile") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.