diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Terragrunt.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Terragrunt.kt
new file mode 100644
index 0000000..784a387
--- /dev/null
+++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Terragrunt.kt
@@ -0,0 +1,54 @@
+package org.domaindrivenarchitecture.provs.desktop.infrastructure
+
+import org.domaindrivenarchitecture.provs.framework.core.Prov
+import org.domaindrivenarchitecture.provs.framework.core.ProvResult
+import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.*
+import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.checkCommand
+import org.domaindrivenarchitecture.provs.framework.ubuntu.web.base.downloadFromURL
+
+fun Prov.installTerragrunt(
+    version: String = "0.72.6",
+    enforceVersion: Boolean = false,
+    sha256sum: String = "df63a41576b8b4129b498da5b698b5792a5a228ea5012bbecdcbe49d4d662be3"
+) = taskWithResult {
+    if (checkCommand("terragrunt") && !enforceVersion) {
+        return@taskWithResult ProvResult(true)
+    }
+
+    if (checkTerragruntVersion(version)) {
+        return@taskWithResult ProvResult(true, out = "Terragrunt is already installed.")
+    }
+
+    val downloadUrl = "https://github.com/gruntwork-io/terragrunt/releases/download/v$version/terragrunt_linux_amd64"
+    val filename = "terragrunt_linux_amd64"
+    val target = "${userHome()}tmp"
+    val result = downloadFromURL(
+        downloadUrl,
+        filename,
+        target,
+        sha256sum = sha256sum
+    )
+
+    if (result.success) {
+        cmd("sudo cp $target/$filename /usr/local/bin/terragrunt", sudo = true)
+        cmd("chmod 755 /usr/local/bin/terragrunt", sudo = true)
+        cmd("chown root /usr/local/bin/terragrunt", sudo = true)
+        cmd("chgrp root /usr/local/bin/terragrunt", sudo = true)
+        deleteFile("$target/$filename")
+        configureBashForUser()
+        // check and assert installation
+        addResult(checkTerragruntVersion(version), info = "Terragrunt version $version has been installed.")
+    } else {
+        return@taskWithResult ProvResult(false, err = "Terragrunt $version could not be downloaded and installed. " + result.err)
+    }
+}
+
+fun Prov.checkTerragruntVersion(version: String): Boolean {
+    val installedTerragruntVersion = terragruntVersion()
+    return installedTerragruntVersion != null && installedTerragruntVersion.startsWith("terragrunt version v" + version)
+}
+
+internal fun Prov.terragruntVersion(): String? {
+    val result = cmdNoEval("terragrunt --version", sudo = true)
+    return if (!result.success) null else result.out
+}
\ No newline at end of file
diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/TerragruntKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/TerragruntKtTest.kt
new file mode 100644
index 0000000..98215da
--- /dev/null
+++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/TerragruntKtTest.kt
@@ -0,0 +1,23 @@
+package org.domaindrivenarchitecture.provs.desktop.infrastructure
+
+import org.domaindrivenarchitecture.provs.test.defaultTestContainer
+import org.domaindrivenarchitecture.provs.test.tags.ExtensiveContainerTest
+import org.junit.jupiter.api.Assertions.assertTrue
+
+class TerragruntKtTest {
+
+  @ExtensiveContainerTest
+ fun installTerragrunt() {
+  // given
+  val prov = defaultTestContainer()
+
+  // when
+  val res = prov.task {
+   installOpentofu()
+   installOpentofu()  // check repeatability
+  }
+
+  // then
+  assertTrue(res.success)
+ }
+}