diff --git a/install/tk.sh b/install/tk.sh
index f16a2a1a5de752d964e65aaf53e5bdea4da60ad0..7962bcb84ac462685b9afe8ef370eeb1d4cdbc78 100755
--- a/install/tk.sh
+++ b/install/tk.sh
@@ -1,51 +1,183 @@
 #!/usr/bin/env bash
-
 set -e
 
 DEFAULT_BIN_DIR="/usr/local/bin"
-BIN_DIR=${1:-"$DEFAULT_BIN_DIR"}
-
-opsys=""
-if [[ "$OSTYPE" == linux* ]]; then
-  opsys=linux
-elif [[ "$OSTYPE" == darwin* ]]; then
-  opsys=darwin
-fi
-
-if [[ "$opsys" == "" ]]; then
-  echo "OS $OSTYPE not supported"
-  exit 1
-fi
-
-if [[ ! -x "$(command -v curl)" ]]; then
-    echo "curl not found"
+BIN_DIR=${1:-"${DEFAULT_BIN_DIR}"}
+GITHUB_REPO="fluxcd/toolkit"
+
+# Helper functions for logs
+info() {
+    echo '[INFO] ' "$@"
+}
+
+warn() {
+    echo '[WARN] ' "$@" >&2
+}
+
+fatal() {
+    echo '[ERROR] ' "$@" >&2
     exit 1
-fi
+}
 
-tmpDir=`mktemp -d`
-if [[ ! "$tmpDir" || ! -d "$tmpDir" ]]; then
-  echo "could not create temp dir"
-  exit 1
-fi
+# Set os, fatal if operating system not supported
+setup_verify_os() {
+    if [[ -z "${OS}" ]]; then
+        OS=$(uname)
+    fi
+    case ${OS} in
+        Darwin)
+            OS=darwin
+            ;;
+        Linux)
+            OS=linux
+            ;;
+        *)
+            fatal "Unsupported operating system ${OS}"
+    esac
+}
 
-function cleanup {
-  rm -rf "$tmpDir"
+# Set arch, fatal if architecture not supported
+setup_verify_arch() {
+    if [[ -z "${ARCH}" ]]; then
+        ARCH=$(uname -m)
+    fi
+    case ${ARCH} in
+        amd64)
+            ARCH=amd64
+            ;;
+        x86_64)
+            ARCH=amd64
+            ;;
+        *)
+            fatal "Unsupported architecture ${ARCH}"
+    esac
 }
 
-trap cleanup EXIT
+# Verify existence of downloader executable
+verify_downloader() {
+    # Return failure if it doesn't exist or is no executable
+    [[ -x "$(which "$1")" ]] || return 1
 
-pushd $tmpDir >& /dev/null
+    # Set verified executable as our downloader program and return success
+    DOWNLOADER=$1
+    return 0
+}
 
-curl -s https://api.github.com/repos/fluxcd/toolkit/releases/latest |\
-  grep browser_download |\
-  grep $opsys |\
-  cut -d '"' -f 4 |\
-  xargs curl -sL -o tk.tar.gz
+# Create tempory directory and cleanup when done
+setup_tmp() {
+    TMP_DIR=$(mktemp -d -t tk-install.XXXXXXXXXX)
+    TMP_METADATA="${TMP_DIR}/tk.json"
+    TMP_HASH="${TMP_DIR}/tk.hash"
+    TMP_BIN="${TMP_DIR}/tk.tar.gz"
+    cleanup() {
+        code=$?
+        set +e
+        trap - EXIT
+        rm -rf "${TMP_DIR}"
+        exit ${code}
+    }
+    trap cleanup INT EXIT
+}
 
-tar xzf ./tk.tar.gz
+# Find version from Github metadata
+get_release_version() {
+    METADATA_URL="https://api.github.com/repos/${GITHUB_REPO}/releases/latest"
 
-mv ./tk $BIN_DIR
+    info "Downloading metadata ${METADATA_URL}"
+    download "${TMP_METADATA}" "${METADATA_URL}"
 
-popd >& /dev/null
+    VERSION_TK=$(grep '"tag_name":' "${TMP_METADATA}" | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-)
+    if [[ -n "${VERSION_TK}" ]]; then
+        info "Using ${VERSION_TK} as release"
+    else
+        fatal "Unable to determine release version"
+    fi
+}
 
-echo "$(tk --version) installed"
+# Download from file from URL
+download() {
+    [[ $# -eq 2 ]] || fatal 'download needs exactly 2 arguments'
+
+    case $DOWNLOADER in
+        curl)
+            curl -o "$1" -sfL "$2"
+            ;;
+        wget)
+            wget -qO "$1" "$2"
+            ;;
+        *)
+            fatal "Incorrect executable '${DOWNLOADER}'"
+            ;;
+    esac
+
+    # Abort if download command failed
+    [[ $? -eq 0 ]] || fatal 'Download failed'
+}
+
+# Download hash from Github URL
+download_hash() {
+    HASH_URL="https://github.com/${GITHUB_REPO}/releases/download/v${VERSION_TK}/toolkit_${VERSION_TK}_checksums.txt"
+    info "Downloading hash ${HASH_URL}"
+    download "${TMP_HASH}" "${HASH_URL}"
+    HASH_EXPECTED=$(grep " tk_${VERSION_TK}_${OS}_${ARCH}.tar.gz$" "${TMP_HASH}")
+    HASH_EXPECTED=${HASH_EXPECTED%%[[:blank:]]*}
+}
+
+# Download binary from Github URL
+download_binary() {
+    BIN_URL="https://github.com/${GITHUB_REPO}/releases/download/v${VERSION_TK}/tk_${VERSION_TK}_${OS}_${ARCH}.tar.gz"
+    info "Downloading binary ${BIN_URL}"
+    download "${TMP_BIN}" "${BIN_URL}"
+}
+
+compute_sha256sum() {
+  cmd=$(which sha256sum shasum | head -n 1)
+  case $(basename "$cmd") in
+    sha256sum)
+      sha256sum "$1" | cut -f 1 -d ' '
+      ;;
+    shasum)
+      shasum -a 256 "$1" | cut -f 1 -d ' '
+      ;;
+    *)
+      fatal "Can not find sha256sum or shasum to compute checksum"
+      ;;
+  esac
+}
+
+# Verify downloaded binary hash
+verify_binary() {
+    info "Verifying binary download"
+    HASH_BIN=$(compute_sha256sum "${TMP_BIN}")
+    HASH_BIN=${HASH_BIN%%[[:blank:]]*}
+    if [[ "${HASH_EXPECTED}" != "${HASH_BIN}" ]]; then
+        fatal "Download sha256 does not match ${HASH_EXPECTED}, got ${HASH_BIN}"
+    fi
+}
+
+# Setup permissions and move binary
+setup_binary() {
+    chmod 755 "${TMP_BIN}"
+    info "Installing tk to ${BIN_DIR}/tk"
+    tar -xzf "${TMP_BIN}" -C "${TMP_DIR}"
+
+    local CMD_MOVE="mv -f \"${TMP_DIR}/tk\" \"${BIN_DIR}\""
+    if [[ -w "${BIN_DIR}" ]]; then
+        eval "${CMD_MOVE}"
+    else
+        eval "sudo ${CMD_MOVE}"
+    fi
+}
+
+# Run the install process
+{
+    setup_verify_os
+    setup_verify_arch
+    verify_downloader curl || verify_downloader wget || fatal 'Can not find curl or wget for downloading files'
+    setup_tmp
+    get_release_version
+    download_hash
+    download_binary
+    verify_binary
+    setup_binary
+}