diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b8e8cad95f77c2d16a40b92b600dac0d708fc10c..8c8426af7637f8080a5d038ba161d5cb565589e7 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -57,10 +57,13 @@ stages:
   - release
   - cleanup
 
-.opentofu-versions:
+.image-matrix:
   parallel:
     matrix:
       - OPENTOFU_VERSION: !reference [.data, supported_versions]
+        GITLAB_OPENTOFU_BASE_IMAGE_OS:
+          - 'alpine'
+          - 'debian'
 
 variables:
   # OpenTofu variables
@@ -68,9 +71,8 @@ variables:
 
   # OpenTofu image build variables:
   PLATFORMS: linux/amd64,linux/arm64
-  BASE_IMAGE: "alpine:3.20.3"
   GITLAB_OPENTOFU_IMAGE_BASE: "$CI_REGISTRY_IMAGE/internal"
-  GITLAB_OPENTOFU_IMAGE_NAME: "$GITLAB_OPENTOFU_IMAGE_BASE/gitlab-opentofu:$CI_COMMIT_SHA-opentofu$OPENTOFU_VERSION"
+  GITLAB_OPENTOFU_IMAGE_NAME: "$GITLAB_OPENTOFU_IMAGE_BASE/gitlab-opentofu:$CI_COMMIT_SHA-opentofu$OPENTOFU_VERSION-$GITLAB_OPENTOFU_BASE_IMAGE_OS"
 
 check-semantic-version:
   stage: .pre
@@ -83,17 +85,17 @@ check-semantic-version:
     - echo -n "$CI_COMMIT_TAG" | ./.gitlab/scripts/check-semantic-version.sh
 
 gitlab-opentofu-image:build:
-  extends: .opentofu-versions
+  extends: .image-matrix
   stage: build
   image: quay.io/containers/buildah:v1.37.1
   before_script:
     - buildah login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
   script:
+    - echo "Building $GITLAB_OPENTOFU_IMAGE_NAME"
     - buildah build
       --platform "$PLATFORMS"
-      --build-arg BASE_IMAGE=$BASE_IMAGE
       --build-arg OPENTOFU_VERSION=$OPENTOFU_VERSION
-      --file Dockerfile
+      --file Dockerfile.$GITLAB_OPENTOFU_BASE_IMAGE_OS
       --jobs 2
       --manifest "$GITLAB_OPENTOFU_IMAGE_NAME"
       .
@@ -101,7 +103,7 @@ gitlab-opentofu-image:build:
   rules:
     - if: $CI_COMMIT_TAG
     - changes:
-        - Dockerfile
+        - Dockerfile*
         - .dockerignore
         - opentofu_versions.yaml
         - .gitlab-ci.yml
@@ -163,26 +165,23 @@ shellcheck:
 #     - if: $CI_COMMIT_TAG
 #     - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
 
-gitlab-opentofu-image:deploy:
+.gitlab-opentofu-image:deploy:base:
   stage: deploy
   image:
     name: gcr.io/go-containerregistry/crane:debug
     entrypoint: [""]
+  variables:
+    GITLAB_OPENTOFU_BASE_IMAGE_OS: $RELEASE_BASE_IMAGE_OS
   before_script:
     - crane auth login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
-  script:
     # OCI image tags are not compatible with semver, specifically the build metadata part
     # indicated with a `+` sign, see https://github.com/distribution/distribution/issues/1201
     # We use a dash `-` here, instead of the `+`.
     # This may be problematic, because it indicates a semver prerelease.
     - export RELEASE_IMAGE_NAME="$CI_REGISTRY_IMAGE/gitlab-opentofu"
-    - export RELEASE_IMAGE="${RELEASE_IMAGE_NAME}:${RELEASE_VERSION}${RELEASE_OPENTOFU_VERSION:+-opentofu$RELEASE_OPENTOFU_VERSION}"
+    - export RELEASE_IMAGE="${RELEASE_IMAGE_NAME}:${RELEASE_VERSION}${RELEASE_OPENTOFU_VERSION:+-opentofu$RELEASE_OPENTOFU_VERSION}${RELEASE_BASE_IMAGE_OS:+-$RELEASE_BASE_IMAGE_OS}"
+    - 'echo "base image OS: $GITLAB_OPENTOFU_BASE_IMAGE_OS"'
     - echo "Deploying $GITLAB_OPENTOFU_IMAGE_NAME as $RELEASE_IMAGE"
-    - crane copy "$GITLAB_OPENTOFU_IMAGE_NAME" "$RELEASE_IMAGE"
-    - 'echo "- \`$RELEASE_IMAGE\` (digest: \`$(crane digest $RELEASE_IMAGE)\`)" > image$CI_JOB_ID.md'
-  artifacts:
-    paths:
-      - 'image*.md'
   parallel:
     # OPENTOFU_VERSION: opentofu version to release in the job (from gitlab-opentofu-image:build)
     # RELEASE_VERSION:  Tag base for the release image
@@ -192,16 +191,44 @@ gitlab-opentofu-image:deploy:
         OPENTOFU_VERSION: !reference [.data, supported_versions]
         RELEASE_VERSION: $CI_COMMIT_TAG
         RELEASE_OPENTOFU_VERSION: $OPENTOFU_VERSION
+        RELEASE_BASE_IMAGE_OS: ['alpine', 'debian']
       - # :latest-opentofu{opentofu-version}
         OPENTOFU_VERSION: !reference [.data, supported_versions]
         RELEASE_VERSION: latest
         RELEASE_OPENTOFU_VERSION: $OPENTOFU_VERSION
+        RELEASE_BASE_IMAGE_OS: ['alpine', 'debian']
       - # :{commit-tag|latest}{-opentofulatest|}
         OPENTOFU_VERSION: $LATEST_OPENTOFU_VERSION
         RELEASE_VERSION: ["${CI_COMMIT_TAG}", latest]
         RELEASE_OPENTOFU_VERSION: ["", latest]
+        RELEASE_BASE_IMAGE_OS: ['alpine', 'debian']
+
+gitlab-opentofu-image:deploy:
+  extends: ['.gitlab-opentofu-image:deploy:base']
+  script:
+    - crane copy "$GITLAB_OPENTOFU_IMAGE_NAME" "$RELEASE_IMAGE"
+    - export image_digest="$(crane digest $RELEASE_IMAGE)"
+    - 'echo "- \`$RELEASE_IMAGE\` (digest: \`$image_digest\`)" > image$CI_JOB_ID.md'
+  artifacts:
+    paths:
+      - 'image*.md'
+  rules:
+    - if: $CI_COMMIT_TAG
+
+gitlab-opentofu-image:deploy:dry-run:
+  extends: ['.gitlab-opentofu-image:deploy:base']
+  needs: ['gitlab-opentofu-image:build']
+  script:
+    - echo "dry run"
   rules:
     - if: $CI_COMMIT_TAG
+      when: never
+    - changes:
+        - Dockerfile*
+        - .dockerignore
+        - opentofu_versions.yaml
+        - .gitlab-ci.yml
+        - src/**/*
 
 # If the pipeline is for a new tag with a semantic version, and all previous jobs succeed,
 # create the release.
diff --git a/.gitlab/README.md.template b/.gitlab/README.md.template
index 849b65d35f593fc508ef7d840b22ca3c97292f0e..1fc866f7a796b51c175dc2601a35f4b05462e969 100644
--- a/.gitlab/README.md.template
+++ b/.gitlab/README.md.template
@@ -97,6 +97,20 @@ fmt:
 ...
 ```
 
+### OpenTofu Version
+
+The OpenTofu version can be specified with the `opentofu_version` input.
+More details can be found [here](#available-opentofu-versions).
+
+### Base Image OS
+
+The GitLab OpenTofu images come in multiple base image variants:
+
+- `alpine` (default)
+- `debian`
+
+The base image OS can be specified with the `base_os` input.
+
 ### GitLab-managed Terraform state backend
 
 This component - by leveraging the [`gitlab-tofu`](src/gitlab-tofu.sh) CLI internally -
@@ -263,16 +277,21 @@ Due to the limitations described in https://gitlab.com/gitlab-org/gitlab/-/issue
 it's currently required to provide the component version in the `component` include field
 and as the `version` input. Check out the [Usage](#Usage) section for examples.
 
+There are `alpine` and `debian` variants available.
+
 Each component release deploys the following images:
 
-- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-opentofu<OPENTOFU_VERSION>`
-- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-opentofu`
+- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-opentofu<OPENTOFU_VERSION>-<OS_VARIANT>`
+- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-opentofu-<OS_VARIANT>`
   - Includes the latest stable OpenTofu version at the time of releasing the component
-- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>`
+- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-<OS_VARIANT>`
   - Includes the latest stable OpenTofu version at the time of releasing the component
 
-In the above examples `<VERSION>` references the component version and `<OPENTOFU_VERSION>`
-an OpenTofu release, from [here](https://github.com/opentofu/opentofu/releases).
+In the above examples `<VERSION>` references the component version, `<OPENTOFU_VERSION>`
+an OpenTofu release, from [here](https://github.com/opentofu/opentofu/releases) and
+`OS_VARIANT` either `alpine` or `debian`.
+
+The release notes contain a full list of images deployed to the registry.
 
 *Note: unfortunately, these image versions are not SemVer compatible,
 because `-` indicates a prerelease (which they are not in this case).
diff --git a/Dockerfile b/Dockerfile.alpine
similarity index 96%
rename from Dockerfile
rename to Dockerfile.alpine
index 75f8f167935318bb33038a639b61d7e15d4204a6..65d8090d978344126f0c342c8e4b34f073351196 100644
--- a/Dockerfile
+++ b/Dockerfile.alpine
@@ -1,4 +1,4 @@
-ARG BASE_IMAGE
+ARG BASE_IMAGE=alpine:3.20.3
 
 FROM $BASE_IMAGE
 
diff --git a/Dockerfile.debian b/Dockerfile.debian
new file mode 100644
index 0000000000000000000000000000000000000000..aa12b49c1f085edd6fb7cbf7a7faafa17f622950
--- /dev/null
+++ b/Dockerfile.debian
@@ -0,0 +1,48 @@
+ARG BASE_IMAGE=debian:12.7
+
+FROM $BASE_IMAGE
+
+ARG TARGETARCH
+
+RUN apt-get update && apt-get install -y \
+  curl \
+  wget \
+  git \
+  jq \
+  openssh-client \
+  unzip \
+  && rm -rf /var/lib/apt/lists/*
+
+# NOTE: cosign is not yet available in the debian apt sources
+ARG COSIGN_VERSION=2.4.0
+WORKDIR /tmp
+RUN wget https://github.com/sigstore/cosign/releases/download/v${COSIGN_VERSION}/cosign_${COSIGN_VERSION}_${TARGETARCH}.deb && \
+    dpkg -i *.deb && \
+    rm -f /tmp/*.deb
+
+# NOTE: glab is not yet available in the debian apt sources
+ARG GLAB_VERSION=1.46.1
+WORKDIR /tmp
+RUN if [ "${TARGETARCH}" = "amd64" ]; then hack_glab_arch="x86_64"; else hack_glab_arch="${TARGETARCH}"; fi && \
+    echo "arch=$hack_glab_arch" && \
+    wget https://gitlab.com/gitlab-org/cli/-/releases/v${GLAB_VERSION}/downloads/glab_${GLAB_VERSION}_Linux_${hack_glab_arch}.deb && \
+    dpkg -i *.deb && \
+    rm -f /tmp/*.deb
+
+# Install OpenTofu using the installer script in standalone mode
+# see https://opentofu.org/docs/intro/install/standalone
+# We may want to switch to installing manually from GitHub and verifying signature
+ARG OPENTOFU_VERSION
+RUN curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh && \
+    chmod +x install-opentofu.sh && \
+    ./install-opentofu.sh --install-method standalone --opentofu-version "${OPENTOFU_VERSION}" && \
+    rm ./install-opentofu.sh && \
+    rm -rf /tmp/* && \
+    tofu --version
+
+WORKDIR /
+
+COPY --chmod=755 src/gitlab-tofu.sh /usr/bin/gitlab-tofu
+
+# Override ENTRYPOINT
+ENTRYPOINT []
diff --git a/README.md b/README.md
index d4d5a3805cad21e2ee42b48f0d9f68e973e24be7..44eb77f9a15cf448cf94fedf902a511674b04e53 100644
--- a/README.md
+++ b/README.md
@@ -99,6 +99,20 @@ fmt:
 ...
 ```
 
+### OpenTofu Version
+
+The OpenTofu version can be specified with the `opentofu_version` input.
+More details can be found [here](#available-opentofu-versions).
+
+### Base Image OS
+
+The GitLab OpenTofu images come in multiple base image variants:
+
+- `alpine` (default)
+- `debian`
+
+The base image OS can be specified with the `base_os` input.
+
 ### GitLab-managed Terraform state backend
 
 This component - by leveraging the [`gitlab-tofu`](src/gitlab-tofu.sh) CLI internally -
@@ -280,16 +294,21 @@ Due to the limitations described in https://gitlab.com/gitlab-org/gitlab/-/issue
 it's currently required to provide the component version in the `component` include field
 and as the `version` input. Check out the [Usage](#Usage) section for examples.
 
+There are `alpine` and `debian` variants available.
+
 Each component release deploys the following images:
 
-- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-opentofu<OPENTOFU_VERSION>`
-- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-opentofu`
+- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-opentofu<OPENTOFU_VERSION>-<OS_VARIANT>`
+- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-opentofu-<OS_VARIANT>`
   - Includes the latest stable OpenTofu version at the time of releasing the component
-- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>`
+- `$CI_TEMPLATE_REGISTRY_HOST/components/opentofu/gitlab-opentofu:<VERSION>-<OS_VARIANT>`
   - Includes the latest stable OpenTofu version at the time of releasing the component
 
-In the above examples `<VERSION>` references the component version and `<OPENTOFU_VERSION>`
-an OpenTofu release, from [here](https://github.com/opentofu/opentofu/releases).
+In the above examples `<VERSION>` references the component version, `<OPENTOFU_VERSION>`
+an OpenTofu release, from [here](https://github.com/opentofu/opentofu/releases) and
+`OS_VARIANT` either `alpine` or `debian`.
+
+The release notes contain a full list of images deployed to the registry.
 
 *Note: unfortunately, these image versions are not SemVer compatible,
 because `-` indicates a prerelease (which they are not in this case).
diff --git a/templates/apply.yml b/templates/apply.yml
index e19771e3a1deb919facca40439b3b00518022c0d..bf123ad3ab5098055709c6182d041c9ddc555c4a 100644
--- a/templates/apply.yml
+++ b/templates/apply.yml
@@ -15,6 +15,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -91,6 +99,6 @@ spec:
     TF_APPLY_NO_PLAN: $[[ inputs.no_plan ]]
     TF_PLAN_NAME: $[[ inputs.plan_name ]]
   image:
-    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]'
+    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]'
   script:
     - gitlab-tofu apply
diff --git a/templates/custom-command.yml b/templates/custom-command.yml
index 3acee3604f5514f90901d0cc3634234e70507d45..2a9bf3542396b5431dea11bef02c58539a8ab080 100644
--- a/templates/custom-command.yml
+++ b/templates/custom-command.yml
@@ -15,6 +15,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -70,7 +78,7 @@ spec:
     __CACHE_KEY_HACK: "$[[ inputs.root_dir ]]"
     TF_ROOT: $[[ inputs.root_dir ]]
   image:
-    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]'
+    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]'
   script:
     - gitlab-tofu $[[ inputs.command ]]
 
diff --git a/templates/destroy.yml b/templates/destroy.yml
index fb6749700802e55a20e4abfb9b3cc4a949996f99..66a17a757711dd24333d9657029c00c6f984cea5 100644
--- a/templates/destroy.yml
+++ b/templates/destroy.yml
@@ -15,6 +15,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -90,6 +98,6 @@ spec:
     TF_APPLY_NO_PLAN: $[[ inputs.no_plan ]]
     TF_PLAN_NAME: $[[ inputs.plan_name ]]
   image:
-    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]'
+    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]'
   script:
     - gitlab-tofu apply -destroy
diff --git a/templates/fmt.yml b/templates/fmt.yml
index 6ab765aeec1ff613f24255aa930b78111d8f2595..2ad408bd018a92459fe798ddfaded397cf4a9f11 100644
--- a/templates/fmt.yml
+++ b/templates/fmt.yml
@@ -15,6 +15,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -78,6 +86,6 @@ spec:
     __CACHE_KEY_HACK: "$[[ inputs.root_dir ]]"
     TF_ROOT: $[[ inputs.root_dir ]]
   image:
-    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]'
+    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]'
   script:
     - gitlab-tofu fmt
diff --git a/templates/full-pipeline.yml b/templates/full-pipeline.yml
index e57a17737b153d52925c1cc63ff581a818f61151..f2637c1dfcd866c59df06a0b4456627a408b5f91 100644
--- a/templates/full-pipeline.yml
+++ b/templates/full-pipeline.yml
@@ -24,6 +24,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -84,6 +92,7 @@ include:
       as: 'fmt'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -93,6 +102,7 @@ include:
       as: 'validate'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -103,6 +113,7 @@ include:
       as: 'test'
       stage: $[[ inputs.stage_test ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -116,6 +127,7 @@ include:
       as: 'plan'
       stage: $[[ inputs.stage_build ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -127,6 +139,7 @@ include:
       as: 'apply'
       stage: $[[ inputs.stage_deploy ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -138,6 +151,7 @@ include:
       as: 'destroy'
       stage: $[[ inputs.stage_cleanup ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
diff --git a/templates/graph.yml b/templates/graph.yml
index d39cf4f068420afa0b09a30a80894544d1445807..2ff3da0f3a2c4f65e620a7e7982224ec5bafece8 100644
--- a/templates/graph.yml
+++ b/templates/graph.yml
@@ -15,6 +15,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -76,7 +84,7 @@ spec:
     TF_ROOT: $[[ inputs.root_dir ]]
     TF_STATE_NAME: $[[ inputs.state_name ]]
   image:
-    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]'
+    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]'
   script:
     - gitlab-tofu graph > "$[[ inputs.graph_file ]]"
   artifacts:
diff --git a/templates/job-templates.yml b/templates/job-templates.yml
index 78071d110d87177eab4e0b8b6ec2bce5ec7dad55..496c6d2ae9d85f7d6e86e25b9d5927064b926898 100644
--- a/templates/job-templates.yml
+++ b/templates/job-templates.yml
@@ -24,6 +24,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -84,6 +92,7 @@ include:
       as: '$[[ inputs.job_name_prefix ]]fmt'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -93,6 +102,7 @@ include:
       as: '$[[ inputs.job_name_prefix ]]validate'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -103,6 +113,7 @@ include:
       as: '$[[ inputs.job_name_prefix ]]graph'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -112,6 +123,7 @@ include:
       as: '$[[ inputs.job_name_prefix ]]test'
       stage: $[[ inputs.stage_test ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -122,6 +134,7 @@ include:
       as: '$[[ inputs.job_name_prefix ]]plan'
       stage: $[[ inputs.stage_build ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -132,6 +145,7 @@ include:
       as: '$[[ inputs.job_name_prefix ]]apply'
       stage: $[[ inputs.stage_deploy ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -143,6 +157,7 @@ include:
       as: '$[[ inputs.job_name_prefix ]]destroy'
       stage: $[[ inputs.stage_cleanup ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
diff --git a/templates/plan.yml b/templates/plan.yml
index 7eaeb8a219d139b3423b51c69424aeef94ee3d0f..8ceba23462d92864b2c0aceb2b30fb5c58a04809 100644
--- a/templates/plan.yml
+++ b/templates/plan.yml
@@ -15,6 +15,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -100,7 +108,7 @@ spec:
     TF_STATE_NAME: $[[ inputs.state_name ]]
     TF_PLAN_NAME: $[[ inputs.plan_name ]]
   image:
-    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]'
+    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]'
   script:
     - "args=\"\"\nif [ \"$[[ inputs.destroy ]]\" == \"true\" ]; then \n  echo \"Planning for a destroy\"\n  args=\"-destroy\"\nfi\n"
     - gitlab-tofu plan $args
diff --git a/templates/test.yml b/templates/test.yml
index b8384016820c2335fb205b1408afb373277ae65a..231b09fe7f95187d77af5ca3a1d88e131eea4117 100644
--- a/templates/test.yml
+++ b/templates/test.yml
@@ -15,6 +15,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -76,6 +84,6 @@ spec:
     TF_ROOT: $[[ inputs.root_dir ]]
     TF_STATE_NAME: $[[ inputs.state_name ]]
   image:
-    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]'
+    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]'
   script:
     - gitlab-tofu test
diff --git a/templates/validate-plan-apply.yml b/templates/validate-plan-apply.yml
index 55d621a2bb364dfba1e2ba98dabd5ed7a98a7e8a..ee4bb68bf4d5b1b6bfb343f5c6b28332d5d8fa98 100644
--- a/templates/validate-plan-apply.yml
+++ b/templates/validate-plan-apply.yml
@@ -18,6 +18,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -74,6 +82,7 @@ include:
       as: 'fmt'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -83,6 +92,7 @@ include:
       as: 'validate'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -93,6 +103,7 @@ include:
       as: 'plan'
       stage: $[[ inputs.stage_build ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -104,6 +115,7 @@ include:
       as: 'apply'
       stage: $[[ inputs.stage_deploy ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
diff --git a/templates/validate-plan-destroy.yml b/templates/validate-plan-destroy.yml
index f9084d97fc9c44833e23c513e1e8f475b0645782..431d4c5e5b4ee0931ed12209a7333bc7ad26bbb0 100644
--- a/templates/validate-plan-destroy.yml
+++ b/templates/validate-plan-destroy.yml
@@ -18,6 +18,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -77,6 +85,7 @@ include:
       as: 'fmt'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -86,6 +95,7 @@ include:
       as: 'validate'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -96,6 +106,7 @@ include:
       as: 'plan'
       stage: $[[ inputs.stage_build ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -109,6 +120,7 @@ include:
       as: 'destroy'
       stage: $[[ inputs.stage_cleanup ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
diff --git a/templates/validate-plan.yml b/templates/validate-plan.yml
index 2134488dcdcc1f2a487f6b62b92db70a4df1f24f..0241cc67f9288b5b7be7977f66ebf1936edd9eb5 100644
--- a/templates/validate-plan.yml
+++ b/templates/validate-plan.yml
@@ -15,6 +15,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -67,6 +75,7 @@ include:
       as: 'fmt'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -76,6 +85,7 @@ include:
       as: 'validate'
       stage: $[[ inputs.stage_validate ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
@@ -86,6 +96,7 @@ include:
       as: 'plan'
       stage: $[[ inputs.stage_build ]]
       version: $[[ inputs.version ]]
+      base_os: $[[ inputs.base_os ]]
       opentofu_version: $[[ inputs.opentofu_version ]]
       image_registry_base: $[[ inputs.image_registry_base ]]
       image_name: $[[ inputs.image_name ]]
diff --git a/templates/validate.yml b/templates/validate.yml
index 09c01ad2264e86bc83d72639e34bf33aeabe5159..c34b9a23ece323918c34d57446bc2b5237f54688 100644
--- a/templates/validate.yml
+++ b/templates/validate.yml
@@ -15,6 +15,14 @@ spec:
       default: 'latest'
       description: 'Version of this component. Has to be the same as the one in the component include entry.'
 
+    base_os:
+      default: 'alpine'
+      options:
+        - 'alpine'
+        - 'debian'
+        - '$GITLAB_OPENTOFU_BASE_IMAGE_OS'
+      description: 'Base OS of GitLab OpenTofu image.'
+
     opentofu_version:
       default: '1.8.2'
       options:
@@ -76,6 +84,6 @@ spec:
     TF_STATE_NAME: $[[ inputs.state_name ]]
     TF_IGNORE_INIT_ERRORS: 'true' # Tofu can report errors which might be the reason init failed.
   image:
-    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]'
+    name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]'
   script:
     - gitlab-tofu validate
diff --git a/tests/integration-tests/Defaults.gitlab-ci.yml b/tests/integration-tests/Defaults.gitlab-ci.yml
index 572ee7d9565ae9a23af135686cad3a7846a58151..09762e0d0e81c605c21a819db2dff78494815e71 100644
--- a/tests/integration-tests/Defaults.gitlab-ci.yml
+++ b/tests/integration-tests/Defaults.gitlab-ci.yml
@@ -3,6 +3,7 @@ include:
     inputs:
       image_registry_base: $GITLAB_OPENTOFU_IMAGE_BASE
       version: $CI_COMMIT_SHA
+      base_os: $GITLAB_OPENTOFU_BASE_IMAGE_OS
       opentofu_version: $OPENTOFU_VERSION
       root_dir: $TEST_TF_ROOT
       state_name: $TEST_TF_STATE_NAME
diff --git a/tests/integration-tests/ModuleRelease.gitlab-ci.yml b/tests/integration-tests/ModuleRelease.gitlab-ci.yml
index 77db9b05e033ca0d28538b45ccb36b988d9ad40b..fd8dc3fac72e1d8ebedde2ffcbd30852c43e0352 100644
--- a/tests/integration-tests/ModuleRelease.gitlab-ci.yml
+++ b/tests/integration-tests/ModuleRelease.gitlab-ci.yml
@@ -1,6 +1,6 @@
 variables:
   MODULE_SYSTEM: local
-  MODULE_VERSION: 0.0.0-$CI_COMMIT_SHA
+  MODULE_VERSION: 0.0.0-$CI_COMMIT_SHA-$CI_PIPELINE_ID
 
 include:
   - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/module-release@$CI_COMMIT_SHA
diff --git a/tests/integration.gitlab-ci.yml b/tests/integration.gitlab-ci.yml
index 6411f291aceba82f8f69fce3d2ccea981eb8864d..7b1f5fbae32a5eb2edaa3bb68a773a14884624d2 100644
--- a/tests/integration.gitlab-ci.yml
+++ b/tests/integration.gitlab-ci.yml
@@ -9,8 +9,12 @@ component:
     strategy: depend
   parallel:
     matrix:
-      - PIPELINE_NAME: [Defaults]
-      - PIPELINE_NAME: [JobTemplates]
-      - PIPELINE_NAME: [TestJob]
-      - PIPELINE_NAME: [ModuleRelease]
-      - PIPELINE_NAME: [Destroy]
+      - PIPELINE_NAME:
+          - Defaults
+          - JobTemplates
+          - TestJob
+          - ModuleRelease
+          - Destroy
+        GITLAB_OPENTOFU_BASE_IMAGE_OS:
+          - alpine
+          - debian
diff --git a/tests/unit.gitlab-ci.yml b/tests/unit.gitlab-ci.yml
index 697449fc2e08e19eb162ae20ed2f1b5c1da45dc8..aa8f46268dbfbda8f9e152f539ecf96f434e168c 100644
--- a/tests/unit.gitlab-ci.yml
+++ b/tests/unit.gitlab-ci.yml
@@ -5,7 +5,16 @@ variables:
   image: "$GITLAB_OPENTOFU_IMAGE_NAME"
   before_script:
     # Install dependencies
-    - apk add bats parallel
+    - |
+      if which apk >/dev/null; then
+        apk add bats parallel
+      elif which apt-get >/dev/null; then
+        apt-get update
+        apt-get install -y bats parallel
+      else
+        echo "Error: unable to install test dependencies, must either have apk or apt-get available."
+        exit 1
+      fi
     - mkdir -p /tmp/bats-libs
     - git clone --depth 1 --branch v0.3.0 https://github.com/bats-core/bats-support.git /tmp/bats-libs/bats-support
     - git clone --depth 1 --branch v2.1.0 https://github.com/bats-core/bats-assert.git /tmp/bats-libs/bats-assert
@@ -24,7 +33,7 @@ variables:
 unit-test:gitlab-tofu:
   extends:
     - .unit-test-base
-    - .opentofu-versions
+    - .image-matrix
   script:
     - bats --jobs 8 --report-formatter junit --filter-tags '!source' tests/unit/gitlab-tofu.bats
 
@@ -34,13 +43,26 @@ unit-test:gitlab-tofu:source:
   variables:
     OPENTOFU_VERSION: $LATEST_OPENTOFU_VERSION
   script:
-    - apk add "$PKG"
+    - |
+      if which apk >/dev/null; then
+        if [ "$SHELL" = "ksh" ]; then
+          apk add loksh
+        else
+          apk add "$SHELL"
+        fi
+      elif which apt-get >/dev/null; then
+        apt-get update
+        apt-get install -y "$SHELL"
+      else
+        echo "Error: unable to install test dependencies, must either have apk or apt-get available."
+        exit 1
+      fi
     - bats --jobs 8 --report-formatter junit --filter-tags 'source' tests/unit/gitlab-tofu.bats
   parallel:
     matrix:
       - SHELL: "bash"
-        PKG: "bash"
+        GITLAB_OPENTOFU_BASE_IMAGE_OS: ['alpine', 'debian']
       - SHELL: "zsh"
-        PKG: "zsh"
+        GITLAB_OPENTOFU_BASE_IMAGE_OS: ['alpine', 'debian']
       - SHELL: "ksh"
-        PKG: "loksh"
+        GITLAB_OPENTOFU_BASE_IMAGE_OS: ['alpine', 'debian']
diff --git a/tests/unit/gitlab-tofu.bats b/tests/unit/gitlab-tofu.bats
index 8dd3155e6680b4e7771973fd533343c9ca5335da..0770c928ff00acc5adfaafac7001006740063292 100644
--- a/tests/unit/gitlab-tofu.bats
+++ b/tests/unit/gitlab-tofu.bats
@@ -170,7 +170,7 @@ test -z "$TF_GITLAB_SOURCED"
 test "$TF_GITLAB_SOURCED"
 EOF
 
-  mkdir /usr/local/sbin
+  mkdir -p /usr/local/sbin
   cat <<'EOF' > /usr/local/sbin/tofu
 #!/usr/bin/env sh -e
 echo "Called tofu, but shouldn't have!!"