From 0d915ead58707baa1afc3c42d3a2e9628ccc4d45 Mon Sep 17 00:00:00 2001
From: Janos <86970079+janosdebugs@users.noreply.github.com>
Date: Wed, 10 Jan 2024 15:27:09 +0100
Subject: [PATCH] Updating install instructions to include the installer script
(#1070)
Signed-off-by: Janos Bonic <86970079+janosdebugs@users.noreply.github.com>
---
.../docs/intro/install/alpine-convenience.sh | 14 +
website/docs/intro/install/alpine-manual.sh | 2 +
website/docs/intro/install/alpine.mdx | 20 +-
website/docs/intro/install/alpine.sh | 13 +
website/docs/intro/install/brew-install.sh | 1 +
website/docs/intro/install/deb-convenience.sh | 18 +-
website/docs/intro/install/deb.mdx | 6 +
.../docs/intro/install/docker-compose.yaml | 16 +
website/docs/intro/install/homebrew.mdx | 2 +-
website/docs/intro/install/index.mdx | 4 +-
.../docs/intro/install/install-opentofu.sh | 1244 +++++++++++++++++
.../docs/intro/install/portable-install.ps1 | 10 -
.../docs/intro/install/portable-install.sh | 13 -
website/docs/intro/install/portable.mdx | 31 -
website/docs/intro/install/repo-yum.sh | 2 +
website/docs/intro/install/repo-zypper.sh | 6 +-
.../docs/intro/install/rpm-convenience-yum.sh | 6 -
.../intro/install/rpm-convenience-zypper.sh | 6 -
website/docs/intro/install/rpm-convenience.sh | 14 +
website/docs/intro/install/rpm.mdx | 9 +-
website/docs/intro/install/rpm.sh | 4 +-
.../docs/intro/install/standalone-install.ps1 | 10 +
.../docs/intro/install/standalone-install.sh | 14 +
website/docs/intro/install/standalone.mdx | 68 +
.../intro/install/verify-checksum-linux.sh | 8 +
.../intro/install/verify-checksum-macos.sh | 8 +
.../docs/intro/install/verify-checksum.ps1 | 6 +
website/docs/intro/install/verify-cosign.ps1 | 10 +
website/docs/intro/install/verify-cosign.sh | 10 +
29 files changed, 1490 insertions(+), 85 deletions(-)
create mode 100644 website/docs/intro/install/alpine-convenience.sh
create mode 100644 website/docs/intro/install/alpine-manual.sh
create mode 100755 website/docs/intro/install/alpine.sh
create mode 100755 website/docs/intro/install/install-opentofu.sh
delete mode 100644 website/docs/intro/install/portable-install.ps1
delete mode 100644 website/docs/intro/install/portable-install.sh
delete mode 100644 website/docs/intro/install/portable.mdx
delete mode 100644 website/docs/intro/install/rpm-convenience-yum.sh
delete mode 100644 website/docs/intro/install/rpm-convenience-zypper.sh
create mode 100644 website/docs/intro/install/rpm-convenience.sh
create mode 100644 website/docs/intro/install/standalone-install.ps1
create mode 100644 website/docs/intro/install/standalone-install.sh
create mode 100644 website/docs/intro/install/standalone.mdx
create mode 100644 website/docs/intro/install/verify-checksum-linux.sh
create mode 100644 website/docs/intro/install/verify-checksum-macos.sh
create mode 100644 website/docs/intro/install/verify-checksum.ps1
create mode 100644 website/docs/intro/install/verify-cosign.ps1
create mode 100644 website/docs/intro/install/verify-cosign.sh
diff --git a/website/docs/intro/install/alpine-convenience.sh b/website/docs/intro/install/alpine-convenience.sh
new file mode 100644
index 0000000000..b967249880
--- /dev/null
+++ b/website/docs/intro/install/alpine-convenience.sh
@@ -0,0 +1,14 @@
+# Download the installer script:
+curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
+# Alternatively: wget --secure-protocol=TLSv1_2 --https-only https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
+
+# Give it execution permissions:
+chmod +x install-opentofu.sh
+
+# Please inspect the downloaded script
+
+# Run the installer:
+./install-opentofu.sh --install-method apk
+
+# Remove the installer:
+rm install-opentofu.sh
\ No newline at end of file
diff --git a/website/docs/intro/install/alpine-manual.sh b/website/docs/intro/install/alpine-manual.sh
new file mode 100644
index 0000000000..2f4d3e782b
--- /dev/null
+++ b/website/docs/intro/install/alpine-manual.sh
@@ -0,0 +1,2 @@
+echo '@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories
+apk add opentofu@testing
\ No newline at end of file
diff --git a/website/docs/intro/install/alpine.mdx b/website/docs/intro/install/alpine.mdx
index 82281c140a..1d4697f397 100644
--- a/website/docs/intro/install/alpine.mdx
+++ b/website/docs/intro/install/alpine.mdx
@@ -5,17 +5,21 @@ description: |-
Install OpenTofu on Alpine Linux.
---
+import CodeBlock from '@theme/CodeBlock';
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import ApkConvenienceScript from '!!raw-loader!./alpine-convenience.sh'
+import ApkManualScript from '!!raw-loader!./alpine-manual.sh'
+
# Installing OpenTofu on Alpine Linux
OpenTofu is available in the [Alpine Linux testing repository](https://pkgs.alpinelinux.org/packages?name=opentofu) or as an `.apk` package from the [GitHub releases page](https://github.com/opentofu/opentofu/releases/latest/).
-## Installing from the testing repository
+## Installing using the installer
-OpenTofu is available in the Alpine Testing repository and can be installed from there:
+You can use the OpenTofu installer script to run the installation.
-```bash
-apk add opentofu --repository=https://dl-cdn.alpinelinux.org/alpine/edge/testing/
-```
+{ApkConvenienceScript}
## Installing the .apk
@@ -24,3 +28,9 @@ You can also [download the .apk](https://github.com/opentofu/opentofu/releases/l
```bash
apk add --allow-untrusted tofu_*.apk
```
+
+## Installing from the testing repository
+
+OpenTofu is currently available in the Alpine Testing repository and coming to Alpine stable. You can use the following commands to test Alpine installation.
+
+{ApkManualScript}
diff --git a/website/docs/intro/install/alpine.sh b/website/docs/intro/install/alpine.sh
new file mode 100755
index 0000000000..1d050e52c7
--- /dev/null
+++ b/website/docs/intro/install/alpine.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -e
+
+apk add curl
+
+if [ "$1" = "--convenience" ]; then
+ sh -x alpine-convenience.sh
+else
+ sh -x alpine-manual.sh
+fi
+
+tofu --version
\ No newline at end of file
diff --git a/website/docs/intro/install/brew-install.sh b/website/docs/intro/install/brew-install.sh
index d71119012a..540ac9d075 100644
--- a/website/docs/intro/install/brew-install.sh
+++ b/website/docs/intro/install/brew-install.sh
@@ -1 +1,2 @@
+brew update
brew install opentofu
\ No newline at end of file
diff --git a/website/docs/intro/install/deb-convenience.sh b/website/docs/intro/install/deb-convenience.sh
index 1f33717b7b..42c5e0d2cb 100644
--- a/website/docs/intro/install/deb-convenience.sh
+++ b/website/docs/intro/install/deb-convenience.sh
@@ -1,6 +1,14 @@
-curl --proto '=https' --tlsv1.2 -fsSL 'https://packages.opentofu.org/install/repositories/opentofu/tofu/script.deb.sh?any=true' -o /tmp/tofu-repository-setup.sh
-# Inspect the downloaded script at /tmp/tofu-repository-setup.sh before running
-sudo bash /tmp/tofu-repository-setup.sh
-rm /tmp/tofu-repository-setup.sh
+# Download the installer script:
+curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
+# Alternatively: wget --secure-protocol=TLSv1_2 --https-only https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
-sudo apt-get install tofu
\ No newline at end of file
+# Give it execution permissions:
+chmod +x install-opentofu.sh
+
+# Please inspect the downloaded script
+
+# Run the installer:
+./install-opentofu.sh --install-method deb
+
+# Remove the installer:
+rm install-opentofu.sh
\ No newline at end of file
diff --git a/website/docs/intro/install/deb.mdx b/website/docs/intro/install/deb.mdx
index 7b395f41df..61530a973f 100644
--- a/website/docs/intro/install/deb.mdx
+++ b/website/docs/intro/install/deb.mdx
@@ -19,6 +19,12 @@ import Buildkite from './buildkite'
You can install OpenTofu from our Debian repository by following the step-by-step instructions below.
+## Installing using the installer
+
+You can use the OpenTofu installer script to run the installation.
+
+{DebConvenienceScript}
+
## Step-by-step instructions
The following steps explain how to set up the OpenTofu Debian repositories. These instructions should work on most Debian-based Linux systems.
diff --git a/website/docs/intro/install/docker-compose.yaml b/website/docs/intro/install/docker-compose.yaml
index c3f23be3e6..a59cd5d685 100644
--- a/website/docs/intro/install/docker-compose.yaml
+++ b/website/docs/intro/install/docker-compose.yaml
@@ -2,6 +2,22 @@
# test-install-instructions.sh for details.
version: '3.2'
services:
+ alpine-convenience:
+ image: alpine
+ volumes:
+ - source: ./
+ target: /data
+ type: bind
+ command: /data/alpine.sh --convenience
+ working_dir: /data
+ alpine-manual:
+ image: alpine
+ volumes:
+ - source: ./
+ target: /data
+ type: bind
+ command: /data/alpine.sh
+ working_dir: /data
debian-convenience:
image: debian:buster
volumes:
diff --git a/website/docs/intro/install/homebrew.mdx b/website/docs/intro/install/homebrew.mdx
index 69450a5e69..1e492e3bb1 100644
--- a/website/docs/intro/install/homebrew.mdx
+++ b/website/docs/intro/install/homebrew.mdx
@@ -10,6 +10,6 @@ import BrewScript from '!!raw-loader!./brew-install.sh'
# Installing OpenTofu via Homebrew
-You can use OpenTofu as a [portable binary](portable.mdx) or you can install it using [Homebrew](https://formulae.brew.sh/formula/opentofu). OpenTofu is available in the Homebrew Core repository, so you can install it by running:
+You can use OpenTofu as a [standalone binary](standalone.mdx) or you can install it using [Homebrew](https://formulae.brew.sh/formula/opentofu). OpenTofu is available in the Homebrew Core repository, so you can install it by running:
{BrewScript}
diff --git a/website/docs/intro/install/index.mdx b/website/docs/intro/install/index.mdx
index b3048cdeae..f2af090b33 100644
--- a/website/docs/intro/install/index.mdx
+++ b/website/docs/intro/install/index.mdx
@@ -49,8 +49,8 @@ You can install OpenTofu via a wide range of methods. Please select your operati
},
{
type: "link",
- href: "/docs/intro/install/portable",
- label: "Portable (Linux/MacOS/Windows)",
+ href: "/docs/intro/install/standalone",
+ label: "Standalone (Linux/MacOS/Windows)",
description:
"Use OpenTofu without installation on Linux, MacOS, or Windows.",
},
diff --git a/website/docs/intro/install/install-opentofu.sh b/website/docs/intro/install/install-opentofu.sh
new file mode 100755
index 0000000000..8e75576c56
--- /dev/null
+++ b/website/docs/intro/install/install-opentofu.sh
@@ -0,0 +1,1244 @@
+#!/bin/sh
+
+# OpenTofu Installer
+#
+# This script installs OpenTofu via any of the supported methods.
+
+export TOFU_INSTALL_EXIT_CODE_OK=0
+export TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET=1
+export TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED=2
+export TOFU_INSTALL_EXIT_CODE_INVALID_ARGUMENT=3
+
+export TOFU_INSTALL_RETURN_CODE_COMMAND_NOT_FOUND=11
+export TOFU_INSTALL_RETURN_CODE_DOWNLOAD_FAILED=13
+
+bold=""
+normal=""
+red=""
+green=""
+yellow=""
+blue=""
+magenta=""
+cyan=""
+gray=""
+if [ -t 1 ]; then
+ if command -v "tput" >/dev/null 2>&1; then
+ colors=$(tput colors)
+ else
+ colors=2
+ fi
+
+ if [ "${colors}" -ge 8 ]; then
+ bold="$(tput bold)"
+ normal="$(tput sgr0)"
+ red="$(tput setaf 1)"
+ green="$(tput setaf 2)"
+ yellow="$(tput setaf 3)"
+ blue="$(tput setaf 4)"
+ magenta="$(tput setaf 5)"
+ cyan="$(tput setaf 6)"
+ gray="$(tput setaf 245)"
+ fi
+fi
+
+ROOT_METHOD=auto
+INSTALL_METHOD=""
+DEFAULT_INSTALL_PATH=/opt/opentofu
+INSTALL_PATH="${DEFAULT_INSTALL_PATH}"
+DEFAULT_SYMLINK_PATH=/usr/local/bin
+SYMLINK_PATH="${DEFAULT_SYMLINK_PATH}"
+DEFAULT_OPENTOFU_VERSION=latest
+OPENTOFU_VERSION="${DEFAULT_OPENTOFU_VERSION}"
+DEFAULT_DEB_GPG_URL=https://get.opentofu.org/opentofu.gpg
+DEB_GPG_URL="${DEFAULT_DEB_GPG_URL}"
+DEFAULT_DEB_REPO_GPG_URL=https://packages.opentofu.org/opentofu/tofu/gpgkey
+DEB_REPO_GPG_URL="${DEFAULT_DEB_REPO_GPG_URL}"
+DEFAULT_DEB_REPO_URL=https://packages.opentofu.org/opentofu/tofu/any/
+DEB_REPO_URL=${DEFAULT_DEB_REPO_URL}
+DEFAULT_DEB_REPO_SUITE=any
+DEB_REPO_SUITE="${DEFAULT_DEB_REPO_SUITE}"
+DEFAULT_DEB_REPO_COMPONENTS=main
+DEB_REPO_COMPONENTS="${DEFAULT_DEB_REPO_COMPONENTS}"
+DEFAULT_RPM_REPO_URL=https://packages.opentofu.org/opentofu/tofu/rpm_any/rpm_any/
+
+RPM_REPO_URL=${DEFAULT_RPM_REPO_URL}
+DEFAULT_RPM_REPO_GPG_URL=https://packages.opentofu.org/opentofu/tofu/gpgkey
+DEFAULT_RPM_GPG_URL=https://get.opentofu.org/opentofu.asc
+RPM_GPG_URL="${DEFAULT_RPM_GPG_URL}"
+RPM_REPO_GPG_URL="${DEFAULT_RPM_REPO_GPG_URL}"
+#TODO once the package makes it into stable change this to "-"
+DEFAULT_APK_REPO_URL="@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing"
+APK_REPO_URL=${DEFAULT_APK_REPO_URL}
+DEFAULT_APK_PACKAGE="opentofu@testing"
+APK_PACKAGE="${DEFAULT_APK_PACKAGE}"
+DEFAULT_COSIGN_PATH=cosign
+COSIGN_PATH=${DEFAULT_COSIGN_PATH}
+DEFAULT_COSIGN_IDENTITY=autodetect
+COSIGN_IDENTITY=${DEFAULT_COSIGN_IDENTITY}
+DEFAULT_COSIGN_OIDC_ISSUER=https://token.actions.githubusercontent.com
+COSIGN_OIDC_ISSUER=${DEFAULT_COSIGN_OIDC_ISSUER}
+SKIP_VERIFY=0
+
+# region ZSH
+if [ -n "${ZSH_VERSION}" ]; then
+ ## Enable POSIX-style word splitting:
+ setopt SH_WORD_SPLIT >/dev/null 2>&1
+fi
+# endregion
+
+log_success() {
+ if [ -z "$1" ]; then
+ return
+ fi
+ echo "${green}$1${normal}" 1>&2
+}
+
+log_warning() {
+ if [ -z "$1" ]; then
+ return
+ fi
+ echo "${yellow}$1${normal}" 1>&2
+}
+
+log_info() {
+ if [ -z "$1" ]; then
+ return
+ fi
+ echo "${cyan}$1${normal}" 1>&2
+}
+
+log_debug() {
+ if [ -z "$1" ]; then
+ return
+ fi
+ if [ -z "${LOG_DEBUG}" ]; then
+ return
+ fi
+ echo "${gray}$1${normal}" 1>&2
+}
+
+log_error() {
+ if [ -z "$1" ]; then
+ return
+ fi
+ echo "${red}$1${normal}" 1>&2
+}
+
+# This function checks if the command specified in $1 exists.
+command_exists() {
+ log_debug "Determining if the ${1} command is available..."
+ if [ -z "$1" ]; then
+ log_error "Bug: no command supplied to command_exists()"
+ return "${TOFU_INSTALL_EXIT_CODE_INVALID_ARGUMENT}"
+ fi
+ if ! command -v "$1" >/dev/null 2>&1; then
+ log_debug "The ${1} command is not available."
+ return "${TOFU_INSTALL_RETURN_CODE_COMMAND_NOT_FOUND}"
+ fi
+ log_debug "The ${1} command is available."
+ return "${TOFU_INSTALL_EXIT_CODE_OK}"
+}
+
+is_root() {
+ if [ "$(id -u || true)" -eq 0 ]; then
+ return 0
+ fi
+ return 1
+}
+
+# This function runs the specified command as root.
+as_root() {
+ # shellcheck disable=SC2145
+ log_debug "Running command as root: $*"
+ case "${ROOT_METHOD}" in
+ auto)
+ log_debug "Automatically determining root method..."
+ if is_root; then
+ log_debug "We are already root, no user change needed."
+ "$@"
+ elif command_exists "sudo"; then
+ log_debug "Running command using sudo."
+ sudo "$@"
+ elif command_exists "su"; then
+ log_debug "Running command using su."
+ su root "$@"
+ else
+ log_error "Neither su nor sudo is installed, cannot obtain root privileges."
+ return "${TOFU_INSTALL_RETURN_CODE_COMMAND_NOT_FOUND}"
+ fi
+ return $?
+ ;;
+ none)
+ log_debug "Using manual root method 'none'."
+ "$@"
+ return $?
+ ;;
+ sudo)
+ log_debug "Using manual root method 'sudo'."
+ sudo "$@"
+ return $?
+ ;;
+ su)
+ log_debug "Using manual root method 'su'."
+ su root "$@"
+ return $?
+ ;;
+ *)
+ log_error "Bug: invalid root method value: $1"
+ return "${TOFU_INSTALL_EXIT_CODE_INVALID_ARGUMENT}"
+ esac
+}
+
+# This function attempts to execute a function as the current user and switches to root if it fails.
+maybe_root() {
+ if ! "$@" >/dev/null 2>&1; then
+ if ! as_root "$@"; then
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ fi
+ return "${TOFU_INSTALL_EXIT_CODE_OK}"
+}
+
+# This function verifies if one of the supported download tools is installed and returns with
+# $TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET if that is not th ecase.
+download_tool_exists() {
+ log_debug "Determining if a supported download tool is installed..."
+ if command_exists "wget"; then
+ log_debug "wget is installed."
+ return "${TOFU_INSTALL_EXIT_CODE_OK}"
+ elif command_exists "curl"; then
+ log_debug "curl is installed."
+ return "${TOFU_INSTALL_EXIT_CODE_OK}"
+ else
+ log_debug "No supported download tool is installed."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET}"
+ fi
+}
+
+# This function downloads the URL specified in $1 into the file specified in $2.
+# It returns $TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET if no supported download tool is installed, or $TOFU_INSTALL_RETURN_CODE_DOWNLOAD_FAILED
+# if the download failed.
+download_file() {
+ if [ -z "$1" ]; then
+ log_error "Bug: no URL supplied to download_file()"
+ return "${TOFU_INSTALL_EXIT_CODE_INVALID_ARGUMENT}"
+ fi
+ if [ -z "$2" ]; then
+ log_error "Bug: no destination file supplied to download_file()"
+ return "${TOFU_INSTALL_EXIT_CODE_INVALID_ARGUMENT}"
+ fi
+ log_debug "Downloading URL ${1} to ${2}..."
+ IS_GITHUB=0
+ if [ -n "${GITHUB_TOKEN}" ]; then
+ if [ "$(echo "$1" | grep -c "api.github.com" || true)" -ne 0 ]; then
+ IS_GITHUB=1
+ fi
+ fi
+ if command_exists "wget"; then
+ if [ "${IS_GITHUB}" -eq 1 ]; then
+ log_debug "Downloading using wget with GITHUB_TOKEN..."
+ if ! wget -q --header="Authorization: token ${GITHUB_TOKEN}" -O "$2" "$1"; then
+ log_debug "Download failed."
+ return "${TOFU_INSTALL_RETURN_CODE_DOWNLOAD_FAILED}"
+ fi
+ else
+ log_debug "Downloading using wget without GITHUB_TOKEN, this may lead to rate limit issues..."
+ if ! wget -q -O "$2" "$1"; then
+ log_debug "Download failed, please try specifying the GITHUB_TOKEN environment variable."
+ return "${TOFU_INSTALL_RETURN_CODE_DOWNLOAD_FAILED}"
+ fi
+ fi
+ elif command_exists "curl"; then
+ if [ "${IS_GITHUB}" -eq 1 ]; then
+ log_debug "Downloading using curl with GITHUB_TOKEN..."
+ if ! curl --proto '=https' --tlsv1.2 -fsSL -H "Authorization: token ${GITHUB_TOKEN}" -o "$2" "$1"; then
+ log_debug "Download failed."
+ return "${TOFU_INSTALL_RETURN_CODE_DOWNLOAD_FAILED}"
+ fi
+ else
+ log_debug "Downloading using curl without GITHUB_TOKEN, this may lead to rate limit issues..."
+ if ! curl --proto '=https' --tlsv1.2 -fsSL -o "$2" "$1"; then
+ log_debug "Download failed, please try specifying the GITHUB_TOKEN environment variable."
+ return "${TOFU_INSTALL_RETURN_CODE_DOWNLOAD_FAILED}"
+ fi
+ fi
+ else
+ log_error "Neither wget nor curl are available on your system. Please install one of them to proceed."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET}"
+ fi
+ log_debug "Download successful."
+ return "${TOFU_INSTALL_EXIT_CODE_OK}"
+}
+
+# This function downloads the OpenTofu GPG key from the specified URL to the specified location. Setting the third
+# parameter to 1 causes the file to be moved as root. It returns $TOFU_INSTALL_RETURN_CODE_DOWNLOAD_FAILED if the
+# download fails, or $TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET if no download tool is available.
+download_gpg() {
+ if [ -z "$1" ]; then
+ log_error "Bug: no URL passed to download_gpg."
+ return "${TOFU_INSTALL_EXIT_CODE_INVALID_ARGUMENT}"
+ fi
+ if [ -z "$2" ]; then
+ log_error "Bug: no destination passed to download_gpg."
+ return "${TOFU_INSTALL_EXIT_CODE_INVALID_ARGUMENT}"
+ fi
+ if ! command_exists "gpg"; then
+ log_error "Missing gpg binary."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET}"
+ fi
+ log_debug "Downloading GPG key from ${1} to ${2}..."
+ if ! download_tool_exists; then
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET}"
+ fi
+ log_debug "Creating temporary directory..."
+ TEMPDIR=$(mktemp -d)
+ if [ -z "${TEMPDIR}" ]; then
+ log_error "Failed to create temporary directory for GPG download."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ TEMPFILE="${TEMPDIR}/opentofu.gpg"
+
+ if ! download_file "${1}" "${TEMPFILE}"; then
+ log_debug "Removing temporary directory..."
+ rm -rf "${TEMPFILE}"
+ return "${TOFU_INSTALL_RETURN_CODE_DOWNLOAD_FAILED}"
+ fi
+ if [ "$(grep 'BEGIN PGP PUBLIC KEY BLOCK' -c "${TEMPFILE}" || true)" -ne 0 ]; then
+ log_debug "Performing GPG dearmor on ${TEMPFILE}"
+ if ! gpg --no-tty --batch --dearmor -o "${TEMPFILE}.tmp" <"${TEMPFILE}"; then
+ log_error "Failed to GPG dearmor ${TEMPFILE}."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ if ! mv "${TEMPFILE}.tmp" "${TEMPFILE}"; then
+ log_error "Failed to move ${TEMPFILE}.tmp to ${TEMPFILE}."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ fi
+ if [ "$3" = "1" ]; then
+ log_debug "Moving GPG file as root..."
+ if ! as_root mv "${TEMPFILE}" "${2}"; then
+ log_error "Failed to move ${TEMPFILE} to ${2}."
+ rm -rf "${TEMPFILE}"
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ else
+ log_debug "Moving GPG file as the current user..."
+ if ! mv "${TEMPFILE}" "${2}"; then
+ log_error "Failed to move ${TEMPFILE} to ${2}."
+ rm -rf "${TEMPFILE}"
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ fi
+
+ log_debug "Removing temporary directory..."
+ rm -rf "${TEMPFILE}"
+ return "${TOFU_INSTALL_EXIT_CODE_OK}"
+}
+
+# This is a helper function that downloads a GPG URL to the specified file.
+deb_download_gpg() {
+ DEB_GPG_URL="${1}"
+ GPG_FILE="${2}"
+ if [ -z "${DEB_GPG_URL}" ]; then
+ log_error "Bug: no GPG URL specified for deb_download_gpg."
+ return "${TOFU_INSTALL_EXIT_CODE_INVALID_ARGUMENT}"
+ fi
+ if [ -z "${GPG_FILE}" ]; then
+ log_error "Bug: no destination path specified for deb_download_gpg."
+ return "${TOFU_INSTALL_EXIT_CODE_INVALID_ARGUMENT}"
+ fi
+ if ! download_gpg "${DEB_GPG_URL}" "${GPG_FILE}" 1; then
+ log_error "Failed to download GPG key from ${DEB_GPG_URL}."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ log_debug "Changing ownership and permissions of ${GPG_FILE}..."
+ if ! as_root chown root:root "${GPG_FILE}"; then
+ log_error "Failed to chown ${GPG_FILE}."
+ rm -rf "${GPG_FILE}"
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ if ! as_root chmod a+r "${GPG_FILE}"; then
+ log_error "Failed to chmod ${GPG_FILE}."
+ rm -rf "${GPG_FILE}"
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ return "${TOFU_INSTALL_EXIT_CODE_OK}"
+}
+
+# This function installs OpenTofu via a Debian repository. It returns
+# $TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET if this is not a Debian system.
+install_deb() {
+ log_info "Attempting installation via Debian repository..."
+ if ! command_exists apt-get; then
+ log_info "The apt-get command is not available, skipping Debian repository installation."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET}"
+ fi
+
+ if ! is_root; then
+ log_info "Root privileges are required to install OpenTofu as a Debian package."
+ log_info "The installer will now verify if it can correctly assume root privileges."
+ log_info "${bold}You may be asked to enter your password.${normal}"
+ if ! as_root echo -n ""; then
+ log_error "Cannot assume root privileges."
+ log_info "Please set up either '${bold}su${normal}' or '${bold}sudo${normal}'."
+ log_info "Alternatively, run this script with ${bold}-h${normal} for other installation methods."
+ fi
+ fi
+
+ log_info "Updating package list..."
+ if ! as_root apt-get update; then
+ log_error "Failed to update apt package list."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+
+ log_debug "Determining packages to install..."
+ PACKAGE_LIST="apt-transport-https ca-certificates"
+ if [ "${SKIP_VERIFY}" -ne "1" ]; then
+ PACKAGE_LIST="${PACKAGE_LIST} gnupg"
+ fi
+ if ! download_tool_exists; then
+ log_debug "No download tool present, adding curl to the package list..."
+ PACKAGE_LIST="${PACKAGE_LIST} curl"
+ fi
+
+ log_info "Installing necessary packages for installation..."
+ log_debug "Installing ${PACKAGE_LIST}..."
+ # shellcheck disable=SC2086
+ if ! as_root apt-get install -y ${PACKAGE_LIST}; then
+ log_error "Failed to install requisite packages for Debian repository installation."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ log_debug "Necessary packages installed."
+
+ if [ "${SKIP_VERIFY}" -ne "1" ]; then
+ log_info "Installing the OpenTofu GPG keys..."
+ log_debug "Creating /etc/apt/keyrings..."
+ if ! as_root install -m 0755 -d /etc/apt/keyrings; then
+ log_error "Failed to create /etc/apt/keyrings."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ log_debug "Created /etc/apt/keyrings."
+
+ PACKAGE_GPG_FILE=/etc/apt/keyrings/opentofu.gpg
+ log_debug "Downloading the GPG key from ${DEB_GPG_URL}.."
+ if ! deb_download_gpg "${DEB_GPG_URL}" "${PACKAGE_GPG_FILE}"; then
+ log_error "Failed to download GPG key from ${DEB_GPG_URL}."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ if [ -n "${DEB_REPO_GPG_URL}" ] && [ "${DEB_REPO_GPG_URL}" != "-" ]; then
+ log_debug "Downloading the repo GPG key from ${DEB_REPO_GPG_URL}.."
+ REPO_GPG_FILE=/etc/apt/keyrings/opentofu-repo.gpg
+ if ! deb_download_gpg "${DEB_REPO_GPG_URL}" "${REPO_GPG_FILE}" 1; then
+ log_error "Failed to download GPG key from ${DEB_REPO_GPG_URL}."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ fi
+ fi
+
+ log_info "Creating OpenTofu sources list..."
+ if [ "${SKIP_VERIFY}" -ne "1" ]; then
+ if [ -n "${REPO_GPG_FILE}" ]; then
+ if ! as_root tee /etc/apt/sources.list.d/opentofu.list; then
+ log_error "Failed to create /etc/apt/sources.list.d/opentofu.list."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi < /dev/null; then
+ log_error "Failed to run tofu after installation."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ return "${TOFU_INSTALL_EXIT_CODE_OK}"
+}
+
+# This function installs OpenTofu via the zypper command line utility. It returns
+# $TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET if zypper is not available.
+install_zypper() {
+ if ! command_exists "zypper"; then
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_REQUIREMENTS_NOT_MET}"
+ fi
+ log_info "Installing OpenTofu using zypper..."
+ if [ "${SKIP_VERIFY}" -ne "1" ]; then
+ GPGCHECK=1
+ GPG_URL="${RPM_GPG_URL}"
+ if [ "${RPM_REPO_GPG_URL}" != "-" ]; then
+ GPG_URL=$(cat </dev/null 2>&1; then
+ log_error "Cannot move ${ZIPDIR} contents to ${INSTALL_PATH}. Please check the permissions on the target directory."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+
+ if [ "${SYMLINK_PATH}" != "-" ]; then
+ log_info "Creating tofu symlink at ${SYMLINK_PATH}/tofu..."
+ if ! maybe_root ln -sf "${INSTALL_PATH}/tofu" "${SYMLINK_PATH}/tofu"; then
+ log_error "Failed to create symlink at ${INSTALL_PATH}/tofu."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ fi
+ log_info "Checking if OpenTofu is installed correctly..."
+ if [ "${SYMLINK_PATH}" != "-" ]; then
+ if ! "${SYMLINK_PATH}/tofu" --version; then
+ log_error "Failed to run ${SYMLINK_PATH}/tofu after installation."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ else
+ if ! "${INSTALL_PATH}/tofu" --version; then
+ log_error "Failed to run ${INSTALL_PATH}/tofu after installation."
+ return "${TOFU_INSTALL_EXIT_CODE_INSTALL_FAILED}"
+ fi
+ fi
+ log_success "Installation complete."
+ return "${TOFU_INSTALL_EXIT_CODE_OK}"
+}
+
+usage() {
+ if [ -n "$1" ]; then
+ log_error "Error: $1"
+ fi
+ cat </dev/null
-wget "https://github.com/opentofu/opentofu/releases/download/v${TOFU_VERSION}/tofu_${TOFU_VERSION}_${OS}_${ARCH}.zip"
-unzip "tofu_${TOFU_VERSION}_${OS}_${ARCH}.zip"
-sudo mv tofu /usr/local/bin/tofu
-popd >/dev/null
-rm -rf "${TEMPDIR}"
-echo "OpenTofu is now available at /usr/local/bin/tofu."
\ No newline at end of file
diff --git a/website/docs/intro/install/portable.mdx b/website/docs/intro/install/portable.mdx
deleted file mode 100644
index bfae5c657d..0000000000
--- a/website/docs/intro/install/portable.mdx
+++ /dev/null
@@ -1,31 +0,0 @@
----
-sidebar_position: 99
-sidebar_label: Portable (Linux/MacOS/Windows)
-description: |-
- Use OpenTofu as a portable binary without installation.
----
-
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
-import LinuxScript from '!!raw-loader!./portable-install.sh'
-import WindowsScript from '!!raw-loader!./portable-install.ps1'
-
-# Using OpenTofu as a portable binary
-
-You can run OpenTofu without installation as a portable binary. You can [download the latest release](https://github.com/opentofu/opentofu/releases/latest/) for your operating system from the [GitHub releases page](https://github.com/opentofu/opentofu/releases/latest/), unpack the zip and start using it. For easier updates, we recommend using the **non-portable packaged versions for your operating system**.
-
-:::tip Scripting downloads
-
-If you want to automate the updates of the portable binaries yourself you can do so by adapting the following scripts to your needs:
-
-
-
- {LinuxScript}
-
-
- {WindowsScript}
-
-
-
-:::
diff --git a/website/docs/intro/install/repo-yum.sh b/website/docs/intro/install/repo-yum.sh
index ddc30a1599..7f2d07ad6a 100644
--- a/website/docs/intro/install/repo-yum.sh
+++ b/website/docs/intro/install/repo-yum.sh
@@ -6,6 +6,7 @@ repo_gpgcheck=0
gpgcheck=1
enabled=1
gpgkey=https://get.opentofu.org/opentofu.gpg
+ https://packages.opentofu.org/opentofu/tofu/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
@@ -17,6 +18,7 @@ repo_gpgcheck=0
gpgcheck=1
enabled=1
gpgkey=https://get.opentofu.org/opentofu.gpg
+ https://packages.opentofu.org/opentofu/tofu/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
diff --git a/website/docs/intro/install/repo-zypper.sh b/website/docs/intro/install/repo-zypper.sh
index 65373ec570..78298f92b0 100644
--- a/website/docs/intro/install/repo-zypper.sh
+++ b/website/docs/intro/install/repo-zypper.sh
@@ -2,10 +2,11 @@ cat >/etc/zypp/repos.d/opentofu.repo <{RpmConvenienceScript}
+
## Step-by-step instructions
The following steps explain how to set up the OpenTofu RPM repositories. These instructions should work on most RPM-based Linux systems.
diff --git a/website/docs/intro/install/rpm.sh b/website/docs/intro/install/rpm.sh
index 1d3c806e44..cfbb94f73d 100755
--- a/website/docs/intro/install/rpm.sh
+++ b/website/docs/intro/install/rpm.sh
@@ -5,7 +5,7 @@ set -e
if [ -f /usr/bin/zypper ]; then
zypper install -y sudo
if [ "$1" = "--convenience" ]; then
- bash -ex rpm-convenience-zypper.sh
+ bash -ex rpm-convenience.sh
else
bash -ex repo-zypper.sh
bash -ex install-zypper.sh
@@ -13,7 +13,7 @@ if [ -f /usr/bin/zypper ]; then
else
yum install -y sudo
if [ "$1" = "--convenience" ]; then
- bash -ex rpm-convenience-yum.sh
+ bash -ex rpm-convenience.sh
else
bash -ex repo-yum.sh
bash -ex install-yum.sh
diff --git a/website/docs/intro/install/standalone-install.ps1 b/website/docs/intro/install/standalone-install.ps1
new file mode 100644
index 0000000000..58a8b0fb71
--- /dev/null
+++ b/website/docs/intro/install/standalone-install.ps1
@@ -0,0 +1,10 @@
+# Download the installer script:
+Invoke-WebRequest -outfile "install-opentofu.ps1" -uri "https://get.opentofu.org/install-opentofu.ps1"
+
+# Please inspect the downloaded script at this point.
+
+# Run the installer:
+& .\install-opentofu.ps1 -installMethod standalone
+
+# Remove the installer:
+Remove-Item install-opentofu.ps1
\ No newline at end of file
diff --git a/website/docs/intro/install/standalone-install.sh b/website/docs/intro/install/standalone-install.sh
new file mode 100644
index 0000000000..54a2e3eb98
--- /dev/null
+++ b/website/docs/intro/install/standalone-install.sh
@@ -0,0 +1,14 @@
+# Download the installer script:
+curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
+# Alternatively: wget --secure-protocol=TLSv1_2 --https-only https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
+
+# Grand execution permissions:
+chmod +x install-opentofu.sh
+
+# Please inspect the downloaded script at this point.
+
+# Run the installer:
+./install-opentofu.sh --install-method standalone
+
+# Remove the installer:
+rm install-opentofu.sh
\ No newline at end of file
diff --git a/website/docs/intro/install/standalone.mdx b/website/docs/intro/install/standalone.mdx
new file mode 100644
index 0000000000..ac1adb6c8c
--- /dev/null
+++ b/website/docs/intro/install/standalone.mdx
@@ -0,0 +1,68 @@
+---
+sidebar_position: 99
+sidebar_label: Standalone (Linux/MacOS/Windows)
+description: |-
+ Use OpenTofu as a standalone binary without installation.
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import CodeBlock from '@theme/CodeBlock';
+import LinuxScript from '!!raw-loader!./standalone-install.sh'
+import WindowsScript from '!!raw-loader!./standalone-install.ps1'
+import VerifyChecksumPS1 from '!!raw-loader!./verify-checksum.ps1'
+import VerifyChecksumLinux from '!!raw-loader!./verify-checksum-linux.sh'
+import VerifyChecksumMacOS from '!!raw-loader!./verify-checksum-macos.sh'
+import VerifyCosignLinux from '!!raw-loader!./verify-cosign.sh'
+import VerifyCosignWindows from '!!raw-loader!./verify-cosign.ps1'
+import Admonition from '@theme/Admonition';
+
+# Installing OpenTofu from GitHub Releases
+
+## Using the installer script
+
+
+
+ {LinuxScript}
+ The standalone installer verifies the integrity of the downloaded files. You need to install cosign, GnuPG, or disable the integrity verification by using the --skip-verify
option.
+
+
+ {WindowsScript}
+ If you run into script execution policy issues when running this script, please run Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
before running the installer.
+ The standalone installer verifies the integrity of the downloaded files. You need to install cosign, GnuPG, or disable the integrity verification by using the -skipVerify
option.
+
+
+
+
+## Using OpenTofu as a standalone binary
+
+You can run OpenTofu without installation as a standalone binary. You can [download the latest release](https://github.com/opentofu/opentofu/releases/latest/) for your operating system from the [GitHub releases page](https://github.com/opentofu/opentofu/releases/latest/), unpack the zip and start using it. For easier updates, we recommend using the **non-portable packaged versions for your operating system**.
+
+## Verify the file integrity
+
+Please download the `tofu_YOURVERSION_SHA256SUMS` file from the release. This file contains the SHA256 checksums for all files. You can verify the integrity of your file by running:
+
+
+
+ {VerifyChecksumLinux}
+
+
+ {VerifyChecksumMacOS}
+
+
+ {VerifyChecksumPS1}
+
+
+
+# Verifying the binaries with Cosign
+
+After you have verified the checksums, you can verify the integrity of the checksum file itself with [Cosign](https://docs.sigstore.dev/system_config/installation/). Please make sure you have installed Cosign and download the `tofu_YOURVERSION_SHA256SUMS.pem` and `tofu_YOURVERSION_SHA256SUMS.sig` files for your release. You can then run the integrity verification:
+
+
+
+ {VerifyCosignLinux}
+
+
+ {VerifyCosignWindows}
+
+
diff --git a/website/docs/intro/install/verify-checksum-linux.sh b/website/docs/intro/install/verify-checksum-linux.sh
new file mode 100644
index 0000000000..d17c64e3b3
--- /dev/null
+++ b/website/docs/intro/install/verify-checksum-linux.sh
@@ -0,0 +1,8 @@
+ZIPFILE=tofu_*.zip
+CHECKSUM=$(sha256sum "${ZIPFILE}" | cut -f 1 -d ' ')
+EXPECTED_CHECKSUM=$(grep "${ZIPFILE}" tofu_*_SHA256SUMS | cut -f 1 -d ' ')
+if [ "${CHECKSUM}" = "${EXPECTED_CHECKSUM}" ]; then
+ echo "OK"
+else
+ echo "MISMATCH"
+fi
\ No newline at end of file
diff --git a/website/docs/intro/install/verify-checksum-macos.sh b/website/docs/intro/install/verify-checksum-macos.sh
new file mode 100644
index 0000000000..89fec323fa
--- /dev/null
+++ b/website/docs/intro/install/verify-checksum-macos.sh
@@ -0,0 +1,8 @@
+ZIPFILE=tofu_*.zip
+CHECKSUM=$(shasum -a 256 "tofu_*.zip" | cut -f 1 -d ' ')
+EXPECTED_CHECKSUM=$(grep "${ZIPFILE}" tofu_*_SHA256SUMS | cut -f 1 -d ' ')
+if [ "${CHECKSUM}" = "${EXPECTED_CHECKSUM}" ]; then
+ echo "OK"
+else
+ echo "MISMATCH"
+fi
\ No newline at end of file
diff --git a/website/docs/intro/install/verify-checksum.ps1 b/website/docs/intro/install/verify-checksum.ps1
new file mode 100644
index 0000000000..94e1f8f0ff
--- /dev/null
+++ b/website/docs/intro/install/verify-checksum.ps1
@@ -0,0 +1,6 @@
+$zipFile="tofu_YOURVERSION_REPLACEME.zip"
+$checksum = $(Get-FileHash -Algorithm SHA256 $zipFile).Hash
+$expectedChecksum = $((Get-Content "tofu_YOURVERSION_REPLACEME_SHA256SUMS" | Select-String -Pattern $zipFile) -split '\s+')[0]
+if ($realHash -ne $expectedHash) {
+ Write-Error "Checksum mismatch"
+}
\ No newline at end of file
diff --git a/website/docs/intro/install/verify-cosign.ps1 b/website/docs/intro/install/verify-cosign.ps1
new file mode 100644
index 0000000000..dc77aa65f2
--- /dev/null
+++ b/website/docs/intro/install/verify-cosign.ps1
@@ -0,0 +1,10 @@
+$version = [version]"YOUR_OPENTOFU_VERSION"
+$identity = "https://github.com/opentofu/opentofu/.github/workflows/release.yml@refs/heads/v${version.Major}.${version.Minor}"
+# For alpha and beta builds use /main
+cosign.exe `
+ verify-blob `
+ --certificate-identity $identity `
+ --signature "tofu_YOURVERSION_REPLACEME.sig" `
+ --certificate "tofu_YOURVERSION_REPLACEME.pem" `
+ --certificate-oidc-issuer "https://token.actions.githubusercontent.com" `
+ "tofu_YOURVERSION_REPLACEME_SHA256SUMS"
\ No newline at end of file
diff --git a/website/docs/intro/install/verify-cosign.sh b/website/docs/intro/install/verify-cosign.sh
new file mode 100644
index 0000000000..9c2b228c2c
--- /dev/null
+++ b/website/docs/intro/install/verify-cosign.sh
@@ -0,0 +1,10 @@
+OPENTOFU_VERSION_MAJORMINOR="Add your OpenTofu major and minor version here"
+IDENTITY="https://github.com/opentofu/opentofu/.github/workflows/release.yml@refs/heads/v${OPENTOFU_VERSION_MAJORMINOR}"
+# For alpha and beta builds use /main
+cosign \
+ verify-blob \
+ --certificate-identity "${IDENTITY}" \
+ --signature "tofu_*.sig" \
+ --certificate "tofu_*.pem" \
+ --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
+ "tofu_*_SHA256SUMS"
\ No newline at end of file