To reduce 90% of common post here i decided to learn to use salt on Qubes to provide pre-configured hardened template and browsers. I spend 3-4 days working on this.
What is salt ? Read here https://doc.qubes-os.org/en/latest/user/advanced-topics/salt.html but with simple term you can say it's a "advanced bash script" to setup your own config under Qubes
Once you have installed everything i recommend you to switch to this guide https://forum.qubes-os.org/t/qubes-os-live-mode-dom0-in-ram-non-persistent-boot-ram-wipe-protection-against-forensics-tails-mode-hardening-dom0-root-read-only-paranoid-security/38868
The guide target advanced Qubes users (for now) i will provide the same setup for noob users soon
The guide is using debian-13-minimal and fedora-43-minimal template so you will need to install those templates before starting
The debian/kicksecure salt file require sys-whonix to setup the template but the fedora salt file do not require sys-whonix
To use the "automatic installation" file you need to move the file inside dom0 with this command
qvm-run --pass-io <src-vm> 'cat /path/to/file_in_src_domain' > /path/to/file_name_in_dom0
To be more clear the command must look like this
qvm-run --pass-io fedora-43 'cat /home/user/Downlods/firefox.sls' > firefox.sls
Then do sudo mv (name of the file) /srv/salt/
or you can use this guide to copy paste easily
The file must be put at /srv/salt/(name of the file).sls
The name of the file doesn't matter you can name the file ex.sls it will work
In dom0 open a terminal and do sudo qubesctl state.apply librewolf (don't put "sls" at the end of the command) sudo qubesctl state.apply x where x = the name of the file in /srv/salt/
If you do not have enough ram the installation process will abort so don't open too much vm at the same time.
Features :
✅ Deny read access to root file system , home directories except Downloads and machine-id for browsers using my apparmor profiles ✅ Dark theme enabled by default ✅ Anonymize hostname at boot for Template, Appvm, Dispvm (works only for deb/kicksecure template for now.. the script doesn't work in fedora template i don't know why..) ✅ Every installation of browsers will be done by using apt-transport-tor (for deb based template) because fedora do not provide this feature ✅ Firefox is using arkenfox user.js and brave is hardened by default the browser profile is coming from here no telemetry , no ai enabled etc... ✅ qvm-firewall enabled by default for the Appvm we allow only dns traffic , https , http trafic everything else will be drop ✅ Minimize debian even more thanks to qubist post ✅ Automatically install Ublock origin when firefox start (like librewolf) ✅ Automatically setup wget proxy and curl proxy to install software in the template (works only in debian for unknow reason) ✅ Apparmor enabled by default the browser , Nautilus and qubes features will use my apparmor profiles
[details="debian-brave-apparmor.sls"]
start-debian-minimal:
qvm.start:
- name: debian-13-minimal
update-debian-minimal:
qvm.run:
- name: debian-13-minimal
- cmd: |
/bin/bash -c 'apt-get update && apt-get -y full-upgrade'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: start-debian-minimal
shutdown-debian-minimal:
qvm.shutdown:
- name: debian-13-minimal
- require:
- qvm: update-debian-minimal
setup-transport:
qvm.start:
- name: debian-13-minimal
- require:
- qvm: shutdown-debian-minimal
fix-locale:
qvm.run:
- name: debian-13-minimal
- cmd: |
/bin/bash -c "sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && /usr/sbin/locale-gen" && \
sed -i 's/^# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
/usr/sbin/locale-gen
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: setup-transport
setup-tor:
qvm.run:
- name: debian-13-minimal
- cmd: |
/bin/bash -c 'apt-get -y install apt-transport-tor alacritty'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: fix-locale
minimize-debian:
qvm.run:
- name: debian-13-minimal
- cmd: |
/bin/bash -c 'apt-get -y purge \
apt-transport-https \
apt-utils \
cpio \
cron \
cron-daemon-common \
debconf-i18n \
dhcpcd-base \
eatmydata \
fdisk \
ifupdown \
iproute2 \
iputils-ping \
less \
libcap2-bin \
libeatmydata1 \
libfdisk1 \
libgcrypt20 \
libidn2-0 \
libjansson4 \
libk5crypto3 \
libkeyutils1 \
libkrb5support0 \
libmnl0 \
libnewt0.52 \
libp11-kit0 \
libsemanage-common \
libsepol2 \
libslang2 \
libtext-iconv-perl \
libtirpc-common \
libxtables12 \
logrotate \
nftables \
tasksel \
whiptail \
xterm && apt-get -y autoremove'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: setup-tor
shutdown-after-tor:
qvm.shutdown:
- name: debian-13-minimal
- require:
- qvm: minimize-debian
clone-base-apparmor:
qvm.clone:
- name: base-apparmor
- source: debian-13-minimal
- require:
- qvm: shutdown-after-tor
config-apt:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/sources.list
deb tor+https://deb.debian.org/debian trixie main contrib non-free-firmware
deb tor+https://deb.debian.org/debian-security trixie-security main contrib non-free-firmware
deb tor+https://deb.debian.org/debian trixie-backports main
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: clone-base-apparmor
enable-dark-theme:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/environment
GTK_THEME=Adwaita:dark
QT_QPA_PLATFORMTHEME=qt5ct
QT_STYLE_OVERRIDE=Adwaita-dark
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: config-apt
random-hostname:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat > /etc/rc.local << '"'"'EOF'"'"'
#!/bin/bash
# Anonymize hostname with random name at boot
RANDOM_HOSTNAME=$(cat /dev/urandom | tr -dc "a-z" | head -c 12)
echo "$RANDOM_HOSTNAME" > /etc/hostname
hostname "$RANDOM_HOSTNAME"
sed -i "s/^127\.0\.0\.1.*/127.0.0.1 $RANDOM_HOSTNAME localhost/" /etc/hosts
hostnamectl set-hostname "$RANDOM_HOSTNAME" 2>/dev/null || true
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: enable-dark-theme
random-hostname-exec:
qvm.run:
- name: base-apparmor
- cmd: chmod +x /etc/rc.local
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: random-hostname
config-apt-onion-qubes:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/sources.list.d/qubes-r4.list
deb [arch=amd64 signed-by=/usr/share/keyrings/qubes-archive-keyring-4.3.gpg] tor+http://deb.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r4.3/vm trixie main
# Backup HTTPS repository (commented)
#deb [arch=amd64 signed-by=/usr/share/keyrings/qubes-archive-keyring-4.3.gpg ] https://deb.qubes-os.org/r4.3/vm trixie main"
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: random-hostname-exec
set-pinning-backports:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/preferences.d/backports
Package: *
Pin: release n=trixie-backports
Pin-Priority: 900
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: config-apt-onion-qubes
set-pinning-stable:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/preferences.d/stable
Package: *
Pin: release n=stable
Pin-Priority: 500
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: set-pinning-backports
update-base-apparmor:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'apt-get update && apt-get -y full-upgrade'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: set-pinning-backports
- qvm: set-pinning-stable
restart:
qvm.shutdown:
- name: base-apparmor
- require:
- qvm: update-base-apparmor
start-again:
qvm.start:
- name: base-apparmor
- require:
- qvm: restart
add-unstable-repo:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >>/etc/apt/sources.list
deb tor+https://deb.debian.org/debian/ unstable main
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: start-again
create-apparmor-pinning:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/preferences.d/unstable-pin
Package: apparm* python*-appar* python*-libappar*
Pin: release a=unstable
Pin-Priority: 990
Package: *
Pin: release a=unstable
Pin-Priority: 1
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: add-unstable-repo
update-indexes-after-unstable:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'apt update'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: create-apparmor-pinning
install-apparmor:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'apt install -y -t unstable apparmor apparmor-utils apparmor-profiles apparmor-profiles-extra'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: update-indexes-after-unstable
shutdown-before-kernelopts:
qvm.shutdown:
- name: base-apparmor
- require:
- qvm: install-apparmor
set-apparmor-kernelopts:
qvm.prefs:
- name: base-apparmor
- kernelopts: 'swiotlb=2048 apparmor=1 security=apparmor'
- require:
- qvm: shutdown-before-kernelopts
restart-base-apparmor:
qvm.start:
- name: base-apparmor
- require:
- qvm: set-apparmor-kernelopts
minimize-git:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'apt-get install --no-install-recommends -y git'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: restart-base-apparmor
speed-boost-apparmor:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c '
tee -a /etc/apparmor/parser.conf > /dev/null <<EOF
write-cache
cache-loc /etc/apparmor/earlypolicy/
Optimize=compress-fast
EOF
'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: minimize-git
shutdown-base-apparmor-before-clone:
qvm.shutdown:
- name: base-apparmor
- require:
- qvm: speed-boost-apparmor
cloning-apparmor:
qvm.clone:
- name: debian-apparmor-brave
- source: base-apparmor
- flags:
- shutdown
start-brave-template:
qvm.start:
- name: debian-apparmor-brave
- require:
- qvm: cloning-apparmor
# we install the tor package you will need it to install package in appvm or dispvm
install-curl-tor:
qvm.run:
- name: debian-apparmor-brave
- cmd: 'apt-get -y install tor curl'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: start-brave-template
# by default the tor package will enable the tor service but we are already using sys-whonix it's useless
disable-tor-service:
qvm.run:
- name: debian-apparmor-brave
- cmd: 'systemctl disable tor'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: install-curl-tor
download-brave-key:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
bash -c "export all_proxy=http://127.0.0.1:8082/ && \
curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg \
https://brave-browser-apt-release.s3.brave4u7jddbv7cyviptqjc7jusxh72uik7zt6adtckl5f4nwy2v72qd.onion/brave-browser-archive-keyring.gpg"
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: disable-tor-service
add-brave-repo:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
bash -c "export all_proxy=http://127.0.0.1:8082/ && \
curl -fsSLo /etc/apt/sources.list.d/brave-browser-release.sources \
https://brave-browser-apt-release.s3.brave4u7jddbv7cyviptqjc7jusxh72uik7zt6adtckl5f4nwy2v72qd.onion/brave-browser.sources"
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: download-brave-key
force-brave-onion-apt:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
/bin/bash -c 'cat > /etc/apt/sources.list.d/brave-browser-release.sources << EOF
Types: deb
URIs: https://brave-browser-apt-release.s3.brave4u7jddbv7cyviptqjc7jusxh72uik7zt6adtckl5f4nwy2v72qd.onion
Suites: stable
Components: main
Architectures: amd64 arm64
Signed-By: /usr/share/keyrings/brave-browser-archive-keyring.gpg
EOF'
- user: root
- flags:
- pass-io
- nogui
- require:
- qvm: add-brave-repo
install-brave:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
bash -c 'apt-get update && apt-get install -y brave-browser zenity ffmpeg libavcodec-extra pipewire-qubes qubes-core-agent-networking nautilus qubes-core-agent-nautilus && \
apt-get -y purge gnome-keyring && \
apt-get -y autoremove'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: force-brave-onion-apt
setup-apparmor-profiles-dkzkz:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
/bin/bash -c 'export all_proxy=http://127.0.0.1:8082/ && \
cd /tmp && \
git clone https://codeberg.org/dkzkz/apparmor-qubes && \
cd /tmp/apparmor-qubes/stable/browser/brave && \
mv bra* /etc/apparmor.d/ && \
mv /tmp/apparmor-qubes/stable/file-manager/nautilus /etc/apparmor.d/ && \
mv /tmp/apparmor-qubes/stable/display-vm/Xorg /etc/apparmor.d/Xorg && \
cd /tmp/apparmor-qubes/stable/qubes-scripts/ && \
mv q* /etc/apparmor.d/ && \
cd /tmp/apparmor-qubes/stable/xdg-open/ && \
mv open /etc/apparmor.d/'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: install-brave
enable-brave-apparmor:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
/bin/bash -c 'apparmor_parser -r /etc/apparmor.d/brav* && \
apparmor_parser -r /etc/apparmor.d/Xorg && \
apparmor_parser -r /etc/apparmor.d/qubes* && \
apparmor_parser -r /etc/apparmor.d/nautilus && \
apparmor_parser -r /etc/apparmor.d/open'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: setup-apparmor-profiles-dkzkz
cleanup-apparmor-repo:
qvm.run:
- name: debian-apparmor-brave
- cmd: 'rm -rf /tmp/apparmor-qubes'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: enable-brave-apparmor
create-brave-dir:
qvm.run:
- name: debian-apparmor-brave
- cmd: 'mkdir -p /opt/brave.com/brave'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: cleanup-apparmor-repo
setup-proxy-wget:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
/bin/bash -c '
echo "proxy = http://127.0.0.1:8082" >> ~/.curlrc
echo "use_proxy = on" >> ~/.wgetrc
echo "http_proxy = 127.0.0.1:8082" >> ~/.wgetrc
echo "https_proxy = 127.0.0.1:8082" >> ~/.wgetrc'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: create-brave-dir
write-initial-preferences:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
/bin/bash -c 'cd /tmp && \
wget https://codeberg.org/dkzkz/apparmor-qubes/raw/branch/main/install/salt/debian/apparmor/brave-browser/brave-browser.sls/initial_preferences && \
mv ini* /opt/brave.com/brave/'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: setup-proxy-wget
create-policy-dir:
qvm.run:
- name: debian-apparmor-brave
- cmd: 'mkdir -p /etc/brave/policies/managed'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: write-initial-preferences
write-group-policy:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/brave/policies/managed/GroupPolicy.json
{
"MetricsReportingEnabled": false
}
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: create-policy-dir
make-skel-dir:
qvm.run:
- name: debian-apparmor-brave
- cmd: 'mkdir -p /etc/skel/.config/BraveSoftware/Brave-Browser'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: write-group-policy
write-skel-local-state:
qvm.run:
- name: debian-apparmor-brave
- cmd: |
/bin/bash -c 'cat <<EOF | sudo tee /etc/skel/.config/BraveSoftware/Brave-Browser/Local\ State > /dev/null
{
"background_mode": {"enabled": false},
"hardware_acceleration_mode": {"enabled": false},
"brave": {
"p3a": {"enabled": false},
"stats": {"reporting_enabled": false}
},
"default_apps": {"extensions": {}},
"extensions": {
"theme": {"colors": {}}
},
"sync_promo": {"user_skipped": true}
}
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: make-skel-dir
shutdown-template:
qvm.shutdown:
- name: debian-apparmor-brave
- require:
- qvm: write-skel-local-state
set-template-colour:
qvm.prefs:
- name: debian-apparmor-brave
- label: black
- require:
- qvm: shutdown-template
create-dvm:
qvm.present:
- name: brave-browser-dvm
- template: debian-apparmor-brave
- label: yellow
- require:
- qvm: set-template-colour
config-firewall:
cmd.run:
- name: |
printf "action=accept specialtarget=dns
action=accept proto=tcp dstports=443
action=accept proto=tcp dstports=80
action=accept proto=tcp dstports=9050
action=drop" | qubesd-query dom0 admin.vm.firewall.Set brave-browser-dvm
config-brave-dvm:
qvm.prefs:
- name: brave-browser-dvm
- memory: 300
- maxmem: 3000
- template-for-dispvms: true
- require:
- qvm: create-dvm
enable-brave-appmenus-dispvm:
qvm.features:
- name: brave-browser-dvm
- enable:
- service.apparmor
- appmenus-dispvm
- require:
- qvm: config-brave-dvm
hardening-dvm:
qvm.features:
- name: brave-browser-dvm
- set:
- anon-timezone: '1'
- menu-items: brave-browser.desktop Alacritty.desktop
- require:
- qvm: enable-brave-appmenus-dispvm
[/details]
[details="debian-mullvad-apparmor.sls"]
start-debian-minimal:
qvm.start:
- name: debian-13-minimal
update-debian-minimal:
qvm.run:
- name: debian-13-minimal
- cmd: |
/bin/bash -c 'apt-get update && apt-get -y full-upgrade'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: start-debian-minimal
shutdown-debian-minimal:
qvm.shutdown:
- name: debian-13-minimal
- require:
- qvm: update-debian-minimal
setup-transport:
qvm.start:
- name: debian-13-minimal
- require:
- qvm: shutdown-debian-minimal
fix-locale:
qvm.run:
- name: debian-13-minimal
- cmd: |
/bin/bash -c "sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && /usr/sbin/locale-gen" && \
sed -i 's/^# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
/usr/sbin/locale-gen
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: setup-transport
setup-tor:
qvm.run:
- name: debian-13-minimal
- cmd: |
/bin/bash -c 'apt-get -y install apt-transport-tor alacritty'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: fix-locale
minimize-debian:
qvm.run:
- name: debian-13-minimal
- cmd: |
/bin/bash -c 'apt-get -y purge \
apt-transport-https \
apt-utils \
cpio \
cron \
cron-daemon-common \
debconf-i18n \
dhcpcd-base \
eatmydata \
fdisk \
ifupdown \
iproute2 \
iputils-ping \
less \
libcap2-bin \
libeatmydata1 \
libfdisk1 \
libgcrypt20 \
libidn2-0 \
libjansson4 \
libk5crypto3 \
libkeyutils1 \
libkrb5support0 \
libmnl0 \
libnewt0.52 \
libp11-kit0 \
libsemanage-common \
libsepol2 \
libslang2 \
libtext-iconv-perl \
libtirpc-common \
libxtables12 \
logrotate \
nftables \
tasksel \
whiptail \
xterm && apt-get -y autoremove'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: setup-tor
shutdown-after-tor:
qvm.shutdown:
- name: debian-13-minimal
- require:
- qvm: minimize-debian
clone-base-apparmor:
qvm.clone:
- name: base-apparmor
- source: debian-13-minimal
- require:
- qvm: shutdown-after-tor
config-apt:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/sources.list
deb tor+https://deb.debian.org/debian trixie main contrib non-free-firmware
deb tor+https://deb.debian.org/debian-security trixie-security main contrib non-free-firmware
deb tor+https://deb.debian.org/debian trixie-backports main
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: clone-base-apparmor
enable-dark-theme:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/environment
GTK_THEME=Adwaita:dark
QT_QPA_PLATFORMTHEME=qt5ct
QT_STYLE_OVERRIDE=Adwaita-dark
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: config-apt
random-hostname:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat > /etc/rc.local << '"'"'EOF'"'"'
#!/bin/bash
# Anonymize hostname with random name at boot
RANDOM_HOSTNAME=$(cat /dev/urandom | tr -dc "a-z" | head -c 12)
echo "$RANDOM_HOSTNAME" > /etc/hostname
hostname "$RANDOM_HOSTNAME"
sed -i "s/^127\.0\.0\.1.*/127.0.0.1 $RANDOM_HOSTNAME localhost/" /etc/hosts
hostnamectl set-hostname "$RANDOM_HOSTNAME" 2>/dev/null || true
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: enable-dark-theme
random-hostname-exec:
qvm.run:
- name: base-apparmor
- cmd: chmod +x /etc/rc.local
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: random-hostname
config-apt-onion-qubes:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/sources.list.d/qubes-r4.list
deb [arch=amd64 signed-by=/usr/share/keyrings/qubes-archive-keyring-4.3.gpg] tor+http://deb.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r4.3/vm trixie main
# Backup HTTPS repository (commented)
#deb [arch=amd64 signed-by=/usr/share/keyrings/qubes-archive-keyring-4.3.gpg ] https://deb.qubes-os.org/r4.3/vm trixie main"
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: random-hostname-exec
set-pinning-backports:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/preferences.d/backports
Package: *
Pin: release n=trixie-backports
Pin-Priority: 900
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: config-apt-onion-qubes
set-pinning-stable:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/preferences.d/stable
Package: *
Pin: release n=stable
Pin-Priority: 500
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: set-pinning-backports
update-base-apparmor:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'apt-get update && apt-get -y full-upgrade'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: set-pinning-backports
- qvm: set-pinning-stable
restart:
qvm.shutdown:
- name: base-apparmor
- require:
- qvm: update-base-apparmor
start-again:
qvm.start:
- name: base-apparmor
- require:
- qvm: restart
add-unstable-repo:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >>/etc/apt/sources.list
deb tor+https://deb.debian.org/debian/ unstable main
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: start-again
create-apparmor-pinning:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'cat <<EOF >/etc/apt/preferences.d/unstable-pin
Package: apparm* python*-appar* python*-libappar*
Pin: release a=unstable
Pin-Priority: 990
Package: *
Pin: release a=unstable
Pin-Priority: 1
EOF'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: add-unstable-repo
update-indexes-after-unstable:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'apt update'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: create-apparmor-pinning
install-apparmor:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'apt install -y -t unstable apparmor apparmor-utils apparmor-profiles apparmor-profiles-extra'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: update-indexes-after-unstable
shutdown-before-kernelopts:
qvm.shutdown:
- name: base-apparmor
- require:
- qvm: install-apparmor
set-apparmor-kernelopts:
qvm.prefs:
- name: base-apparmor
- kernelopts: 'swiotlb=2048 apparmor=1 security=apparmor'
- require:
- qvm: shutdown-before-kernelopts
restart-base-apparmor:
qvm.start:
- name: base-apparmor
- require:
- qvm: set-apparmor-kernelopts
minimize-git:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c 'apt-get install --no-install-recommends -y git'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: restart-base-apparmor
speed-boost-apparmor:
qvm.run:
- name: base-apparmor
- cmd: |
/bin/bash -c '
tee -a /etc/apparmor/parser.conf > /dev/null <<EOF
write-cache
cache-loc /etc/apparmor/earlypolicy/
Optimize=compress-fast
EOF
'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: minimize-git
shutdown-base-apparmor-before-clone:
qvm.shutdown:
- name: base-apparmor
- require:
- qvm: speed-boost-apparmor
clone-debian-13-minimal-to-mullvad-template:
qvm.clone:
- name: debian-apparmor-mullvad
- source: base-apparmor
- flags:
- shutdown
- require:
- qvm: shutdown-base-apparmor-before-clone
# Start the cloned template
start-mullvad-template:
qvm.start:
- name: debian-apparmor-mullvad
- require:
- qvm: clone-debian-13-minimal-to-mullvad-template
basic-tool-needed:
qvm.run:
- name: debian-apparmor-mullvad
- cmd: 'apt-get -y install curl wget'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: start-mullvad-template
setup-proxy-wget:
qvm.run:
- name: debian-apparmor-librewolf
- cmd: |
/bin/bash -c '
echo "proxy = http://127.0.0.1:8082" >> ~/.curlrc
echo "use_proxy = on" >> ~/.wgetrc
echo "http_proxy = 127.0.0.1:8082" >> ~/.wgetrc
echo "https_proxy = 127.0.0.1:8082" >> ~/.wgetrc'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: basic-tool-needed
# Download Mullvad signing key
download-mullvad-key:
qvm.run:
- name: debian-apparmor-mullvad
- cmd: 'bash -c "export all_proxy=http://127.0.0.1:8082/ && curl -fsSLo /usr/share/keyrings/mullvad-keyring.asc https://repository.mullvad.net/deb/mullvad-keyring.asc"'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: setup-proxy-wget
# Add Mullvad repository
add-mullvad-repository:
qvm.run:
- name: debian-apparmor-mullvad
- cmd: |
/bin/bash -c 'echo "deb [signed-by=/usr/share/keyrings/mullvad-keyring.asc arch=$( dpkg --print-architecture )] tor+https://repository.mullvad.net/deb/stable stable main" | tee /etc/apt/sources.list.d/mullvad.list'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: download-mullvad-key
# Update package indexes for Mullvad
update-for-mullvad:
qvm.run:
- name: debian-apparmor-mullvad
- cmd: 'apt update'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: add-mullvad-repository
# Install Mullvad Browser, nautilus, and dependencies, then remove gnome-keyring
install-mullvad-browser-nautilus:
qvm.run:
- name: debian-apparmor-mullvad
- cmd: |
/bin/bash -c 'apt-get -y install mullvad-browser ffmpeg libavcodec-extra pipewire-qubes nautilus qubes-core-agent-networking zenity qubes-core-agent-nautilus && \
apt-get -y purge gnome-keyring && \
apt-get -y autoremove'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: update-for-mullvad
setup-apparmor-profiles-dkzkz:
qvm.run:
- name: debian-apparmor-mullvad
- cmd: |
/bin/bash -c 'export all_proxy=http://127.0.0.1:8082/ && \
cd /tmp && \
git clone https://codeberg.org/dkzkz/apparmor-qubes && \
cd /tmp/apparmor-qubes/stable/browser/mullvad-browser && \
mv mullv* /etc/apparmor.d/ && \
mv /tmp/apparmor-qubes/stable/file-manager/nautilus /etc/apparmor.d/ && \
mv /tmp/apparmor-qubes/stable/display-vm/Xorg /etc/apparmor.d/Xorg && \
cd /tmp/apparmor-qubes/stable/qubes-scripts/ && \
mv q* /etc/apparmor.d/ && \
cd /tmp/apparmor-qubes/stable/xdg-open/ && \
mv open /etc/apparmor.d/'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: install-mullvad-browser-nautilus
enable-mullvad-apparmor:
qvm.run:
- name: debian-apparmor-mullvad
- cmd: |
/bin/bash -c 'apparmor_parser -r /etc/apparmor.d/mullvad* && \
apparmor_parser -r /etc/apparmor.d/Xorg && \
apparmor_parser -r /etc/apparmor.d/qubes* && \
apparmor_parser -r /etc/apparmor.d/nautilus && \
apparmor_parser -r /etc/apparmor.d/open'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: setup-apparmor-profiles-dkzkz
remove-cloned-repository:
qvm.run:
- name: debian-apparmor-mullvad
- cmd: 'rm -rf /tmp/apparmor-qubes'
- user: root
- flags:
- nogui
- pass-io
- require:
- qvm: enable-mullvad-apparmor
# Shutdown template after AppArmor configuration
shutdown-mullvad-template:
qvm.shutdown:
- name: debian-apparmor-mullvad
- require:
- qvm: remove-cloned-repository
# Set template color to black
set-template-color-black:
qvm.prefs:
- name: debian-apparmor-mullvad
- label: black
- require:
- qvm: shutdown-mullvad-template
# Create AppVM from template as a disposable template
create-apparmor-mullvad-browser-dvm:
qvm.present:
- name: mullvad-browser-dvm
- template: debian-apparmor-mullvad
- label: yellow
- require:
- qvm: set-template-color-black
config-firewall:
cmd.run:
- name: |
printf "action=accept specialtarget=dns
action=accept proto=tcp dstports=443
action=accept proto=tcp dstports=80
action=drop" | qubesd-query dom0 admin.vm.firewall.Set mullvad-browser-dvm
# Set as disposable template
configure-mullvad-dvm:
qvm.prefs:
- name: mullvad-browser-dvm
- template-for-dispvms: true
- memory: 300
- maxmem: 3000
- require:
- qvm: create-apparmor-mullvad-browser-dvm
# Enable appmenus-dispvm feature and set menu-items
enable-mullvad-appmenus-dispvm:
qvm.features:
- name: mullvad-browser-dvm
- enable:
- appmenus-dispvm
- service.apparmor
- require:
- qvm: configure-mullvad-dvm
# Add mullvad-browser.desktop and xterm + hardening features to the menu
add-mullvad-browser-menu:
qvm.features:
- name: mullvad-browser-dvm
- set:
- anon-timezone: '1'
- menu-items: mullvad-browser.desktop Alacritty.desktop
- require:
- qvm: enable-mullvad-appmenus-dispvm
I provide only two files because there is more than ~ 3 500 lines for all salt files and if i have to edit the post to update the content it would be painful for me almost impossible
To get the kicksecure version only brave for now go on my repo To get the debian version go on my codeberg repo
To get the fedora version go on my codeberg repo
Technical details information
Every files have the same logic.
Update the original template , shutdown the original template clone the template
Debian and kicksecure files is using the onion repository of Qubes to update the system
Debian is using the backports repository mixed with the stable repository to get recent packages and fix
Debian andd kicksecure is using the unstable version of apparmor because of this issue
The brave hardened value and arkenfox js profile is fetched from my codeberg repo i didn't touch anything to the original files
Qubist provided a list of packages that can be removed in debian-13 i didn't removed nano , vim perl, gnupg
IMCP request will not work due to the qvm-firewall rules i applied
In debian template i removed xterm in favor of Alacritty terminal
I probably forget some details but you can inspect the salt content if details are missing i will add them later
Know issue :
Missing :
❌ A salt file to automatically update the apparmor profile from my repository to the template (i will do it soon)
❌ I didn't enable selinux for fedora to avoid any problem for users. Fedora-43 seems unstable for now nautilus doesn't launch properly. I replaced nautilus by thunar for fedora ❌ Hostname anonymize feature doesn't work on fedora i will need help for make the script work in fedora
❌ Librewolf is not in dark mode on fedora or debian i forget which one
❌ I'm not really sure if the qvm-features anon-timezone 1 is properly working in my testing i get the same issue as https://forum.qubes-os.org/t/anon-timezone-doesnt-work-for-me/39539 i enabled anon-timezone 1 for every salt file but my timezone didn't change when i tested on website like https://browserleaks.com/
Feel free to contact me on element @aatrfs76519:nope.chat for any suggestion about the guide
The curl and wget proxy The dark theme Brave browser hardened is coming from here To setup arkenfox js and ublock for firefox i used my own guide The qvm-firewall is coming from this discussion