Allow rootless containers to use AppArmor profiles
Previously, Podman would print an error if you tried to run a container
with an AppArmor profile as a non-root user, e.g.
$ podman run --security-opt apparmor=my-profile ...
Error: Apparmor profile "my-profile" specified, but Apparmor is not
enabled on this system
In fact, the only thing that Podman needs root privileges for is reading
/sys/kernel/security/apparmor/profiles to see if the profile is already
loaded, which isn't strictly necessary.
This commit removes the 'IsLoaded()' check that occurs when you try to
specify an AppArmor profile as a non-root user, as well as the other
checks in pkg/apparmor/ for whether the program is running as UID 0. The
check for whether the AppArmor profile is loaded should now be deferred
to the container runtime at the point where it writes to either
/proc/self/attr/exec or /proc/self/attr/apparmor/exec, since the write
should fail if the profile is not loaded.
Closes #958.
Signed-off-by: kernelmethod <17100608+kernelmethod@users.noreply.github.com>
This commit is contained in:
parent
5863f624be
commit
6994271ca4
|
|
@ -17,6 +17,4 @@ const (
|
|||
var (
|
||||
// ErrApparmorUnsupported indicates that AppArmor support is not supported.
|
||||
ErrApparmorUnsupported = errors.New("AppArmor is not supported")
|
||||
// ErrApparmorRootless indicates that AppArmor support is not supported in rootless mode.
|
||||
ErrApparmorRootless = errors.New("AppArmor is not supported in rootless mode")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import (
|
|||
"text/template"
|
||||
|
||||
"github.com/containers/common/pkg/apparmor/internal/supported"
|
||||
"github.com/containers/storage/pkg/unshare"
|
||||
runcaa "github.com/opencontainers/runc/libcontainer/apparmor"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
|
@ -77,10 +76,6 @@ func macroExists(m string) bool {
|
|||
// InstallDefault generates a default profile and loads it into the kernel
|
||||
// using 'apparmor_parser'.
|
||||
func InstallDefault(name string) error {
|
||||
if unshare.IsRootless() {
|
||||
return ErrApparmorRootless
|
||||
}
|
||||
|
||||
p := profileData{
|
||||
Name: name,
|
||||
}
|
||||
|
|
@ -137,12 +132,9 @@ func DefaultContent(name string) ([]byte, error) {
|
|||
}
|
||||
|
||||
// IsLoaded checks if a profile with the given name has been loaded into the
|
||||
// kernel.
|
||||
// kernel. This function checks for the existence of a profile by reading
|
||||
// /sys/kernel/security/apparmor/profiles, and hence requires root permissions.
|
||||
func IsLoaded(name string) (bool, error) {
|
||||
if name != "" && unshare.IsRootless() {
|
||||
return false, errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name)
|
||||
}
|
||||
|
||||
file, err := os.Open("/sys/kernel/security/apparmor/profiles")
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
|
|
@ -238,25 +230,13 @@ func parseAAParserVersion(output string) (int, error) {
|
|||
// CheckProfileAndLoadDefault checks if the specified profile is loaded and
|
||||
// loads the DefaultLibpodProfile if the specified on is prefixed by
|
||||
// DefaultLipodProfilePrefix. This allows to always load and apply the latest
|
||||
// default AppArmor profile. Note that AppArmor requires root. If it's a
|
||||
// default profile, return DefaultLipodProfilePrefix, otherwise the specified
|
||||
// one.
|
||||
// default AppArmor profile. If it's a default profile, return
|
||||
// DefaultLipodProfilePrefix, otherwise the specified one.
|
||||
func CheckProfileAndLoadDefault(name string) (string, error) {
|
||||
if name == "unconfined" {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// AppArmor is not supported in rootless mode as it requires root
|
||||
// privileges. Return an error in case a specific profile is specified.
|
||||
if unshare.IsRootless() {
|
||||
if name != "" {
|
||||
return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name)
|
||||
} else {
|
||||
logrus.Debug("Skipping loading default AppArmor profile (rootless mode)")
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
// Check if AppArmor is disabled and error out if a profile is to be set.
|
||||
if !runcaa.IsEnabled() {
|
||||
if name == "" {
|
||||
|
|
@ -271,13 +251,6 @@ func CheckProfileAndLoadDefault(name string) (string, error) {
|
|||
} else if !strings.HasPrefix(name, ProfilePrefix) {
|
||||
// If the specified name is not a default one, ignore it and return the
|
||||
// name.
|
||||
isLoaded, err := IsLoaded(name)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "verify if profile %s is loaded", name)
|
||||
}
|
||||
if !isLoaded {
|
||||
return "", errors.Errorf("AppArmor profile %q specified but not loaded", name)
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,9 +40,6 @@ func NewAppArmorVerifier() *ApparmorVerifier {
|
|||
// - AppArmor is disabled by the host system
|
||||
// - the `apparmor_parser` binary is not discoverable
|
||||
func (a *ApparmorVerifier) IsSupported() error {
|
||||
if a.impl.UnshareIsRootless() {
|
||||
return errors.New("AppAmor is not supported on rootless containers")
|
||||
}
|
||||
if !a.impl.RuncIsEnabled() {
|
||||
return errors.New("AppArmor not supported by the host system")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue