Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow rootless containers to use AppArmor profiles #960

Merged

Conversation

kernelmethod
Copy link
Contributor

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.

@kernelmethod
Copy link
Contributor Author

Built with these changes to common, Podman is able to use a custom AppArmor profile when you run a rootless container:

$ kernelmethod@debdev:~/podman/podman$ podman run -t --security-opt apparmor=my-profile alpine:3.15 ls /tmp
ls: can't open '/tmp': Permission denied

The check for whether the profile exists gets deferred to the container runtime when it tries to write to /proc/self/attr{,/apparmor}/exec. This is probably how things should be, since there isn't (to my knowledge) a way to check the existence of an AppArmor profile as a non-root user that doesn't involve writing to procfs.

The downside of all this is that you get a somewhat opaque error if you try to run a container with a nonexistent profile:

$ podman run -t --security-opt apparmor=foobarbaz alpine:3.15 ls /tmp
Error: runc: runc create failed: unable to start container process: error during container init: unable to apply apparmor profile: apparmor failed to apply profile: write /proc/self/attr/apparmor/exec: no such file or directory: OCI runtime attempted to invoke a command that was not found

But that's an issue for runc, and to be fair, the old error was even less helpful:

$ podman run -t --security-opt apparmor=my-profile alpine:3.15 ls /tmp
Error: Apparmor profile "my-profile" specified, but Apparmor is not enabled on this system

(Which is inaccurate since AppArmor is in fact enabled on my system.)

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 containers#958.

Signed-off-by: kernelmethod <[email protected]>
@rhatdan
Copy link
Member

rhatdan commented Mar 15, 2022

LGTM
@saschagrunert @vrothberg PTAL

Copy link
Member

@saschagrunert saschagrunert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@vrothberg vrothberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!
@giuseppe, can you give a final head nod?

Copy link
Member

@giuseppe giuseppe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Mar 16, 2022

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: giuseppe, kernelmethod, saschagrunert

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@giuseppe
Copy link
Member

/lgtm

@rhatdan
Copy link
Member

rhatdan commented Jun 6, 2023

Could we revisit this? I can not see what was blowing up in Podman CI/CD system any longer. Could it just have been an ancient version of ubuntu that was blowing up?

@kernelmethod
Copy link
Contributor Author

Could we revisit this? I can not see what was blowing up in Podman CI/CD system any longer. Could it just have been an ancient version of ubuntu that was blowing up?

From what I remember (and from #969 (comment)), the issue was that Podman opens /sys/kernel/security/apparmor/profiles to check whether the default Podman AppArmor profile has already been loaded into the kernel (which requires root privileges). If that check fails, then Podman generates the profile and loads it with apparmor_parser.

The changes in this PR modified the apparmor.IsEnabled() so that it doesn't automatically generate an error if run as a non-root user. That it turn caused Podman to proceed to the check on /sys/kernel/security/apparmor/profiles in its rootless tests, which failed in the CI/CD pipeline.

@rhatdan
Copy link
Member

rhatdan commented Jun 6, 2023

Can we fix this Patch to not do that or add a new API to check if the apparmor is loaded?

@kernelmethod
Copy link
Contributor Author

Can we fix this Patch to not do that...

Well, I suppose. I think the way to do that would be to only attempt to load the default profile into the kernel if we're running with uid 0, and just skip the check and loading altogether otherwise. For that to work without breaking Podman on AppArmor-enabled kernels we'd need to make the default profile unconfined for all non-root users. IMO though it'd be better to solve containers/podman#15874 first by storing the default profile in /etc/apparmor.d/, and then we can skip the whole profile checking and loading process to begin with.

... or add a new API to check if the apparmor is loaded?

The only way to rootlessly check for the existence of a profile is to attempt a profile transition by writing to /proc/$pid/attr/apparmor/{current,exec}. It's a little ham-handed but we could fork, have the child attempt a profile transition, and use the result to determine whether the profile has been loaded. Really, though, the standard way to do this would be to skip the check altogether and just pass along the profile to the container runtime to fail when it attempts to perform a profile transition.

@rhatdan
Copy link
Member

rhatdan commented Jun 7, 2023

Well I am certainly not an expert in this, being the SELinux guy, and most of the core engineers know little of apparmor, so we need community to take the lead. If you could make this work it would be great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow rootless containers to use AppArmor profiles
6 participants