From b03f9618cc3ee7a77f1e1b614f2d4d29052a2111 Mon Sep 17 00:00:00 2001 From: Tim McCormack Date: Wed, 5 Mar 2025 14:56:07 +0000 Subject: [PATCH 1/2] refactor: Copy codejail-service apparmor profile from devstack This is a straight copy from the version in development at https://github.com/edx/devstack/blob/9a2067bab6ebdd1bc9f4179aee603b1e4251b01c/codejail.profile The next commit will make it appropriate for use in additional environments. --- apparmor/openedx_codejail_service.profile | 113 ++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 apparmor/openedx_codejail_service.profile diff --git a/apparmor/openedx_codejail_service.profile b/apparmor/openedx_codejail_service.profile new file mode 100644 index 0000000..e3f403e --- /dev/null +++ b/apparmor/openedx_codejail_service.profile @@ -0,0 +1,113 @@ +# AppArmor profile for running codejail-service in devstack. +# +# #=========# +# # WARNING # +# #=========# +# +# This is not a complete and secure apparmor profile! Do not use this +# in any deployed environment (even a staging environment) without +# careful inspection and modification to fit your needs. +# +# See https://manpages.ubuntu.com/manpages/noble/man5/apparmor.d.5.html +# or `man apparmor.d` for documentation of syntax and options. +# +# Failure to apply a secure apparmor profile *will* likely result in a +# compromise of your environment by an attacker. +# +# We may at some point make this file good enough for confinement in +# production, but for now it is only intended to be used in devstack. + + + +# Sets standard variables used by abstractions/base, later. Controlled +# by OS, see /etc/apparmor.d/tunables/global for contents. +include + +# Require that the system understands the feature set that this policy was written +# for. If we didn't include this, then on Ubuntu >= 22.04, AppArmor might assume +# the wrong feature set was requested, and some rules might become too permissive. +# See https://github.com/netblue30/firejail/issues/3659#issuecomment-711074899 +abi , + +# This outer profile applies to the entire container, and isn't as +# important as the inner (codejail_sandbox) profile. If the inner profile doesn't work, it's not likely that +# the outer one is going to help. But there may be some small value in +# defense-in-depth, as it's possible that a bug in the codejail_sandbox (inner) +# profile isn't present in the outer one. +profile openedx_codejail_service flags=(mediate_deleted) { + + # Allow access to a variety of commonly needed, generally safe things + # (such as reading /dev/random, free memory, etc.) + # + # Manpage: "Includes files that should be readable and writable in all profiles." + include + + # Filesystem access -- self-explanatory + file, + + # netlink is needed for sudo's interprocess communication + network netlink raw, + + # Allow all of the various network operations required to listen, accept connection, etc. + network tcp, + # But then deny making a new *outbound* connection. + deny network (connect) tcp, + + # Required for sudoing to sandbox + capability setuid setgid audit_write, + # Allow sending a kill signal + capability kill, + + # Allow sending a kill signal to the codejail_sandbox subprofile when the execution + # runs beyond time limits. + signal (send) set=(kill) peer=openedx_codejail_service//codejail_sandbox, + + # The core of the confinement: When the sandbox Python is executed, switch to + # the (extremely constrained) codejail_sandbox profile. + # + # This path needs to be coordinated with the Dockerfile and Django settings. + # + # Manpage: "Cx: transition to subprofile on execute -- scrub the environment" + /sandbox/venv/bin/python Cx -> codejail_sandbox, + + # This is the important apparmor profile -- the one that actually + # constrains the sandbox Python process. + # + # mediate_deleted is not well documented, but it seems to indicate that + # apparmor will continue to make policy decisions in cases where a confined + # executable has a handle to a file's inode even after the file is removed + # from the filesystem. + profile codejail_sandbox flags=(mediate_deleted) { + + # This inner profile also gets general access to "safe" + # actions; we could list those explicitly out of caution but + # it could get pretty verbose. + include + + # Read and run binaries and libraries in the virtualenv. This + # includes the sandbox's copy of Python as well as any + # dependencies that have been installed for inclusion in + # sandboxes. + # + # m: executable mapping, required for shared libraries used by some + # Python dependencies with C compontents, eg `nltk`. + /sandbox/venv/** rm, + + # Allow access to the temporary directories that are set up by + # codejail, one for each code-exec call. Each /tmp/code-XXXXX + # contains one execution. + # + # Codejail has a hardcoded reference to this file path, although the + # use of /tmp specifically may be controllable with environment variables: + # https://github.com/openedx/codejail/blob/0165d9ca351/codejail/util.py#L15 + /tmp/codejail-*/ r, + /tmp/codejail-*/** rw, + + # Allow interactive terminal in devstack. + /dev/pts/* rw, + + # Allow receiving a kill signal from the webapp when the execution + # runs beyond time limits. + signal (receive) set=(kill) peer=openedx_codejail_service, + } +} From 28c385e1a4a296880bd4eb20ba92ee8d2750048a Mon Sep 17 00:00:00 2001 From: Tim McCormack Date: Wed, 5 Mar 2025 18:41:15 +0000 Subject: [PATCH 2/2] feat: Adjust codejail-service apparmor profile for general use; add docs Only functional change is to remove facility for terminal interaction from inner profile; this turned out to not be very important for iterative development. It was the only remaining dev-related aspect of the profile, so now the big scary warning can be removed from the top (and replaced by a different one). This is preparatory for deploying to stage. Once we have a deployment process, the docs here can be updated. --- apparmor/README.rst | 13 +++++++++++++ apparmor/openedx_codejail_service.profile | 21 ++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 apparmor/README.rst diff --git a/apparmor/README.rst b/apparmor/README.rst new file mode 100644 index 0000000..ca0b898 --- /dev/null +++ b/apparmor/README.rst @@ -0,0 +1,13 @@ +AppArmor profiles +################# + +If a service's Docker image is to be deployed with an AppArmor profile, the profile can be stored here. + +Caveats: + +* We don't have an automated deployment mechanism for AppArmor profiles, and in particular we don't have a way to coordinate image updates and profile updates. Use an expand/contract pattern when coordinating changes between a Dockerfile and an AppArmor profile, and double-check that changes have been applied on one side before proceeding with the other. +* The name of the profile, as defined in the text of the file, is the part that AppArmor cares about. The filename is irrelevant. We should probably keep the two in sync, though. + + * Bear in mind that changing a profile name is an annoying and manual process, so think carefully when picking a name. Prefixing with ``openedx_`` may help operators. + +See ``__ or ``man apparmor.d`` for documentation of syntax and options. diff --git a/apparmor/openedx_codejail_service.profile b/apparmor/openedx_codejail_service.profile index e3f403e..3553cc4 100644 --- a/apparmor/openedx_codejail_service.profile +++ b/apparmor/openedx_codejail_service.profile @@ -1,21 +1,15 @@ -# AppArmor profile for running codejail-service in devstack. +# AppArmor profile for running codejail-service. +# +# Changes to this profile must be coordinated carefully with changes to the +# Dockerfile. See README for additional cautions. # # #=========# # # WARNING # # #=========# # -# This is not a complete and secure apparmor profile! Do not use this -# in any deployed environment (even a staging environment) without -# careful inspection and modification to fit your needs. -# -# See https://manpages.ubuntu.com/manpages/noble/man5/apparmor.d.5.html -# or `man apparmor.d` for documentation of syntax and options. -# # Failure to apply a secure apparmor profile *will* likely result in a -# compromise of your environment by an attacker. -# -# We may at some point make this file good enough for confinement in -# production, but for now it is only intended to be used in devstack. +# full compromise of the host by an attacker. AppArmor is *mandatory* +# for using codejail -- this is not just for hardening. @@ -103,9 +97,6 @@ profile openedx_codejail_service flags=(mediate_deleted) { /tmp/codejail-*/ r, /tmp/codejail-*/** rw, - # Allow interactive terminal in devstack. - /dev/pts/* rw, - # Allow receiving a kill signal from the webapp when the execution # runs beyond time limits. signal (receive) set=(kill) peer=openedx_codejail_service,