CodeJail是对于不可信代码的管理系统,主要针对Python的运行,也同样适用于其他编程语言。CodeJail的运行依赖AppArmor,在没有前置安装AppArmor的时候,CodeJail将无法被执行。
CodeJail安装
CodeJail可以从Github上直接获取到,浏览器访问地址https://github.com/edx/codejail或是使用SVN/git从https://github.com/edx/codejail.git直接获取。在获取到CodeJail之后通过python
setup.py进行安装。以一台干净的Ubuntu16.04系统为原料,开始安装的步骤
CodeJail的安装包使用Python2进行安装,安装依赖python-setuptools,所以定位至CodeJail源码文件夹之后使用
sudo apt-get install python-setuptools
sudo python2 setup.py install
操作成功完成CodeJail。安装
CodeJail部署
参数定义:
$SANDBOX_CALLER$:在项目中调用代码的用户。有别于sandbox,作为沙箱内部的代码运行权限用户。
$SANDENV$ :代码所运行的虚拟环境目录位置,需要有被sandbox的访问权限。
部署步骤:
1.为沙箱添加用户和用户组
sudo addgroup sandbox
sudo adduser --disabled-login sandbox --ingroup sandbox
2.创建虚拟环境
创建虚拟环境需要使用virtualenv进行,使用
sudo pip install virtualenv
完成virtualenv安装,使用
sudo virtualenv $SANDENV$
完成虚拟环境部署。
3.安装虚拟环境所用的Python第三方包
下面通过
source $SANDENV$/bin/activate
进入虚拟环境,根据需要,添加第三方Python包
pip install -r sandbox-requirements.txt
4.配置项目服务以沙箱的方式运行
创建配置文件/etc/sudoers.d/01-sandbox
sudo visudo -f /etc/sudoers.d/01-sandbox
并在文件中写入:
$SANDBOX_CALLER$ ALL=(sandbox) SETENV:NOPASSWD:$SANDENV$/bin/python
$SANDBOX_CALLER$ ALL=(sandbox) SETENV:NOPASSWD:/usr/bin/find
$SANDBOX_CALLER$ ALL=(ALL) NOPASSWD:/usr/bin/pkill
5.配置AppArmor配置文件。
创建配置文件的文件名参照被配置应用的路径的,如如下位置的文件
/home/administrator/sandbox/bin/python
其权限配置文件名为
home.administrator.sandbox.bin.python
记配置文件名为$APPARMOR_FILE$
所以使用以下代码配置文件:
sudo vi /etc/apparmor.d/$APPARMOR_FILE$
加入下述配置:
#include
$SANDENV$/bin/python {
#include
#include
$SANDENV$/** mr,
#If you have code that the sandbox must be able to access, add lines
#pointing to those directories:
/the/path/to/your/sandbox-packages/** r,
/tmp/codejail-*/ rix,
/tmp/codejail-*/** wrix,
}
6.解析配置文件
运行
sudo apparmor_parser /etc/apparmor.d/$APPARMOR_FILE$
重启服务以使其生效
sudo service apparmor restart
7.重启项目服务
CodeJail使用
Codejail可以通过codejail.Jail.safe_exec()和codejail.Jail.jail_code()的方式运行Python代码,其使用方式如下。
import codejail#导入codejail模块
#配置codejail的环境信息
jail = codejail.configure('python','/home/administrator/sandbox/bin/python')
#运行Python代码
jail.safe_exec($str: python code$,$dict:outer variables$})
其中codejail.Jail.jail_code()会使用AppArmor管理的子线程运行Python代码。这个方法可以接收处理程序运行,复制进入当前环境的文件,命令行参数和标准输入流。之后,通过创建临时文件夹,创建或者复制所需文件,启动一个子线程运行代码,最终返回输出和运行状态。以下是codejail.Jail.jail_code()的运行时序图。
codejail.Jail.safe_exec()提供专门的处理方式器以执行Python代码,它模拟Python的exec语句,可以处理大量的Python代码,并通过codejail.Jail.jail_code()进行运行。codejail.Jail.safe_exec()会将参数中的全局字典修改为一个函数副作用,并将其序列化,并以json的方式传入codejail.Jail.jail_code()运行的子线程中。以下是codejail.Jail.jail_code()的运行时序图。
代码维护
在CodeJail进行业务扩展变更的时候,需要对所使用的虚拟环境进行更改。由于虚拟环境受到了AppArmor的保护,所以需要先通过
sudo aa-complain /etc/apparmor.d/$APPARMOR_FILE$
关闭AppArmor的保护,等完成环境更新之后再通过
sudo aa-enforce /etc/apparmor.d/$APPARMOR_FILE$
恢复对虚拟环境的权限保护。
Python3运行环境支持
CodeJail目前只支持Python2的导入运行,在Python3上的导入运行存在问题。不过,这并不影响CodeJail沙箱执行Python3的代码。具体的流程如下。
1.安装Python3,setup-tools,pip
在Ubuntu上可以直接使用
sudo apt-get install python3 python3-setuptools python3-pip
完成Python3的安装
2.虚拟环境安装
一般产生虚拟环境按照CodeJail部署-部署步骤-2的流程即可,但是在多Python环境下想要在虚拟环境指定所需要的对应版本的Python,则需要用—python参数来调用指定所需版本的Python
virtualenv --python=python3 $SANDENV$
3.项目配置文件
在CodeJail部署-部署步骤-4在/etc/sudoers.d/01-sandbox添加以下字段
$SANDBOX_CALLER$ ALL=(sandbox)SETENV:NOPASSWD:$SANDENV$/bin/python3
在CodeJail部署-部署步骤-5配置对应的Python3文件配置
4.CodeJail运行
在对CodeJail进行配置的时候,使用如下所示的参数
jail = codejail.configure('python3', $SANDENV$/bin/python3',user='sandbox', lang=codejail.python3)
之后jail便可以使用Python3进行代码执行。
CodeJail的配置
在使用CodeJail的过程中出现了无法使用tempfile库的问题。之后再缩小范围,发现写入文件本身就无法正常进行,现象如下:
#正常打开一个文件
f = open("xxx","w")
#进行写入操作,正常运行,但是内容未被写入
f.write("abc")
#关闭文件时报错
f.close()
在后来在codejail包下的limits.py文件内找到了对虚拟环境下子线程的运行配置。该部分内容限制了代码运行时使用的硬件资源。
更改FSIZE大小更改,解决无法创建写入文件的问题。
同样,codejail有jail_code代码运行时间的限制。默认为1秒。更改REALTIME项修改。
codejail禁止了创建子进程的功能,进行下述更改
#该行禁止了子进程的创建
rlimits.append((resource.RLIMIT_NPROC, (0, 0)))
#将0改为恰当的数值,这里设置为7848
rlimits.append((resource.RLIMIT_NPROC, (7848, 7848)))
此外,如果有多线程内核的需要可以进行下述更改
#改行对cpu进行了限制
rlimits.append((resource.RLIMIT_CPU, (cpu,cpu+1)))
#将其改为下句可以不限制内核使用
rlimits.append((resource.RLIMIT_CPU, (-1,-1)))
原始代码详细参见如下内容:
codejail/limits.py at master · edx/codejail · GitHub
关于resource的其他配置可以参考:
36.13. resource — Resource usage information — Python 2.7.13 documentation
35.11. resource — Resource usage information — Python 3.6.2rc1 documentation