diff --git a/Dockerfile b/Dockerfile
index 80c008a2d..329171970 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -38,3 +38,12 @@ RUN chmod g=u /etc/passwd
 # run as `builder` user
 USER builder
 ENTRYPOINT ["/usr/bin/dumb-init", "/usr/bin/coreos-assembler"]
+
+# Constellation start
+USER root
+
+RUN dnf -y update && \
+    dnf install -y veritysetup && \
+    dnf clean all
+
+USER builder
+# Constellation end
diff --git a/mantle/platform/qemu.go b/mantle/platform/qemu.go
index d4d5eafa7..20f156315 100644
--- a/mantle/platform/qemu.go
+++ b/mantle/platform/qemu.go
@@ -449,7 +449,7 @@ type QemuBuilder struct {
 func NewQemuBuilder() *QemuBuilder {
 	ret := QemuBuilder{
 		Firmware:  "bios",
-		Swtpm:     true,
+		Swtpm:     false,
 		Pdeathsig: true,
 		Argv:      []string{},
 	}
diff --git a/src/cosalib/qemuvariants.py b/src/cosalib/qemuvariants.py
index 8d57803b1..cdad6aeba 100644
--- a/src/cosalib/qemuvariants.py
+++ b/src/cosalib/qemuvariants.py
@@ -81,7 +81,7 @@ VARIANTS = {
         "image_suffix": "tar.gz",
         "gzip": True,
         "convert_options": {
-            '-o': 'preallocation=off'
+            '-o': 'preallocation=full'
         },
         "tar_members": [
             "disk.raw"
diff --git a/src/create_disk.sh b/src/create_disk.sh
index 61d52cd96..fa3fe1655 100755
--- a/src/create_disk.sh
+++ b/src/create_disk.sh
@@ -188,6 +188,7 @@ set -x
 SDPART=1
 BOOTPN=3
 ROOTPN=4
+VERITYHASHPN=5
 # Make the size relative
 if [ "${rootfs_size}" != "0" ]; then
     rootfs_size="+${rootfs_size}"
@@ -201,7 +202,8 @@ case "$arch" in
         -n 1:0:+1M -c 1:BIOS-BOOT -t 1:21686148-6449-6E6F-744E-656564454649 \
         -n ${EFIPN}:0:+127M -c ${EFIPN}:EFI-SYSTEM -t ${EFIPN}:C12A7328-F81F-11D2-BA4B-00A0C93EC93B \
         -n ${BOOTPN}:0:+384M -c ${BOOTPN}:boot \
-        -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4
+        -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root_raw -A ${ROOTPN}:set:60 -A ${ROOTPN}:set:63 -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
+        -n ${VERITYHASHPN}:0:+32M -c ${VERITYHASHPN}:root_verity
         sgdisk -p "$disk"
         ;;
     aarch64)
@@ -212,7 +214,8 @@ case "$arch" in
         -n ${RESERVEDPN}:0:+1M -c ${RESERVEDPN}:reserved -t ${RESERVEDPN}:8DA63339-0007-60C0-C436-083AC8230908 \
         -n ${EFIPN}:0:+127M -c ${EFIPN}:EFI-SYSTEM -t ${EFIPN}:C12A7328-F81F-11D2-BA4B-00A0C93EC93B \
         -n ${BOOTPN}:0:+384M -c ${BOOTPN}:boot \
-        -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4
+        -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root_raw -A ${ROOTPN}:set:60 -A ${ROOTPN}:set:63 -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
+        -n ${VERITYHASHPN}:0:+32M -c ${VERITYHASHPN}:root_verity
         sgdisk -p "$disk"
         ;;
     s390x)
@@ -222,6 +225,7 @@ case "$arch" in
                 -n ${SDPART}:0:+200M -c ${SDPART}:se -t ${SDPART}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
                 -n ${BOOTPN}:0:+384M -c ${BOOTPN}:boot \
-                -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4
+                -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root_raw -A ${ROOTPN}:set:60 -A ${ROOTPN}:set:63 -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
+                -n ${VERITYHASHPN}:0:+32M -c ${VERITYHASHPN}:root_verity
         else
             # NB: in the bare metal case when targeting ECKD DASD disks, this
             # partition table is not what actually gets written to disk in the end:
@@ -231,7 +235,8 @@ case "$arch" in
                 -U "${uninitialized_gpt_uuid}" \
                 -n ${BOOTPN}:0:+384M -c ${BOOTPN}:boot \
-                -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4
+                -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root_raw -A ${ROOTPN}:set:60 -A ${ROOTPN}:set:63 -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
+                -n ${VERITYHASHPN}:0:+32M -c ${VERITYHASHPN}:root_verity
         fi
         sgdisk -p "$disk"
         ;;
     ppc64le)
@@ -243,7 +248,8 @@ case "$arch" in
         -n ${PREPPN}:0:+4M -c ${PREPPN}:PowerPC-PReP-boot -t ${PREPPN}:9E1A2D38-C612-4316-AA26-8B49521E5A8B \
         -n ${RESERVEDPN}:0:+1M -c ${RESERVEDPN}:reserved -t ${RESERVEDPN}:8DA63339-0007-60C0-C436-083AC8230908 \
         -n ${BOOTPN}:0:+384M -c ${BOOTPN}:boot \
-        -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4
+        -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root_raw -A ${ROOTPN}:set:60 -A ${ROOTPN}:set:63 -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 \
+        -n ${VERITYHASHPN}:0:+32M -c ${VERITYHASHPN}:root_verity
         sgdisk -p "$disk"
         ;;
 esac
@@ -251,10 +257,11 @@ esac
 udevtrig

 zipl_dev="${disk}${SDPART}"
 boot_dev="${disk}${BOOTPN}"
 root_dev="${disk}${ROOTPN}"
+hash_dev="${disk}${VERITYHASHPN}"

 bootargs=
 # If the bootfs_metadata_csum_seed image.yaml knob is set to true then
 # we'll enable the metadata_csum_seed filesystem feature. This is
 # gated behind an image.yaml knob because support for this feature
@@ -305,17 +315,17 @@ case "${rootfs_type}" in
         # And reflinks are *very* useful for the container stack with overlayfs (and in general).
         # So basically, we're choosing performance over half-implemented security.
         # Eventually, we'd like both - once XFS gains verity (probably not too hard),
         # we could unconditionally enable it there.
         # shellcheck disable=SC2086
-        mkfs.ext4 -b "$(getconf PAGE_SIZE)" -O verity -L root "${root_dev}" -U "${rootfs_uuid}" ${rootfs_args}
+        mkfs.ext4 -b "$(getconf PAGE_SIZE)" -O verity -L root_raw "${root_dev}" -U "${rootfs_uuid}" ${rootfs_args}
         ;;
     btrfs)
         # shellcheck disable=SC2086
-        mkfs.btrfs -L root "${root_dev}" -U "${rootfs_uuid}" ${rootfs_args}
+        mkfs.btrfs -L root_raw "${root_dev}" -U "${rootfs_uuid}" ${rootfs_args}
         ;;
     xfs|"")
         # shellcheck disable=SC2086
-        mkfs.xfs "${root_dev}" -L root -m reflink=1 -m uuid="${rootfs_uuid}" ${rootfs_args}
+        mkfs.xfs "${root_dev}" -L root_raw -m reflink=1 -m uuid="${rootfs_uuid}" -s "size=4096" ${rootfs_args}
         ;;
     *)
         echo "Unknown rootfs_type: $rootfs_type" 1>&2
@@ -536,11 +428,10 @@ s390x)
 esac

 ostree config --repo $rootfs/ostree/repo set sysroot.bootloader "${bootloader_backend}"
-# Opt-in to https://github.com/ostreedev/ostree/pull/1767 AKA
-# https://github.com/ostreedev/ostree/issues/1265
-ostree config --repo $rootfs/ostree/repo set sysroot.readonly true
+# constellation: setting readonly to false interestingly stops ostree from remounting anything as rw
+ostree config --repo $rootfs/ostree/repo set sysroot.readonly false
 # enable support for GRUB password
 if [ "${bootloader_backend}" = "none" ]; then
     ostree config --repo $rootfs/ostree/repo set sysroot.bls-append-except-default 'grub_users=""'
 fi

@@ -542,15 +548,16 @@ s390x)
 # enable support for GRUB password
 if [ "${bootloader_backend}" = "none" ]; then
     ostree config --repo $rootfs/ostree/repo set sysroot.bls-append-except-default 'grub_users=""'
 fi

-touch $rootfs/boot/ignition.firstboot
+# constellation: do not enable ignition on first boot
+# touch $rootfs/boot/ignition.firstboot

 # Finally, add the immutable bit to the physical root; we don't
 # expect people to be creating anything there.  A use case for
 # OSTree in general is to support installing *inside* the existing
 # root of a deployed OS, so OSTree doesn't do this by default, but
 # we have no reason not to enable it here.  Administrators should
 # generally expect that state data is in /etc and /var; if anything
 # else is in /sysroot it's probably by accident.
 chattr +i $rootfs
@@ -557,10 +564,21 @@ chattr +i $rootfs

 fstrim -a -v
 # Ensure the filesystem journals are flushed
-for fs in $rootfs/boot $rootfs; do
+mount -o remount,ro $rootfs/boot
+for fs in $rootfs; do
     mount -o remount,ro $fs
     xfs_freeze -f $fs
 done
 umount -R $rootfs

 rmdir $rootfs
+
+# setup dm-verity and disable audit logs
+veritysetup_out=$(veritysetup format "${root_dev}" "${hash_dev}")
+verity_root_hash=$(echo "${veritysetup_out}" | grep 'Root hash:' | sed --expression='s/Root hash:\s*//g')
+bootfs_mount=/tmp/boot
+rm -rf "${bootfs_mount}"
+mkdir -p "${bootfs_mount}"
+mount "${disk}${BOOTPN}" "${bootfs_mount}"
+sed -i -e "s/^options .*/\0 audit=0 verity.sysroot=${verity_root_hash}/g" "${bootfs_mount}/loader.1/entries/ostree-1-fedora-coreos.conf"
+umount "${bootfs_mount}"
diff --git a/src/gf-fsck b/src/gf-fsck
index 2d07eca2a..46c137672 100755
--- a/src/gf-fsck
+++ b/src/gf-fsck
@@ -28,7 +28,7 @@ for pt in $partitions; do
 done

 # And fsck the main rootfs
-root=$(coreos_gf findfs-label root)
+root=$(coreos_gf findfs-label root_raw)
 coreos_gf debug sh "fsck.xfs -f -n ${root}"

 coreos_gf_shutdown
diff --git a/src/libguestfish.sh b/src/libguestfish.sh
index 82cfcf86e..635fb9eaa 100755
--- a/src/libguestfish.sh
+++ b/src/libguestfish.sh
@@ -64,7 +64,7 @@ coreos_gf_run_mount() {
         shift
     fi
     coreos_gf_run "$@"
-    root=$(coreos_gf findfs-label root)
+    root=$(coreos_gf findfs-label root_raw)
     coreos_gf ${mntarg} "${root}" /
     local boot
     boot=$(coreos_gf findfs-label boot)
diff --git a/src/vmdeps.txt b/src/vmdeps.txt
index 6c6045840..ddbece267 100644
--- a/src/vmdeps.txt
+++ b/src/vmdeps.txt
@@ -27,5 +27,8 @@ gdisk xfsprogs e2fsprogs dosfstools btrfs-progs

 # needed for basic CA support
 ca-certificates

 tar
+
+# dm-verity
+veritysetup
