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 Salt (management software) — Qubes OS Documentation 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 🛡 Qubes OS live mode. dom0 in RAM. Non-persistent Boot. RAM-Wipe. Protection against forensics. Tails mode. Hardening dom0. Root read‑only. Paranoid Security. Ephemeral Encryption
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/
Information needed to know :
- If you do not have enough ram the installation process will abort so don’t open too much vm at the same time
- This is possible codeberg block your Tor or VPN IP address in that case the installation will fail you will have to delete the template then restart sys-whonix or change your VPN ip and re-start the command.
- The installation packages with apt or dnf could fail because of Tor or your vpn you will have to do the steps 2 to solve the issue
- I could move the repository to somewhere else to avoid the n2 issue but this will be useless i think a lot of tor/vpn ip is blocked in famous hosting services like gitlab, github etc…
Features :
Kernel hardening from Tails & Secureblue
Selinux automatic installation & enabled
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
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
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
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
To get the fedora Selinux 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 , install packages and config inside the cloned template , shutdown the cloned template , create dvm
- Debian and kicksecure files is using the onion repository of Qubes to update the system
- To allow users to use tor in brave-browser i added the tcp 9050 ports in the firewall for the brave file
- Debian is using the backports repository mixed with the stable repository to get recent packages and fix
- Debian and 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 (90% of software doesn’t need it anyway)
- In debian template i removed xterm in favor of Alacritty terminal because xterm is ugly , slow , and hard to deal with. But you can remove alacritty in the installation process if you want
- 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)
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 Anon-timezone doesnt work for me 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
