Furnace
A lightweight pure-python container implementation.
It is a wrapper around the Linux namespace functionality through libc functions like unshare(), nsenter() and mount(). You can think of it as a sturdier chroot replacement, where cleanup is easy (no lingering processes or leaked mountpoints). It needs superuser privileges to run.
Usage
Installation
You can either install it with pip:
pip3 install furnace
Or if you want, the following commands will install the bleeding-edge version of furnace to your system.
git clone https://github.com/balabit/furnace.git cd furnace python3 setup.py install
This will of course install it into a virtualenv, if you activate it beforehand.
Dependencies
The only dependencies are:
Python3.6+
Linux kernel 2.6.24+
A libc that implements setns() and nsenter() (that’s basically any libc released after 2007)
Example
After installing, the main interface to use is the ContainerContext class. It is, as the name suggests, a context manager, and after entering, its run() and Popen() methods can be used exactly like subprocess’s similarly named methods:
from furnace.context import ContainerContext
with ContainerContext('/opt/ChrootMcChrootface') as container:
container.run(['ps', 'aux'])
The above example will run ps in the new namespace. It should show two processes, furnace’s PID1, and the ps process itself. After leaving the context, furnace will kill all processes started inside, and destroy the namespaces created, including any mountpoints that were mounted inside (e.g. with container.run(['mount', '...'])).
Of course, all other arguments of run() and Popen() are supported:
import sys
import subprocess
from furnace.context import ContainerContext
with ContainerContext('/opt/ChrootMcChrootface') as container:
ls_result = container.run(['ls', '/bin'], env={'LISTFLAGS': '-la'}, stdout=subprocess.PIPE, check=True)
print('Files:')
print(ls_result.stdout.decode('utf-8'))
file_outside_container = open('the_magic_of_file_descriptors.gz', 'wb')
process_1 = container.Popen(['cat', '/etc/passwd'], stdout=subprocess.PIPE)
process_2 = container.Popen(['gzip'], stdin=process_1.stdout, stdout=file_outside_container)
process_2.communicate()
process_1.wait()
As you can see, the processes started can inherit file descriptors from each other, or outside the container, and can also be managed from the python code outside the container, if you wish.
As a convenience feature, the context has an interactive_shell() method that takes you into bash shell inside the container. This is mostly useful for debugging:
import traceback
from furnace.context import ContainerContext
with ContainerContext('/opt/ChrootMcChrootface') as container:
try:
container.run(['systemctl', '--enable', 'nginx.service'])
except Exception as e:
print("OOOPS, an exception occured:")
traceback.print_exc(file=sys.stdout)
print("Entering debug shell")
container.interactive_shell()
raise
Development
Contributing
We appreciate any feedback, so if you have problems, or even suggestions, don’t hesitate to open an issue. Of course, Pull Requests are extra-welcome, as long as tests pass, and the code is not much worse than all other existing code :)
Setting up a development environment
To set up a virtualenv with all the necessary tools for development, install the GNU make tool and the python3-venv package (it is supposed to be part of the standard python3 library, but on Ubuntu systems is an invidual package). Then simply run:
make dev
This will create a virtualenv in a directory named .venv. This virtualenv is used it for all other make targets, like check
Running tests
During and after development, you usually want to run both coding style checks, and integration tests. Make sure if the ‘loop’ kernel module has been loaded before you run the integration tests.
make lint make check
Please make sure at least these pass before submitting a PR.
License
This project is licensed under the GNU LGPLv2.1 License - see the LICENSE.txt for details
Metadata
Release files for furnace 0.0.10
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| furnace-0.0.10.tar.gz | 25.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| furnace-0.0.10-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 49.5 kB
Release files / furnace-0.0.10.tar.gz
| Download URL | furnace-0.0.10.tar.gz |
|---|---|
| Size | 25.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3977dd242171c2f0e7ba4cf487281fd241cda5cd72338cc4d670a1b9b113cb10
|
|
BLAKE2b-256 checksum How to use checksums |
a073a75d6a43634b3905df771417345bfd3e8a71126f60a3fa98d8597cd38495
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.1 CPython/3.11.2
|
Release files / furnace-0.0.10-py3-none-any.whl
| Download URL | furnace-0.0.10-py3-none-any.whl |
|---|---|
| Size | 23.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1470b360638199f318f8217befa44ee047a4b4a0a11f9dda2a10b054ad505c44
|
|
BLAKE2b-256 checksum How to use checksums |
13b74d8ec1c6020acb58b399700a98f71073461e03f6bc785f83653b59fa68b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.1 CPython/3.11.2
|
Security for furnace 0.0.10
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.