#!/bin/bash set -e usage() { echo "Usage: $(basename $0) [-t ] [-v ] [-p ] <-a [amd64/x86_64]|[386/i386]|arm|arm64> <-r fips> <-s tarball source dir>" 1>&2 exit 1 } # Don't follow sourced script. #shellcheck disable=SC1090 #shellcheck disable=SC1091 . "$(dirname "$0")/build-common.sh" while getopts ":t:v:p:a:r:s:n" o; do case "${o}" in t) t=${OPTARG} if [[ ${t} != "oss" && ${t} != "ent" ]]; then usage; fi ;; v) v=${OPTARG} ;; p) p=${OPTARG} if [[ ${p} != "rpm" && ${p} != "deb" && ${p} != "pkg" ]]; then usage; fi ;; a) a=${OPTARG} if [[ ${a} != "amd64" && ${a} != "x86_64" && ${a} != "386" && ${a} != "i386" && ${a} != "arm" && ${a} != "arm64" ]]; then usage; fi ;; r) r=${OPTARG} if [[ ${r} != "fips" ]]; then usage; fi ;; s) s=${OPTARG} ;; n) # Dry-run mode. # Only affects parts of the script, use at your own peril! DRY_RUN_PREFIX='echo + ' ;; *) usage ;; esac done shift $((OPTIND-1)) if [ -z "${t}" ] || [ -z "${v}" ] || [ -z "${p}" ]; then usage fi TELEPORT_TYPE="$t" TELEPORT_VERSION="$v" PACKAGE_TYPE="$p" ARCH="$a" RUNTIME="$r" TARBALL_DIRECTORY="$s" GNUPG_DIR=${GNUPG_DIR:-/tmp/gnupg} # linux package configuration LINUX_BINARY_DIR=/usr/local/bin LINUX_SYSTEMD_DIR=/lib/systemd/system LINUX_CONFIG_DIR=/etc LINUX_DATA_DIR=/var/lib/teleport # extra package information for linux MAINTAINER="info@goteleport.com" LICENSE="Apache-2.0" VENDOR="Gravitational" DESCRIPTION="Teleport is a gateway for managing access to clusters of Linux servers via SSH or the Kubernetes API" DOCS_URL="https://goteleport.com/docs" # check that curl is installed if [[ ! $(type curl) ]]; then echo "curl must be installed" exit 2 fi # check that tar is installed if [[ ! $(type tar) ]]; then echo "tar must be installed" exit 11 fi # check that docker is installed when fpm is needed to build if [[ "${PACKAGE_TYPE}" != "pkg" ]]; then if [[ ! $(type docker) ]]; then echo "docker must be installed to build non-OSX packages" exit 3 fi fi # check that pkgbuild is installed if building for OS X and set variables appropriately if [[ "${PACKAGE_TYPE}" == "pkg" ]]; then if ! uname | grep -q Darwin; then echo "You must be running on OS X to build .pkg files" exit 4 fi if [[ "${ARCH}" != "" ]]; then echo "arch parameter is ignored when building for OS X" unset ARCH fi if [[ "${RUNTIME}" != "" ]]; then echo "runtime parameter is ignored when building for OS X" unset RUNTIME fi PLATFORM="darwin" ARCH="amd64" if [[ ! $(type pkgbuild) ]]; then echo "You need to install pkgbuild" echo "Run: xcode-select --install" exit 5 fi else PLATFORM="linux" # if arch isn't set for other package types, throw an error if [[ "${ARCH}" == "" ]]; then usage fi # set docker image appropriately if [[ "${PACKAGE_TYPE}" == "deb" ]]; then DOCKER_IMAGE="quay.io/gravitational/fpm-debian:8" elif [[ "${PACKAGE_TYPE}" == "rpm" ]]; then DOCKER_IMAGE="quay.io/gravitational/fpm-centos:8" fi fi # handle differences between 'gravitational' arch and system arch if [[ "${ARCH}" == "386" || "${ARCH}" == "i386" ]]; then TEXT_ARCH="32-bit x86" TARBALL_ARCH="386" DEB_PACKAGE_ARCH="i386" DEB_OUTPUT_ARCH="i386" RPM_PACKAGE_ARCH="i386" RPM_OUTPUT_ARCH="i386" elif [[ "${ARCH}" == "amd64" || "${ARCH}" == "x86_64" ]]; then TEXT_ARCH="64-bit x86" TARBALL_ARCH="amd64" DEB_PACKAGE_ARCH="amd64" DEB_OUTPUT_ARCH="amd64" RPM_PACKAGE_ARCH="x86_64" RPM_OUTPUT_ARCH="x86_64" elif [[ "${ARCH}" == "arm" ]]; then TEXT_ARCH="32-bit ARM" TARBALL_ARCH="arm" # 32-bit arm can be hardfloat and softfloat, and we build for linux-gnueabihf DEB_PACKAGE_ARCH="armhf" DEB_OUTPUT_ARCH="arm" # backwards compatibility RPM_PACKAGE_ARCH="armv7hl" RPM_OUTPUT_ARCH="arm" # backwards compatibility elif [[ "${ARCH}" == "arm64" ]]; then TEXT_ARCH="64-bit ARM" TARBALL_ARCH="arm64" DEB_PACKAGE_ARCH="arm64" DEB_OUTPUT_ARCH="arm64" RPM_PACKAGE_ARCH="aarch64" RPM_OUTPUT_ARCH="arm64" # backwards compatibility fi # amd64 RPMs should use CentOS 7 compatible artifacts if [[ "${PACKAGE_TYPE}" == "rpm" && "${RPM_PACKAGE_ARCH}" == "x86_64" ]]; then OPTIONAL_TARBALL_SECTION+="-centos7" fi # set optional runtime section for filename if [[ "${RUNTIME}" == "fips" ]]; then OPTIONAL_RUNTIME_SECTION+="-fips" fi # set variables appropriately depending on type of package being built if [[ "${TELEPORT_TYPE}" == "ent" ]]; then TARBALL_FILENAME="teleport-ent-v${TELEPORT_VERSION}-${PLATFORM}-${TARBALL_ARCH}${OPTIONAL_TARBALL_SECTION}${OPTIONAL_RUNTIME_SECTION}-bin.tar.gz" TAR_PATH="teleport-ent" RPM_NAME="teleport-ent" if [[ "${RUNTIME}" == "fips" ]]; then TYPE_DESCRIPTION="[${TEXT_ARCH} Enterprise edition, built with FIPS support]" RPM_NAME="teleport-ent-fips" else TYPE_DESCRIPTION="[${TEXT_ARCH} Enterprise edition]" fi else TARBALL_FILENAME="teleport-v${TELEPORT_VERSION}-${PLATFORM}-${TARBALL_ARCH}${OPTIONAL_TARBALL_SECTION}${OPTIONAL_RUNTIME_SECTION}-bin.tar.gz" TAR_PATH="teleport" RPM_NAME="teleport" if [[ "${RUNTIME}" == "fips" ]]; then TYPE_DESCRIPTION="[${TEXT_ARCH} Open source edition, built with FIPS support]" RPM_NAME="teleport-fips" else TYPE_DESCRIPTION="[${TEXT_ARCH} Open source edition]" fi fi # set file list if [[ "${PACKAGE_TYPE}" == "pkg" ]]; then SIGN_PKG="true" FILE_LIST="${TAR_PATH}/tsh ${TAR_PATH}/tctl ${TAR_PATH}/teleport ${TAR_PATH}/tbot" BUNDLE_ID="com.gravitational.teleport" if [[ "${TELEPORT_TYPE}" == "ent" ]]; then PKG_FILENAME="teleport-ent-${TELEPORT_VERSION}.${PACKAGE_TYPE}" else PKG_FILENAME="teleport-${TELEPORT_VERSION}.${PACKAGE_TYPE}" fi else FILE_LIST="${TAR_PATH}/tsh ${TAR_PATH}/tctl ${TAR_PATH}/teleport ${TAR_PATH}/tbot ${TAR_PATH}/examples/systemd/teleport.service" LINUX_BINARY_FILE_LIST="${TAR_PATH}/tsh ${TAR_PATH}/tctl ${TAR_PATH}/tbot ${TAR_PATH}/teleport" LINUX_SYSTEMD_FILE_LIST="${TAR_PATH}/examples/systemd/teleport.service" EXTRA_DOCKER_OPTIONS="" RPM_SIGN_STANZA="" if [[ "${PACKAGE_TYPE}" == "rpm" ]]; then PACKAGE_ARCH="${RPM_PACKAGE_ARCH}" OUTPUT_FILENAME="${TAR_PATH}-${TELEPORT_VERSION}-1${OPTIONAL_RUNTIME_SECTION}.${RPM_OUTPUT_ARCH}.rpm" FILE_PERMISSIONS_STANZA="--rpm-user root --rpm-group root --rpm-use-file-permissions " # the rpm/rpmmacros file suppresses the creation of .build-id files (see https://github.com/gravitational/teleport/issues/7040) EXTRA_DOCKER_OPTIONS="-v $(pwd)/rpm/rpmmacros:/root/.rpmmacros" # if we set this environment variable, don't sign RPMs (can be useful for building test RPMs # without having the signing keys) if [ "${UNSIGNED_RPM}" == "true" ]; then echo "RPMs will not be signed as requested" else # the GNUPG_DIR location here is assumed to contain a complete ~/.gnupg directory structure # with pubring.kbx and trustdb.gpg files, plus a private-keys-v1.d directory with signing keys # it needs to contain the "Gravitational, Inc" private key and signing key. # we also use the rpm-sign/rpmmacros file instead which contains extra directives used for signing. EXTRA_DOCKER_OPTIONS="-v $(pwd)/rpm-sign/rpmmacros:/root/.rpmmacros -v $(pwd)/rpm-sign/popt-override:/etc/popt.d/rpmsign-override -v ${GNUPG_DIR}:/root/.gnupg" RPM_SIGN_STANZA="--rpm-sign" fi elif [[ "${PACKAGE_TYPE}" == "deb" ]]; then PACKAGE_ARCH="${DEB_PACKAGE_ARCH}" OUTPUT_FILENAME="${TAR_PATH}_${TELEPORT_VERSION}${OPTIONAL_RUNTIME_SECTION}_${DEB_OUTPUT_ARCH}.deb" FILE_PERMISSIONS_STANZA="--deb-user root --deb-group root " fi fi # create a temporary directory and download specified Teleport version pushd "$(mktemp -d)" PACKAGE_TEMPDIR=$(pwd) # automatically clean up on exit trap 'rm -rf ${PACKAGE_TEMPDIR}' EXIT mkdir -p ${PACKAGE_TEMPDIR}/buildroot # Find or download tarball to the local file cache. tarname="$TARBALL_FILENAME" [[ -n "$TARBALL_DIRECTORY" ]] && tarname="$TARBALL_DIRECTORY/$TARBALL_FILENAME" tarout='' # find_or_fetch_tarball writes to this find_or_fetch_tarball "$tarname" tarout TARBALL_DIRECTORY="$(dirname "$tarout")" TARBALL_FILENAME="$(basename "$tarout")" # for consistency, shouldn't change echo "Found ${TARBALL_DIRECTORY}/${TARBALL_FILENAME} - using it" # extract necessary files from tarball tar -C "$(pwd)" -xvzf ${TARBALL_DIRECTORY}/${TARBALL_FILENAME} ${FILE_LIST} # move files into correct locations before building the package if [[ "${PACKAGE_TYPE}" != "pkg" ]]; then if [[ "${LINUX_BINARY_FILE_LIST}" != "" ]]; then mkdir -p ${PACKAGE_TEMPDIR}/buildroot${LINUX_BINARY_DIR} mv -v ${LINUX_BINARY_FILE_LIST} ${PACKAGE_TEMPDIR}/buildroot${LINUX_BINARY_DIR} fi if [[ "${LINUX_SYSTEMD_FILE_LIST}" != "" ]]; then mkdir -p ${PACKAGE_TEMPDIR}/buildroot${LINUX_SYSTEMD_DIR} mv -v ${LINUX_SYSTEMD_FILE_LIST} ${PACKAGE_TEMPDIR}/buildroot${LINUX_SYSTEMD_DIR} fi if [[ "${LINUX_CONFIG_FILE}" != "" ]]; then mkdir -p ${PACKAGE_TEMPDIR}/buildroot${LINUX_CONFIG_DIR} mv -v ${LINUX_CONFIG_FILE} ${PACKAGE_TEMPDIR}/buildroot${LINUX_CONFIG_DIR} CONFIG_FILE_STANZA="--config-files /src/buildroot${LINUX_CONFIG_DIR}/${LINUX_CONFIG_FILE} " fi # /var/lib/teleport # shellcheck disable=SC2174 mkdir -p -m0700 ${PACKAGE_TEMPDIR}/buildroot${LINUX_DATA_DIR} fi popd if [[ "${PACKAGE_TYPE}" == "pkg" ]]; then # erase any existing versions of the package in the output directory first rm -f ${PKG_FILENAME} if [[ "${SIGN_PKG}" == "true" ]]; then # run codesign to sign binaries for FILE in ${FILE_LIST}; do $DRY_RUN_PREFIX codesign -s "${DEVELOPER_ID_APPLICATION}" \ -f \ -v \ --timestamp \ --options runtime \ ${PACKAGE_TEMPDIR}/${FILE} done fi # build the package for OS X pkgbuild \ --root ${PACKAGE_TEMPDIR}/${TAR_PATH} \ --identifier ${BUNDLE_ID} \ --version ${TELEPORT_VERSION} \ --install-location /usr/local/bin \ ${PKG_FILENAME} if [[ "${SIGN_PKG}" == "true" ]]; then # mark package as unsigned first mv ${PKG_FILENAME} ${PKG_FILENAME}.unsigned # run productsign to sign package $DRY_RUN_PREFIX productsign \ --sign "${DEVELOPER_ID_INSTALLER}" \ --timestamp \ ${PKG_FILENAME}.unsigned \ ${PKG_FILENAME} [[ -n "$DRY_RUN_PREFIX" ]] && cp "$PKG_FILENAME.unsigned" "$PKG_FILENAME" # remove unsigned package after successful signing rm -f ${PKG_FILENAME}.unsigned notarize "$PKG_FILENAME" "$TEAMID" "$BUNDLE_ID" fi # checksum created packages for PACKAGE in *."${PACKAGE_TYPE}"; do shasum -a 256 ${PACKAGE} > ${PACKAGE}.sha256 done else # erase any existing packages of the same type/version/arch in the output directory first rm -vf ${OUTPUT_FILENAME} # build for other platforms docker run -v ${PACKAGE_TEMPDIR}:/src --rm ${EXTRA_DOCKER_OPTIONS} ${DOCKER_IMAGE} \ fpm \ --input-type dir \ --output-type ${PACKAGE_TYPE} \ --name ${RPM_NAME} \ --version "${TELEPORT_VERSION}" \ --maintainer "${MAINTAINER}" \ --url "${DOCS_URL}" \ --license "${LICENSE}" \ --vendor "${VENDOR}" \ --description "${DESCRIPTION} ${TYPE_DESCRIPTION}" \ --architecture ${PACKAGE_ARCH} \ --package ${OUTPUT_FILENAME} \ --chdir /src/buildroot \ --directories ${LINUX_DATA_DIR} \ --provides teleport \ --prefix / \ --verbose \ ${CONFIG_FILE_STANZA} \ ${FILE_PERMISSIONS_STANZA} \ ${RPM_SIGN_STANZA} . # copy created package back to current directory cp ${PACKAGE_TEMPDIR}/*."${PACKAGE_TYPE}" . # checksum created packages for FILE in *."${PACKAGE_TYPE}"; do sha256sum ${FILE} > ${FILE}.sha256 done fi