Start making it possible to execute podman inside the VM

This commit is contained in:
Micah Lee 2021-07-01 16:45:25 -07:00
parent c7bd8a317a
commit 2904d44aad
No known key found for this signature in database
GPG key ID: 403C2657CD994F73
5 changed files with 85 additions and 42 deletions

View file

@ -4,12 +4,12 @@ import subprocess
import sys import sys
import pipes import pipes
import shutil import shutil
import os import json
# What is the container runtime for this platform? # What is the container runtime for this platform?
if platform.system() == "Darwin": if platform.system() == "Darwin":
container_tech = "docker" container_tech = "dangerzone-vm"
container_runtime = "/usr/local/bin/docker" container_runtime = shutil.which("docker")
elif platform.system() == "Windows": elif platform.system() == "Windows":
container_tech = "docker" container_tech = "docker"
container_runtime = shutil.which("docker.exe") container_runtime = shutil.which("docker.exe")
@ -29,24 +29,11 @@ else:
startupinfo = None startupinfo = None
def exec_container(args): def exec(args):
args = [container_runtime] + args
args_str = " ".join(pipes.quote(s) for s in args) args_str = " ".join(pipes.quote(s) for s in args)
print("> " + args_str) print("> " + args_str)
sys.stdout.flush() sys.stdout.flush()
# In Tails, tell the container runtime to download over Tor
if (
platform.system() == "Linux"
and os.getlogin() == "amnesia"
and os.getuid() == 1000
):
env = os.environ.copy()
env["HTTP_PROXY"] = "socks5://127.0.0.1:9050"
else:
env = None
with subprocess.Popen( with subprocess.Popen(
args, args,
stdin=None, stdin=None,
@ -55,12 +42,51 @@ def exec_container(args):
bufsize=1, bufsize=1,
universal_newlines=True, universal_newlines=True,
startupinfo=startupinfo, startupinfo=startupinfo,
env=env,
) as p: ) as p:
p.communicate() p.communicate()
return p.returncode return p.returncode
def exec_vm(args, vm_info):
if container_tech == "dangerzone-vm" and vm_info is None:
print("--vm-info-path required on this platform")
return
args = [
"/usr/bin/ssh",
"-q",
"-i",
vm_info["client_key_path"],
"-p",
vm_info["tunnel_port"],
"-o",
"StrictHostKeyChecking=no",
"user@127.0.0.1",
] + args
return exec(args)
def exec_container(args, vm_info):
if container_tech == "dangerzone-vm" and vm_info is None:
print("--vm-info-path required on this platform")
return
if container_tech == "dangerzone-vm":
args = ["podman"] + args
return exec_vm(args, vm_info)
args = [container_runtime] + args
return exec(args)
def load_vm_info(vm_info_path):
if not vm_info_path:
return None
with open(vm_info_path) as f:
return json.loads(f.read())
@click.group() @click.group()
def container_main(): def container_main():
""" """
@ -71,23 +97,21 @@ def container_main():
@container_main.command() @container_main.command()
@click.option("--vm-info-path", default=None)
@click.option("--container-name", default="docker.io/flmcode/dangerzone") @click.option("--container-name", default="docker.io/flmcode/dangerzone")
def ls(container_name): def ls(vm_info_path, container_name):
"""docker image ls [container_name]""" """docker image ls [container_name]"""
sys.exit(exec_container(["image", "ls", container_name])) sys.exit(
exec_container(["image", "ls", container_name]), load_vm_info(vm_info_path)
)
@container_main.command()
def pull():
"""docker pull flmcode/dangerzone"""
sys.exit(exec_container(["pull", "docker.io/flmcode/dangerzone"]))
@container_main.command() @container_main.command()
@click.option("--vm-info-path", default=None)
@click.option("--document-filename", required=True) @click.option("--document-filename", required=True)
@click.option("--pixel-dir", required=True) @click.option("--pixel-dir", required=True)
@click.option("--container-name", default="docker.io/flmcode/dangerzone") @click.option("--container-name", default="docker.io/flmcode/dangerzone")
def documenttopixels(document_filename, pixel_dir, container_name): def documenttopixels(vm_info_path, document_filename, pixel_dir, container_name):
"""docker run --network none -v [document_filename]:/tmp/input_file -v [pixel_dir]:/dangerzone [container_name] document-to-pixels""" """docker run --network none -v [document_filename]:/tmp/input_file -v [pixel_dir]:/dangerzone [container_name] document-to-pixels"""
args = ["run", "--network", "none"] args = ["run", "--network", "none"]
@ -103,16 +127,17 @@ def documenttopixels(document_filename, pixel_dir, container_name):
container_name, container_name,
"document-to-pixels", "document-to-pixels",
] ]
sys.exit(exec_container(args)) sys.exit(exec_container(args, load_vm_info(vm_info_path)))
@container_main.command() @container_main.command()
@click.option("--vm-info-path", default=None)
@click.option("--pixel-dir", required=True) @click.option("--pixel-dir", required=True)
@click.option("--safe-dir", required=True) @click.option("--safe-dir", required=True)
@click.option("--container-name", default="docker.io/flmcode/dangerzone") @click.option("--container-name", default="docker.io/flmcode/dangerzone")
@click.option("--ocr", required=True) @click.option("--ocr", required=True)
@click.option("--ocr-lang", required=True) @click.option("--ocr-lang", required=True)
def pixelstopdf(pixel_dir, safe_dir, container_name, ocr, ocr_lang): def pixelstopdf(vm_info_path, pixel_dir, safe_dir, container_name, ocr, ocr_lang):
"""docker run --network none -v [pixel_dir]:/dangerzone -v [safe_dir]:/safezone [container_name] -e OCR=[ocr] -e OCR_LANGUAGE=[ocr_lang] pixels-to-pdf""" """docker run --network none -v [pixel_dir]:/dangerzone -v [safe_dir]:/safezone [container_name] -e OCR=[ocr] -e OCR_LANGUAGE=[ocr_lang] pixels-to-pdf"""
sys.exit( sys.exit(
exec_container( exec_container(
@ -130,6 +155,7 @@ def pixelstopdf(pixel_dir, safe_dir, container_name, ocr, ocr_lang):
f"OCR_LANGUAGE={ocr_lang}", f"OCR_LANGUAGE={ocr_lang}",
container_name, container_name,
"pixels-to-pdf", "pixels-to-pdf",
] ],
load_vm_info(vm_info_path),
) )
) )

View file

@ -443,6 +443,8 @@ class GlobalCommon(object):
def exec_dangerzone_container(self, args): def exec_dangerzone_container(self, args):
args = [self.dz_container_path] + args args = [self.dz_container_path] + args
if self.vm:
args += ["--vm-info-path", self.vm.vm_info_path]
args_str = " ".join(pipes.quote(s) for s in args) args_str = " ".join(pipes.quote(s) for s in args)
print(Style.DIM + "> " + Style.NORMAL + Fore.CYAN + args_str) print(Style.DIM + "> " + Style.NORMAL + Fore.CYAN + args_str)

View file

@ -1,9 +1,11 @@
from dangerzone import global_common
import shutil import shutil
import os import os
import platform import platform
import tempfile
import subprocess
from PySide2 import QtCore, QtGui, QtWidgets from PySide2 import QtCore, QtGui, QtWidgets
from .tasks import ConvertToPixels, ConvertToPDF
from ..common import Common from ..common import Common

View file

@ -60,6 +60,7 @@ class Vm(QtCore.QObject):
) )
self.sshd_pid_path = os.path.join(self.state_dir.name, "sshd.pid") self.sshd_pid_path = os.path.join(self.state_dir.name, "sshd.pid")
self.sshd_log_path = os.path.join(self.state_dir.name, "sshd.log") self.sshd_log_path = os.path.join(self.state_dir.name, "sshd.log")
self.vm_info_path = os.path.join(self.state_dir.name, "info.json")
self.vm_disk_img_path = os.path.join(self.state_dir.name, "disk.img") self.vm_disk_img_path = os.path.join(self.state_dir.name, "disk.img")
# UDID for VM # UDID for VM
@ -145,8 +146,6 @@ class Vm(QtCore.QObject):
"-o", "-o",
"Compression=yes", "Compression=yes",
"-o", "-o",
"ForceCommand=/usr/bin/whoami",
"-o",
"UseDNS=no", "UseDNS=no",
"-o", "-o",
f"AuthorizedKeysFile={self.ssh_client_pubkey_path}", f"AuthorizedKeysFile={self.ssh_client_pubkey_path}",
@ -157,7 +156,7 @@ class Vm(QtCore.QObject):
# Create a JSON object to pass into the VM # Create a JSON object to pass into the VM
# This is a 512kb file that starts with a JSON object, followed by null bytes # This is a 512kb file that starts with a JSON object, followed by null bytes
vm_info = { guest_vm_info = {
"id_ed25519": ssh_client_key, "id_ed25519": ssh_client_key,
"id_ed25519.pub": ssh_client_pubkey, "id_ed25519.pub": ssh_client_pubkey,
"user": getpass.getuser(), "user": getpass.getuser(),
@ -166,9 +165,17 @@ class Vm(QtCore.QObject):
"tunnel_port": self.sshd_tunnel_port, "tunnel_port": self.sshd_tunnel_port,
} }
with open(self.vm_disk_img_path, "wb") as f: with open(self.vm_disk_img_path, "wb") as f:
vm_info_bytes = json.dumps(vm_info).encode() guest_vm_info_bytes = json.dumps(guest_vm_info).encode()
f.write(vm_info_bytes) f.write(guest_vm_info_bytes)
f.write(b"\x00" * (512 * 1024 - len(vm_info_bytes))) f.write(b"\x00" * (512 * 1024 - len(guest_vm_info_bytes)))
# Create a JSON object for the container process to read
vm_info = {
"client_key_path": self.ssh_client_key_path,
"tunnel_port": self.sshd_tunnel_port,
}
with open(self.vm_info_path, "w") as f:
f.write(json.dumps(vm_info))
# Run VPNKit # Run VPNKit
args = [ args = [

View file

@ -31,15 +31,25 @@ def main():
f.write(info["id_ed25519.pub"]) f.write(info["id_ed25519.pub"])
f.write("\n") f.write("\n")
with open("/home/user/.ssh/config", "w") as f:
f.write("Host hostbox\n")
f.write(f" Hostname {info['ip']}\n")
f.write(f" Port {info['port']}\n")
f.write(f" User {info['user']}\n")
f.write(" IdentityFile /home/user/.ssh/id_ed25519\n")
f.write("\n")
os.chmod("/home/user/.ssh", 0o700) os.chmod("/home/user/.ssh", 0o700)
os.chmod("/home/user/.ssh/id_ed25519", 0o600) os.chmod("/home/user/.ssh/id_ed25519", 0o600)
os.chmod("/home/user/.ssh/id_ed25519.pub", 0o644) os.chmod("/home/user/.ssh/id_ed25519.pub", 0o644)
os.chmod("/home/user/.ssh/authorized_keys", 0o600) os.chmod("/home/user/.ssh/authorized_keys", 0o600)
os.chmod("/home/user/.ssh/config", 0o600)
shutil.chown("/home/user/.ssh", "user", "user") shutil.chown("/home/user/.ssh", "user", "user")
shutil.chown("/home/user/.ssh/id_ed25519", "user", "user") shutil.chown("/home/user/.ssh/id_ed25519", "user", "user")
shutil.chown("/home/user/.ssh/id_ed25519.pub", "user", "user") shutil.chown("/home/user/.ssh/id_ed25519.pub", "user", "user")
shutil.chown("/home/user/.ssh/authorized_keys", "user", "user") shutil.chown("/home/user/.ssh/authorized_keys", "user", "user")
shutil.chown("/home/user/.ssh/config", "user", "user")
# Start SSH reverse port forward # Start SSH reverse port forward
subprocess.run( subprocess.run(
@ -50,14 +60,10 @@ def main():
"/usr/bin/ssh", "/usr/bin/ssh",
"-o", "-o",
"StrictHostKeyChecking=no", "StrictHostKeyChecking=no",
"-i",
"/home/user/.ssh/id_ed25519",
"-N", "-N",
"-R", "-R",
f"{info['tunnel_port']}:127.0.0.1:22", f"{info['tunnel_port']}:127.0.0.1:22",
"-p", "hostbox",
str(info["port"]),
f"{info['user']}@{info['ip']}",
] ]
) )