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