mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-29 02:12:36 +02:00
Refactor how VM image is created to split it into different files, and write ssh-to-host.py script
This commit is contained in:
parent
da75559e3a
commit
1c39895206
11 changed files with 176 additions and 181 deletions
2
BUILD.md
2
BUILD.md
|
@ -59,7 +59,7 @@ poetry install
|
||||||
Make sure [Docker Desktop](https://www.docker.com/products/docker-desktop) and vagrant (`brew install vagrant`) are installed and run this to collect the binaries from Docker Desktop and then build a custom Alpine Linux ISO for Dangerzone, and copy them into the `share` folder:
|
Make sure [Docker Desktop](https://www.docker.com/products/docker-desktop) and vagrant (`brew install vagrant`) are installed and run this to collect the binaries from Docker Desktop and then build a custom Alpine Linux ISO for Dangerzone, and copy them into the `share` folder:
|
||||||
|
|
||||||
```
|
```
|
||||||
./install/macos/get-vm.sh
|
./install/macos/make-vm.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Run from source tree:
|
Run from source tree:
|
||||||
|
|
|
@ -10,72 +10,72 @@ RUN apk -U upgrade && \
|
||||||
poppler-utils \
|
poppler-utils \
|
||||||
py3-magic \
|
py3-magic \
|
||||||
py3-pillow \
|
py3-pillow \
|
||||||
sudo \
|
sudo
|
||||||
tesseract-ocr \
|
# tesseract-ocr \
|
||||||
tesseract-ocr-data-afr \
|
# tesseract-ocr-data-afr \
|
||||||
tesseract-ocr-data-ara \
|
# tesseract-ocr-data-ara \
|
||||||
tesseract-ocr-data-aze \
|
# tesseract-ocr-data-aze \
|
||||||
tesseract-ocr-data-bel \
|
# tesseract-ocr-data-bel \
|
||||||
tesseract-ocr-data-ben \
|
# tesseract-ocr-data-ben \
|
||||||
tesseract-ocr-data-bul \
|
# tesseract-ocr-data-bul \
|
||||||
tesseract-ocr-data-cat \
|
# tesseract-ocr-data-cat \
|
||||||
tesseract-ocr-data-ces \
|
# tesseract-ocr-data-ces \
|
||||||
tesseract-ocr-data-chi_sim \
|
# tesseract-ocr-data-chi_sim \
|
||||||
tesseract-ocr-data-chi_tra \
|
# tesseract-ocr-data-chi_tra \
|
||||||
tesseract-ocr-data-chr \
|
# tesseract-ocr-data-chr \
|
||||||
tesseract-ocr-data-dan \
|
# tesseract-ocr-data-dan \
|
||||||
tesseract-ocr-data-deu \
|
# tesseract-ocr-data-deu \
|
||||||
tesseract-ocr-data-ell \
|
# tesseract-ocr-data-ell \
|
||||||
tesseract-ocr-data-enm \
|
# tesseract-ocr-data-enm \
|
||||||
tesseract-ocr-data-epo \
|
# tesseract-ocr-data-epo \
|
||||||
tesseract-ocr-data-equ \
|
# tesseract-ocr-data-equ \
|
||||||
tesseract-ocr-data-est \
|
# tesseract-ocr-data-est \
|
||||||
tesseract-ocr-data-eus \
|
# tesseract-ocr-data-eus \
|
||||||
tesseract-ocr-data-fin \
|
# tesseract-ocr-data-fin \
|
||||||
tesseract-ocr-data-fra \
|
# tesseract-ocr-data-fra \
|
||||||
tesseract-ocr-data-frk \
|
# tesseract-ocr-data-frk \
|
||||||
tesseract-ocr-data-frm \
|
# tesseract-ocr-data-frm \
|
||||||
tesseract-ocr-data-glg \
|
# tesseract-ocr-data-glg \
|
||||||
tesseract-ocr-data-grc \
|
# tesseract-ocr-data-grc \
|
||||||
tesseract-ocr-data-heb \
|
# tesseract-ocr-data-heb \
|
||||||
tesseract-ocr-data-hin \
|
# tesseract-ocr-data-hin \
|
||||||
tesseract-ocr-data-hrv \
|
# tesseract-ocr-data-hrv \
|
||||||
tesseract-ocr-data-hun \
|
# tesseract-ocr-data-hun \
|
||||||
tesseract-ocr-data-ind \
|
# tesseract-ocr-data-ind \
|
||||||
tesseract-ocr-data-isl \
|
# tesseract-ocr-data-isl \
|
||||||
tesseract-ocr-data-ita \
|
# tesseract-ocr-data-ita \
|
||||||
tesseract-ocr-data-ita_old \
|
# tesseract-ocr-data-ita_old \
|
||||||
tesseract-ocr-data-jpn \
|
# tesseract-ocr-data-jpn \
|
||||||
tesseract-ocr-data-kan \
|
# tesseract-ocr-data-kan \
|
||||||
tesseract-ocr-data-kat \
|
# tesseract-ocr-data-kat \
|
||||||
tesseract-ocr-data-kor \
|
# tesseract-ocr-data-kor \
|
||||||
tesseract-ocr-data-lav \
|
# tesseract-ocr-data-lav \
|
||||||
tesseract-ocr-data-lit \
|
# tesseract-ocr-data-lit \
|
||||||
tesseract-ocr-data-mal \
|
# tesseract-ocr-data-mal \
|
||||||
tesseract-ocr-data-mkd \
|
# tesseract-ocr-data-mkd \
|
||||||
tesseract-ocr-data-mlt \
|
# tesseract-ocr-data-mlt \
|
||||||
tesseract-ocr-data-msa \
|
# tesseract-ocr-data-msa \
|
||||||
tesseract-ocr-data-nld \
|
# tesseract-ocr-data-nld \
|
||||||
tesseract-ocr-data-nor \
|
# tesseract-ocr-data-nor \
|
||||||
tesseract-ocr-data-pol \
|
# tesseract-ocr-data-pol \
|
||||||
tesseract-ocr-data-por \
|
# tesseract-ocr-data-por \
|
||||||
tesseract-ocr-data-ron \
|
# tesseract-ocr-data-ron \
|
||||||
tesseract-ocr-data-rus \
|
# tesseract-ocr-data-rus \
|
||||||
tesseract-ocr-data-slk \
|
# tesseract-ocr-data-slk \
|
||||||
tesseract-ocr-data-slv \
|
# tesseract-ocr-data-slv \
|
||||||
tesseract-ocr-data-spa \
|
# tesseract-ocr-data-spa \
|
||||||
tesseract-ocr-data-spa_old \
|
# tesseract-ocr-data-spa_old \
|
||||||
tesseract-ocr-data-sqi \
|
# tesseract-ocr-data-sqi \
|
||||||
tesseract-ocr-data-srp \
|
# tesseract-ocr-data-srp \
|
||||||
tesseract-ocr-data-swa \
|
# tesseract-ocr-data-swa \
|
||||||
tesseract-ocr-data-swe \
|
# tesseract-ocr-data-swe \
|
||||||
tesseract-ocr-data-tam \
|
# tesseract-ocr-data-tam \
|
||||||
tesseract-ocr-data-tel \
|
# tesseract-ocr-data-tel \
|
||||||
tesseract-ocr-data-tgl \
|
# tesseract-ocr-data-tgl \
|
||||||
tesseract-ocr-data-tha \
|
# tesseract-ocr-data-tha \
|
||||||
tesseract-ocr-data-tur \
|
# tesseract-ocr-data-tur \
|
||||||
tesseract-ocr-data-ukr \
|
# tesseract-ocr-data-ukr \
|
||||||
tesseract-ocr-data-vie
|
# tesseract-ocr-data-vie
|
||||||
|
|
||||||
# Install pdftk
|
# Install pdftk
|
||||||
RUN \
|
RUN \
|
||||||
|
|
|
@ -133,15 +133,17 @@ class Vm(QtCore.QObject):
|
||||||
f"AuthorizedKeysFile={self.ssh_client_pubkey_path}",
|
f"AuthorizedKeysFile={self.ssh_client_pubkey_path}",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
# TODO: keep track of the sshd process so we can kill it on close
|
||||||
|
|
||||||
# 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 = {
|
vm_info = {
|
||||||
"id_ed25519": ssh_client_key,
|
"id_ed25519": ssh_client_key,
|
||||||
"id_ed25519.pub": ssh_client_pubkey,
|
"id_ed25519.pub": ssh_client_pubkey,
|
||||||
"ssh_target": f"{getpass.getuser()}@192.168.65.2",
|
"user": getpass.getuser(),
|
||||||
"sshd_port": sshd_port,
|
"ip": "192.168.65.2",
|
||||||
"sshd_tunnel_port": sshd_tunnel_port,
|
"port": sshd_port,
|
||||||
|
"tunnel_port": 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()
|
vm_info_bytes = json.dumps(vm_info).encode()
|
||||||
|
|
|
@ -38,7 +38,7 @@ sudo -u user sh mkimage.sh --tag v3.14 \
|
||||||
--repository http://dl-cdn.alpinelinux.org/alpine/v3.14/main \
|
--repository http://dl-cdn.alpinelinux.org/alpine/v3.14/main \
|
||||||
--repository http://dl-cdn.alpinelinux.org/alpine/v3.14/community \
|
--repository http://dl-cdn.alpinelinux.org/alpine/v3.14/community \
|
||||||
--profile dangerzone
|
--profile dangerzone
|
||||||
mv alpine-dangerzone-v3.14-x86_64.iso dangerzone.iso
|
mv /vagrant/vm/alpine-dangerzone-v3.14-x86_64.iso /vagrant/vm/dangerzone.iso
|
||||||
|
|
||||||
# Fix permissions
|
# Fix permissions
|
||||||
chmod 755 /vagrant/vm
|
chmod 755 /vagrant/vm
|
||||||
|
|
12
install/vm-builder/etc/answers.txt
Normal file
12
install/vm-builder/etc/answers.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
KEYMAPOPTS="us us"
|
||||||
|
HOSTNAMEOPTS="-n dangerzone"
|
||||||
|
INTERFACESOPTS="auto lo
|
||||||
|
iface lo inet loopback
|
||||||
|
|
||||||
|
auto eth0
|
||||||
|
iface eth0 inet dhcp
|
||||||
|
hostname dangerzone
|
||||||
|
"
|
||||||
|
DNSOPTS="-d example.com 4.4.4.4"
|
||||||
|
TIMEZONEOPTS="-z UTC"
|
||||||
|
SSHDOPTS="-c openssh"
|
3
install/vm-builder/etc/apk/world
Normal file
3
install/vm-builder/etc/apk/world
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
alpine-base
|
||||||
|
openssh
|
||||||
|
podman
|
22
install/vm-builder/etc/init.d/dangerzone
Executable file
22
install/vm-builder/etc/init.d/dangerzone
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
name="Dangerzone init script"
|
||||||
|
start_pre() {
|
||||||
|
# Setup Alpine
|
||||||
|
/sbin/setup-alpine -f /etc/answers.txt -e -q
|
||||||
|
rm /etc/answers.txt
|
||||||
|
|
||||||
|
# Create user
|
||||||
|
/usr/sbin/adduser -D -u 1001 user
|
||||||
|
|
||||||
|
# Move containers into home dir
|
||||||
|
mkdir -p /home/user/.local/share
|
||||||
|
mv /etc/container-data /home/user/.local/share/containers
|
||||||
|
chown -R user:user /home/user/.local
|
||||||
|
|
||||||
|
# Allow podman containers to run
|
||||||
|
echo "user:100000:65536" >> /etc/subuid
|
||||||
|
echo "user:100000:65536" >> /etc/subgid
|
||||||
|
|
||||||
|
# SSH reverse tunnel to host
|
||||||
|
/etc/ssh-to-host.py &
|
||||||
|
}
|
55
install/vm-builder/etc/ssh-to-host.py
Executable file
55
install/vm-builder/etc/ssh-to-host.py
Executable file
|
@ -0,0 +1,55 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import stat
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not os.path.exists("/dev/vda"):
|
||||||
|
print("Disk is not mounted, skipping")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Read data
|
||||||
|
with open("/dev/vda", "rb") as f:
|
||||||
|
s = f.read()
|
||||||
|
|
||||||
|
info = json.loads(s[0 : s.find(b"\0")])
|
||||||
|
|
||||||
|
# Create SSH files
|
||||||
|
os.makedirs("/home/user/.ssh", mode=0o700, exist_ok=True)
|
||||||
|
perms = stat.S_IRUSR | stat.S_IWUSR
|
||||||
|
|
||||||
|
with open("/home/user/.ssh/id_ed25519", "w") as f:
|
||||||
|
f.write(info["id_ed25519"])
|
||||||
|
|
||||||
|
with open("/home/user/.ssh/id_ed25519.pub", "w") as f:
|
||||||
|
f.write(info["id_ed25519.pub"])
|
||||||
|
|
||||||
|
with open("/home/user/.ssh/authorized_keys", "w") as f:
|
||||||
|
f.write(info["id_ed25519.pub"])
|
||||||
|
|
||||||
|
os.chmod("/home/user/.ssh/id_ed25519", perms)
|
||||||
|
os.chmod("/home/user/.ssh/id_ed25519.pub", perms)
|
||||||
|
os.chmod("/home/user/.ssh/authorized_keys", perms)
|
||||||
|
|
||||||
|
# Start SSH reverse port forward
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
"/usr/bin/ssh",
|
||||||
|
"-o",
|
||||||
|
"StrictHostKeyChecking=no",
|
||||||
|
"-i",
|
||||||
|
"/home/user/.ssh/id_ed25519",
|
||||||
|
"-N",
|
||||||
|
"-R",
|
||||||
|
f"{info['tunnel_port']}:127.0.0.1:22",
|
||||||
|
"-p",
|
||||||
|
info["port"],
|
||||||
|
f"{info['user']}@{info['ip']}",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
7
install/vm-builder/etc/ssh/sshd_config
Normal file
7
install/vm-builder/etc/ssh/sshd_config
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
AuthorizedKeysFile .ssh/authorized_keys
|
||||||
|
AllowTcpForwarding no
|
||||||
|
GatewayPorts no
|
||||||
|
X11Forwarding no
|
||||||
|
Subsystem sftp /usr/lib/ssh/sftp-server
|
||||||
|
UseDNS no
|
||||||
|
PasswordAuthentication no
|
|
@ -10,15 +10,6 @@ cleanup() {
|
||||||
rm -rf "$tmp"
|
rm -rf "$tmp"
|
||||||
}
|
}
|
||||||
|
|
||||||
makefile() {
|
|
||||||
OWNER="$1"
|
|
||||||
PERMS="$2"
|
|
||||||
FILENAME="$3"
|
|
||||||
cat > "$FILENAME"
|
|
||||||
chown "$OWNER" "$FILENAME"
|
|
||||||
chmod "$PERMS" "$FILENAME"
|
|
||||||
}
|
|
||||||
|
|
||||||
rc_add() {
|
rc_add() {
|
||||||
mkdir -p "$tmp"/etc/runlevels/"$2"
|
mkdir -p "$tmp"/etc/runlevels/"$2"
|
||||||
ln -sf /etc/init.d/"$1" "$tmp"/etc/runlevels/"$2"/"$1"
|
ln -sf /etc/init.d/"$1" "$tmp"/etc/runlevels/"$2"/"$1"
|
||||||
|
@ -27,107 +18,9 @@ rc_add() {
|
||||||
tmp="$(mktemp -d)"
|
tmp="$(mktemp -d)"
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
mkdir -p "$tmp"/etc/apk
|
# Copy /etc
|
||||||
makefile root:root 0644 "$tmp"/etc/apk/world <<EOF
|
cp -r /vagrant/etc "$tmp"
|
||||||
alpine-base
|
chown -R root:root "$tmp"/etc
|
||||||
openssh
|
|
||||||
podman
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Custom sshd config
|
|
||||||
mkdir -p "$tmp"/etc/ssh
|
|
||||||
makefile root:root 0644 "$tmp"/etc/ssh/sshd_config <<EOF
|
|
||||||
AuthorizedKeysFile .ssh/authorized_keys
|
|
||||||
AllowTcpForwarding no
|
|
||||||
GatewayPorts no
|
|
||||||
X11Forwarding no
|
|
||||||
Subsystem sftp /usr/lib/ssh/sftp-server
|
|
||||||
UseDNS no
|
|
||||||
PasswordAuthentication no
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Script to read info from host
|
|
||||||
makefile root:root 0755 "$tmp"/etc/read-info-from-host <<EOF
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
import json
|
|
||||||
|
|
||||||
# Read data
|
|
||||||
with open("/dev/vda", "rb") as f:
|
|
||||||
s = f.read()
|
|
||||||
|
|
||||||
info = json.loads(s[0:s.find(b"\0")])
|
|
||||||
|
|
||||||
# Create SSH files
|
|
||||||
os.makedirs("/home/user/.ssh", exist_ok=True)
|
|
||||||
|
|
||||||
with open("/home/user/.ssh/id_ed25519") as f:
|
|
||||||
f.write(info["id_ed25519"])
|
|
||||||
|
|
||||||
with open("/home/user/.ssh/id_ed25519.pub") as f:
|
|
||||||
f.write(info["id_ed25519.pub"])
|
|
||||||
|
|
||||||
with open("/home/user/.ssh/authorized_keys") as f:
|
|
||||||
f.write(info["id_ed25519.pub"])
|
|
||||||
|
|
||||||
with open("/home/user/.ssh/env_ssh_target") as f:
|
|
||||||
f.write(info['ssh_target'])
|
|
||||||
|
|
||||||
with open("/home/user/.ssh/env_sshd_port") as f:
|
|
||||||
f.write(info['sshd_port'])
|
|
||||||
|
|
||||||
with open("/home/user/.ssh/env_sshd_tunnel_port") as f:
|
|
||||||
f.write(info['sshd_tunnel_port'])
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Dangerzone alpine setup
|
|
||||||
makefile root:root 0644 "$tmp"/etc/answers.txt <<EOF
|
|
||||||
KEYMAPOPTS="us us"
|
|
||||||
HOSTNAMEOPTS="-n dangerzone"
|
|
||||||
INTERFACESOPTS="auto lo
|
|
||||||
iface lo inet loopback
|
|
||||||
|
|
||||||
auto eth0
|
|
||||||
iface eth0 inet dhcp
|
|
||||||
hostname dangerzone
|
|
||||||
"
|
|
||||||
DNSOPTS="-d example.com 4.4.4.4"
|
|
||||||
TIMEZONEOPTS="-z UTC"
|
|
||||||
SSHDOPTS="-c openssh"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
mkdir -p "$tmp"/etc/init.d
|
|
||||||
makefile root:root 0755 "$tmp"/etc/init.d/dangerzone <<EOF
|
|
||||||
#!/sbin/openrc-run
|
|
||||||
name="Dangerzone init script"
|
|
||||||
start_pre() {
|
|
||||||
# Setup Alpine
|
|
||||||
/sbin/setup-alpine -f /etc/answers.txt -e -q
|
|
||||||
rm /etc/answers.txt
|
|
||||||
|
|
||||||
# Create user
|
|
||||||
/usr/sbin/adduser -D -u 1001 user
|
|
||||||
|
|
||||||
# Move containers into home dir
|
|
||||||
mkdir -p /home/user/.local/share
|
|
||||||
mv /etc/container-data /home/user/.local/share/containers
|
|
||||||
chown -R user:user /home/user/.local
|
|
||||||
|
|
||||||
# Allow podman containers to run
|
|
||||||
echo "user:100000:65536" >> /etc/subuid
|
|
||||||
echo "user:100000:65536" >> /etc/subgid
|
|
||||||
|
|
||||||
# Get info from the host
|
|
||||||
/etc/read-info-from-host
|
|
||||||
chmod 700 /home/user/.ssh
|
|
||||||
chmod 600 /home/user/.ssh/*
|
|
||||||
|
|
||||||
# Start the ssh reverse tunnel
|
|
||||||
SSH_TARGET=$(cat /home/user/.ssh/env_ssh_target)
|
|
||||||
SSHD_PORT=$(cat /home/user/.ssh/env_sshd_port)
|
|
||||||
SSHD_TUNNEL_PORT=$(cat /home/user/.ssh/sshd_tunnel_port)
|
|
||||||
/usr/bin/ssh -o StrictHostKeyChecking=no -N -R $SSHD_TUNNEL_PORT:127.0.0.1:22 -p $SSHD_PORT $SSH_TARGET &
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Fix permissions and add containers to /etc/container-data, temporarily
|
# Fix permissions and add containers to /etc/container-data, temporarily
|
||||||
for WEIRD_FILE in $(find /home/user/.local/share/containers -perm 000); do
|
for WEIRD_FILE in $(find /home/user/.local/share/containers -perm 000); do
|
||||||
|
@ -144,6 +37,7 @@ rc_add sshd boot
|
||||||
# Run setup-alpine
|
# Run setup-alpine
|
||||||
rc_add dangerzone boot
|
rc_add dangerzone boot
|
||||||
|
|
||||||
|
# Other init scripts
|
||||||
rc_add devfs sysinit
|
rc_add devfs sysinit
|
||||||
rc_add dmesg sysinit
|
rc_add dmesg sysinit
|
||||||
rc_add mdev sysinit
|
rc_add mdev sysinit
|
||||||
|
|
Loading…
Reference in a new issue