mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #29130 from cyphar/29097-dynamically-reload-apparmor
daemon: switch to 'ensure' workflow for AppArmor profiles
This commit is contained in:
commit
96a84ed85a
5 changed files with 51 additions and 20 deletions
|
@ -3,7 +3,8 @@
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Sirupsen/logrus"
|
"fmt"
|
||||||
|
|
||||||
aaprofile "github.com/docker/docker/profiles/apparmor"
|
aaprofile "github.com/docker/docker/profiles/apparmor"
|
||||||
"github.com/opencontainers/runc/libcontainer/apparmor"
|
"github.com/opencontainers/runc/libcontainer/apparmor"
|
||||||
)
|
)
|
||||||
|
@ -13,18 +14,23 @@ const (
|
||||||
defaultApparmorProfile = "docker-default"
|
defaultApparmorProfile = "docker-default"
|
||||||
)
|
)
|
||||||
|
|
||||||
func installDefaultAppArmorProfile() {
|
func ensureDefaultAppArmorProfile() error {
|
||||||
if apparmor.IsEnabled() {
|
if apparmor.IsEnabled() {
|
||||||
if err := aaprofile.InstallDefault(defaultApparmorProfile); err != nil {
|
loaded, err := aaprofile.IsLoaded(defaultApparmorProfile)
|
||||||
apparmorProfiles := []string{defaultApparmorProfile}
|
if err != nil {
|
||||||
|
return fmt.Errorf("Could not check if %s AppArmor profile was loaded: %s", defaultApparmorProfile, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Allow daemon to run if loading failed, but are active
|
// Nothing to do.
|
||||||
// (possibly through another run, manually, or via system startup)
|
if loaded {
|
||||||
for _, policy := range apparmorProfiles {
|
return nil
|
||||||
if err := aaprofile.IsLoaded(policy); err != nil {
|
}
|
||||||
logrus.Errorf("AppArmor enabled on system but the %s profile could not be loaded.", policy)
|
|
||||||
}
|
// Load the profile.
|
||||||
}
|
if err := aaprofile.InstallDefault(defaultApparmorProfile); err != nil {
|
||||||
|
return fmt.Errorf("AppArmor enabled on system but the %s profile could not be loaded.", defaultApparmorProfile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
|
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
func installDefaultAppArmorProfile() {
|
func ensureDefaultAppArmorProfile() error {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -524,7 +524,10 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
|
||||||
logrus.Warnf("Failed to configure golang's threads limit: %v", err)
|
logrus.Warnf("Failed to configure golang's threads limit: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
installDefaultAppArmorProfile()
|
if err := ensureDefaultAppArmorProfile(); err != nil {
|
||||||
|
logrus.Errorf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
daemonRepo := filepath.Join(config.Root, "containers")
|
daemonRepo := filepath.Join(config.Root, "containers")
|
||||||
if err := idtools.MkdirAllAs(daemonRepo, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
|
if err := idtools.MkdirAllAs(daemonRepo, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -733,12 +733,27 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if apparmor.IsEnabled() {
|
if apparmor.IsEnabled() {
|
||||||
appArmorProfile := "docker-default"
|
var appArmorProfile string
|
||||||
if len(c.AppArmorProfile) > 0 {
|
if c.AppArmorProfile != "" {
|
||||||
appArmorProfile = c.AppArmorProfile
|
appArmorProfile = c.AppArmorProfile
|
||||||
} else if c.HostConfig.Privileged {
|
} else if c.HostConfig.Privileged {
|
||||||
appArmorProfile = "unconfined"
|
appArmorProfile = "unconfined"
|
||||||
|
} else {
|
||||||
|
appArmorProfile = "docker-default"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if appArmorProfile == "docker-default" {
|
||||||
|
// Unattended upgrades and other fun services can unload AppArmor
|
||||||
|
// profiles inadvertently. Since we cannot store our profile in
|
||||||
|
// /etc/apparmor.d, nor can we practically add other ways of
|
||||||
|
// telling the system to keep our profile loaded, in order to make
|
||||||
|
// sure that we keep the default profile enabled we dynamically
|
||||||
|
// reload it if necessary.
|
||||||
|
if err := ensureDefaultAppArmorProfile(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.Process.ApparmorProfile = appArmorProfile
|
s.Process.ApparmorProfile = appArmorProfile
|
||||||
}
|
}
|
||||||
s.Process.SelinuxLabel = c.GetProcessLabel()
|
s.Process.SelinuxLabel = c.GetProcessLabel()
|
||||||
|
|
|
@ -94,22 +94,28 @@ func InstallDefault(name string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsLoaded checks if a passed profile has been loaded into the kernel.
|
// IsLoaded checks if a profile with the given name has been loaded into the
|
||||||
func IsLoaded(name string) error {
|
// kernel.
|
||||||
|
func IsLoaded(name string) (bool, error) {
|
||||||
file, err := os.Open("/sys/kernel/security/apparmor/profiles")
|
file, err := os.Open("/sys/kernel/security/apparmor/profiles")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
r := bufio.NewReader(file)
|
r := bufio.NewReader(file)
|
||||||
for {
|
for {
|
||||||
p, err := r.ReadString('\n')
|
p, err := r.ReadString('\n')
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(p, name+" ") {
|
if strings.HasPrefix(p, name+" ") {
|
||||||
return nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue