diff --git a/pungi/phases/buildinstall.py b/pungi/phases/buildinstall.py
index 709c6bf7..50d690c7 100644
--- a/pungi/phases/buildinstall.py
+++ b/pungi/phases/buildinstall.py
@@ -27,7 +27,7 @@ from productmd.images import Image
 
 from pungi.arch import get_valid_arches
 from pungi.util import get_buildroot_rpms, get_volid, get_arch_variant_data
-from pungi.util import get_file_size, get_mtime, failable, makedirs, fusermount
+from pungi.util import get_file_size, get_mtime, failable, makedirs
 from pungi.wrappers.lorax import LoraxWrapper
 from pungi.wrappers.kojiwrapper import KojiWrapper
 from pungi.wrappers import iso
@@ -267,22 +267,15 @@ def tweak_buildinstall(compose, src, dst, arch, variant, label, volid, kickstart
     for image in images:
         if not os.path.isfile(image):
             continue
-        mount_tmp_dir = compose.mkdtemp(prefix="tweak_buildinstall")
-        # use guestmount to mount the image, which doesn't require root privileges
-        # LIBGUESTFS_BACKEND=direct: running qemu directly without libvirt
-        cmd = ["LIBGUESTFS_BACKEND=direct", "guestmount", "-a", image, "-m", "/dev/sda", mount_tmp_dir]
-        run(cmd)
 
-        for config in BOOT_CONFIGS:
-            config_path = os.path.join(tmp_dir, config)
-            config_in_image = os.path.join(mount_tmp_dir, config)
+        with iso.mount(image, logger=compose._logger) as mount_tmp_dir:
+            for config in BOOT_CONFIGS:
+                config_path = os.path.join(tmp_dir, config)
+                config_in_image = os.path.join(mount_tmp_dir, config)
 
-            if os.path.isfile(config_in_image):
-                cmd = ["cp", "-v", "--remove-destination", config_path, config_in_image]
-                run(cmd)
-
-        fusermount(mount_tmp_dir)
-        shutil.rmtree(mount_tmp_dir)
+                if os.path.isfile(config_in_image):
+                    cmd = ["cp", "-v", "--remove-destination", config_path, config_in_image]
+                    run(cmd)
 
     # HACK: make buildinstall files world readable
     run("chmod -R a+rX %s" % pipes.quote(tmp_dir))
diff --git a/pungi/wrappers/iso.py b/pungi/wrappers/iso.py
index 9b1a585b..2ee9c79d 100644
--- a/pungi/wrappers/iso.py
+++ b/pungi/wrappers/iso.py
@@ -18,8 +18,10 @@ import os
 import sys
 import pipes
 from fnmatch import fnmatch
+import contextlib
 
 from kobo.shortcuts import force_list, relative_path, run
+from pungi import util
 
 
 # HACK: define cmp in python3
@@ -392,3 +394,20 @@ def cmp_graft_points(x, y):
         return 1
 
     return cmp(x, y)
+
+
+@contextlib.contextmanager
+def mount(image, logger=None):
+    """Mount an image and make sure it's unmounted.
+
+    The yielded path will only be valid in the with block and is removed once
+    the image is unmounted.
+    """
+    # use guestmount to mount the image, which doesn't require root privileges
+    # LIBGUESTFS_BACKEND=direct: running qemu directly without libvirt
+    with util.temp_dir(prefix='iso-mount-') as mount_dir:
+        run(["LIBGUESTFS_BACKEND=direct", "guestmount", "-a", image, "-m", "/dev/sda", mount_dir])
+        try:
+            yield mount_dir
+        finally:
+            util.fusermount(mount_dir, logger=logger)
diff --git a/tests/test_iso_wrapper.py b/tests/test_iso_wrapper.py
index 6c2dfd20..18d15623 100644
--- a/tests/test_iso_wrapper.py
+++ b/tests/test_iso_wrapper.py
@@ -37,3 +37,25 @@ class TestIsoUtils(unittest.TestCase):
         self.assertEqual(mock_run.call_args_list,
                          [mock.call(['/usr/bin/checkisomd5', '--md5sumonly', 'dummy.iso'])])
         self.assertGreater(len(logger.mock_calls), 0)
+
+    @mock.patch('pungi.util.run_unmount_cmd')
+    @mock.patch('pungi.wrappers.iso.run')
+    def test_mount_iso(self, mock_run, mock_unmount):
+        with iso.mount('dummy') as temp_dir:
+            self.assertTrue(os.path.isdir(temp_dir))
+        self.assertEqual(len(mock_run.call_args_list), 1)
+        self.assertEqual(len(mock_unmount.call_args_list), 1)
+        self.assertFalse(os.path.isdir(temp_dir))
+
+    @mock.patch('pungi.util.run_unmount_cmd')
+    @mock.patch('pungi.wrappers.iso.run')
+    def test_mount_iso_always_unmounts(self, mock_run, mock_unmount):
+        try:
+            with iso.mount('dummy') as temp_dir:
+                self.assertTrue(os.path.isdir(temp_dir))
+                raise RuntimeError()
+        except RuntimeError:
+            pass
+        self.assertEqual(len(mock_run.call_args_list), 1)
+        self.assertEqual(len(mock_unmount.call_args_list), 1)
+        self.assertFalse(os.path.isdir(temp_dir))