Files
labca/install
Arjan H 0745c10d12 Restore MySQL data after renaming containers (#75)
When we changed the docker-compose project name from boulder to labca, we should
have also taken care of moving existing DB data from the old docker volume to the
new one. Now we do this in case anyone else upgrades from a pre-v23.05 release.

Also, clean up gorp_migrations table so the in-place upgrades will actually work.
2023-06-28 20:15:51 +02:00

905 lines
32 KiB
Bash
Executable File

#!/usr/bin/env bash
# LabCA: a private Certificate Authority for internal lab usage
# (c) 2018-2023 Arjan Hakkesteegt
#
# Install with this command from a Linux machine (only tested with Debian and Ubuntu):
# curl -sSL https://raw.githubusercontent.com/hakwerk/labca/master/install | bash
set -eEo pipefail
trap 'err_report $? $LINENO' INT TERM ERR
err_report() {
msg_fatal "return code $1 on line $2 in $(basename $0)" $1
}
#
# Variables / Constants
#
installMode=${installMode:-normal}
baseDir=${baseDir:-/home/labca}
logDir=${logDir:-"$baseDir/logs"}
runId="`date +%y%m%d-%H%M%S`"
installLog="$logDir/install-${runId}.log"
logTimeFormat="+%Y-%m-%d %T.%3N"
cloneDir=${cloneDir:-"$baseDir/labca"}
adminDir=${adminDir:-"$baseDir/admin"}
boulderDir=${boulderDir:-"$baseDir/boulder"}
boulderLabCADir=${boulderLabCADir:-"${boulderDir}_labca"}
dockerComposeVersion="v2.5.0"
labcaUrl="https://github.com/hakwerk/labca/"
boulderUrl="https://github.com/letsencrypt/boulder/"
boulderTag="release-2023-06-12"
# Feature flags
flag_skip_redis=true
#
# Color configuration
#
COL_NC='\e[0m' # No Color
COL_LIGHT_GREEN='\e[1;32m'
COL_LIGHT_RED='\e[1;31m'
TICK="[${COL_LIGHT_GREEN}${COL_NC}]"
CROSS="[${COL_LIGHT_RED}${COL_NC}]"
INFO="[.]"
DONE="${COL_LIGHT_GREEN} done!${COL_NC}"
OVER="\\r\\033[K"
# Dummy implementation in case utils.sh is not available (install via curl method)
wait_down() {
sleep 1
}
wait_up() {
sleep 5
}
count() {
echo 0
}
dn=$(dirname $0)
source "$dn/utils.sh" &>/dev/null || true
cmdlineFqdn=""
cmdlineBranch=""
fullCmdline=""
keepLocal=0
alphaTest=0
#
# Helper functions for informing the user and logging to file
#
msg_info() {
local msg="$1"
echo -ne " ${INFO} ${msg}..."
echo "[`date "${logTimeFormat}"`] [INFO ] ${msg}..." >> $installLog
}
msg_ok() {
local msg="$1"
echo -e "${OVER} ${TICK} ${msg}"
echo "[`date "${logTimeFormat}"`] [OK ] ${msg}" >> $installLog
}
msg_err() {
local msg="$1"
echo -e "${OVER} ${CROSS} ${msg}"
echo "[`date "${logTimeFormat}"`] [ERROR] ${msg}" >> $installLog
}
msg_fatal() {
local msg="$1"
echo -e "\\n ${COL_LIGHT_RED}Error: ${msg}${COL_NC}\\n"
echo "[`date "${logTimeFormat}"`] [FATAL] ${msg}" >> $installLog
exit ${2:-1}
}
#
# Log to /tmp first in case the labca user doesn't exist yet
#
start_temporary_log() {
backupLog=$installLog
installLog="/tmp/labca-install-$$.log"
touch "$installLog"
}
end_temporary_log() {
mv "$installLog" "$backupLog"
installLog=$backupLog
chown labca:labca "$installLog"
}
# Must run as root
check_root() {
if [ "$EUID" -eq 0 ]; then
msg_ok "Running as root"
else
msg_err "Not running as root"
local msg="Run using sudo"
if command -v sudo &> /dev/null; then
msg_ok "$msg"
exec curl -sSL https://raw.githubusercontent.com/hakwerk/labca/master/install | sudo bash "$@"
exit $?
else
msg_err "$msg"
echo -e " ${COL_LIGHT_RED}Script should be run as the root user${COL_NC}"
fi
fi
}
# Create dedicated user
labca_user() {
adduser --gecos "LabCA,,," --disabled-login labca &>>$installLog && msg_ok "Created user 'labca'" || msg_ok "User 'labca' already exists"
[ -d "$logDir" ] || mkdir "$logDir"
chown -R labca:labca "$logDir"
cd ~labca
local gig=$(sudo -u labca -H git config --global core.excludesfile 2>/dev/null)
if [ -z "$gig" ]; then
sudo -u labca -H git config --global core.excludesfile /home/labca/.gitignore_global >/dev/null 2>&1 || msg_info "WARNING: could not set core.excludesfile"
gig=$(sudo -u labca -H git config --global core.excludesfile 2>/dev/null)
fi
gig=${gig/\~/\/home\/labca}
gig=${gig:-/home/labca/.gitignore_global}
[ -e "$gig" ] || sudo -u labca -H touch $gig
sudo -u labca -H grep config_labca "$gig" >/dev/null 2>&1 || sudo -u labca -H echo "config_labca/" >> "$gig"
}
#
# Get the latest code from the git repository
#
clone_repo() {
local dir="$1"
local url="$2"
local branch="$3"
local msg="Clone $url to $dir"
msg_info "$msg"
sudo -u labca -H git clone -q "$url" "$dir" &>>$installLog && msg_ok "$msg" || msg_fatal "Could not clone git repository"
if [ "$branch" != "" ]; then
cd "$dir"
sudo -u labca -H git checkout $branch &>>$installLog
cd - >/dev/null
fi
}
pull_repo() {
local dir="$1"
local branch="$2"
cd "$dir" &>>$installLog || msg_fatal "Could not switch to directory '$dir'"
local msg="Update git repository in $dir"
msg_info "$msg"
sudo -u labca -H git stash --all --quiet &>>$installLog || true
sudo -u labca -H git clean --quiet --force -d &>>$installLog || true
sudo -u labca -H git pull --quiet &>>$installLog && msg_ok "$msg" || (
if [ "$dir" == "$GOPATH/src/github.com/letsencrypt/boulder" ]; then
sudo -u labca -H git reset --hard $boulderTag &>>$installLog && msg_ok "$msg" || msg_fatal "Could not reset local repository"
sudo -u labca -H git pull --quiet &>>$installLog && msg_ok "$msg" || msg_fatal "Could not update local repository (after reset)"
else
msg_fatal "Could not update local repository"
fi
)
if [ "$branch" != "" ]; then
cd "$dir"
sudo -u labca -H git checkout $branch &>>$installLog
cd - >/dev/null
fi
}
clone_or_pull() {
local dir="$1"
local url="$2"
local branch="$3"
local parentdir=$(dirname "$dir")
local dirbase=$(basename "$dir")
local found=0
for sd in $(git config --global --get-all safe.directory); do
if [ "$sd" == "$dir" ]; then
found=1
fi
done
if [ $found -eq 0 ]; then
git config --global --add safe.directory $dir
fi
if [ -d "$dir" ]; then
local rc=0
cd "$dir"
sudo -u labca -H git status --short &> /dev/null || rc=$?
if [ $rc -gt 0 ]; then
cd "$parentdir"
mv "$dirbase" "${dirbase}_${runId}" && msg_ok "Backup existing non-git directory '$dir'"
clone_repo "$dir" "$url" "$branch"
else
pull_repo "$dir" "$branch"
fi
else
clone_repo "$dir" "$url" "$branch"
fi
}
# Checkout the latest release tag
checkout_release() {
local branch="$1"
if [ "$branch" == "" ] || [ "$branch" == "master" ] || [ "$branch" == "main" ]; then
cd "$cloneDir"
if [ "$curChecksum" == "" ]; then
curChecksum=$(md5sum $cloneDir/install 2>/dev/null | cut -d' ' -f1)
fi
TAG=$(sudo -u labca -H git describe --tags $(sudo -u labca -H git rev-list --tags --max-count=1))
sudo -u labca -H git reset --hard $TAG &>>$installLog
fi
}
# Restart the script if it was updated itself
restart_if_updated() {
local gitRev=$(cd $cloneDir && sudo -u labca -H git describe --always --tags)
echo "=== version $gitRev ($curChecksum) ===" >>$installLog
if [ "$curChecksum" != "" ]; then
local newChecksum=$(md5sum $cloneDir/install 2>/dev/null | cut -d' ' -f1)
if [ "$curChecksum" != "$newChecksum" ]; then
msg_info "Restarting updated version of install script"
echo
exec $cloneDir/install $fullCmdline
exit $?
fi
fi
}
# Utility method to prompt the user for a config variable and export it
prompt_and_export() {
local varName="$1"
local varDefault="$2"
local promptMsg="$3"
local answer
read -p "$promptMsg [$varDefault] " answer </dev/tty
if [ "$answer" ]; then
export $varName="$answer"
else
export $varName="$varDefault"
fi
}
# Parse the command line options, if any
parse_cmdline() {
fullCmdline="$@"
local parsed=$(getopt --options=n:,b:,k,t --longoptions=name:,fqdn:,branch:,keep,test --name "$0" -- "$@" 2>>$installLog) || msg_fatal "Could not process commandline parameters"
eval set -- "$parsed"
while true; do
case "$1" in
-n|--name|--fqdn)
cmdlineFqdn="$2"
shift 2
msg_ok "option: using FQDN name '$cmdlineFqdn'"
;;
-b|--branch)
cmdlineBranch="$2"
shift 2
msg_ok "option: using branch '$cmdlineBranch'"
;;
-k|--keep)
keepLocal=1
shift 1
msg_ok "option: keeping local version as is"
;;
-t|--test)
alphaTest=1
shift 1
msg_ok "option: INCLUDING ALPHA TEST STEPS"
;;
--)
shift
break
;;
*)
msg_fatal "Should not have reached this"
;;
esac
done
}
# Utility method to check if value looks like a host + domain
has_domain() {
local dom="$1"
if [[ "$dom" =~ ^\..*$ ]]; then
false
elif [[ "$dom" =~ ^.*\.$ ]]; then
false
elif [[ "$dom" =~ ^.*\..*$ ]]; then
true
else
false
fi
}
# Determine the remote address of this machine from (in order): commandline parameter,
# existing configuration or full hostname.
get_fqdn() {
local cfgFile="$adminDir/data/config.json"
local cfgFqdn=$(grep fqdn $cfgFile 2>/dev/null | grep -v LABCA_FQDN | cut -d ":" -f 2- | tr -d " \"," || echo "")
LABCA_FQDN=${cfgFqdn:-$(hostname -f)}
while [ "$cfgFqdn" == "" ]; do
if [ "$cmdlineFqdn" != "" ]; then
export LABCA_FQDN="$cmdlineFqdn"
else
prompt_and_export LABCA_FQDN "$LABCA_FQDN" "FQDN (Fully Qualified Domain Name) for this PKI host (users will use this in their browsers and clients)?"
fi
if has_domain $LABCA_FQDN; then
cfgFqdn="ok"
else
msg_err "FQDN must include a hostname AND a domain!"
cmdlineFqdn=""
fi
done
if ! has_domain $LABCA_FQDN; then
msg_fatal "FQDN must include a hostname AND a domain!"
fi
msg_ok "Determine web address"
}
# Utility method to replace all instances of given variables in a file
replace_all() {
local filename="$1"
local var
for var in ${@:2}; do
sed -i -e "s|$var|${!var}|g" $filename
done
}
# Copy and configure the admin tree from the local repository
copy_admin() {
local rc=0
local msg="Setup admin application"
msg_info "$msg"
[ -d "$adminDir" ] || mkdir "$adminDir"
cd "$adminDir"
git config --global --add safe.directory "$adminDir"
git status --short &> /dev/null || rc=$?
if [ $rc -gt 0 ]; then
git init &>>$installLog
fi
git add --all &>/dev/null || true
git commit --all --quiet -m "LabCA before update $runId" &>>$installLog && { msg_ok "Commit existing modifications of $adminDir"; msg_info "$msg"; } || true
cp -rp $cloneDir/gui/* "./" &>>$installLog || msg_fatal "Cannot copy the admin files to $adminDir"
msg_ok "$msg"
msg="Configure the admin application"
msg_info "$msg"
[ -e "$adminDir/data/config.json" ] || echo -e "{\n \"config\": {\n \"complete\": false\n },\n \"labca\": {\n \"fqdn\": \"$LABCA_FQDN\"\n },\n \"version\": \"\"\n}" > "$adminDir/data/config.json"
replace_all $adminDir/data/openssl.cnf LABCA_FQDN
replace_all $adminDir/data/issuer/openssl.cnf LABCA_FQDN
cd "$cloneDir"
version=$(sudo -u labca -H git describe --always --tags HEAD 2>/dev/null)
cd "$adminDir"
grep \"version\" data/config.json &>/dev/null || sed -i -e 's/^}$/,\n "version": ""\n}/' data/config.json
sed -i -e "s/\"version\": \".*\"/\"version\": \"$version\"/" data/config.json
[ ! -e bin/labca-gui ] || mv bin/labca-gui bin/labca-gui_prev
chown -R labca:labca $baseDir
chown root:root "$cloneDir/cron_d"
[ -e /etc/cron.d/labca ] && rm /etc/cron.d/labca || true
[ -e /etc/logrotate.d/labca ] && rm /etc/logrotate.d/labca || true
git add --all &>/dev/null || true
git commit --all --quiet -m "LabCA after update $runId" &>>$installLog || true
msg_ok "$msg"
}
# Update any outdated packages
update_upgrade() {
msg_info "Making sure all software is up-to-date"
apt update &>>$installLog
apt upgrade -y &>>$installLog
apt autoremove -y &>>$installLog
msg_ok "Software is up-to-date"
}
#
# Install extra packages that we rely upon
#
install_pkg() {
local package="$1"
msg_info "Install package '$package'"
err=""
apt install -y "$package" &>>$installLog || err="err"
if [ "$err" == "err" ]; then
if [ "$package" == "python" ]; then
package="python3"
apt install -y "$package" &>>$installLog || msg_fatal "Could not install package '$package'"
else
msg_fatal "Could not install package '$package'"
fi
fi
msg_ok "Package '$package' is installed"
}
install_extra() {
local packages=(apt-transport-https ca-certificates curl gnupg2 net-tools software-properties-common tzdata ucspi-tcp zip python)
for package in "${packages[@]}"; do
install_pkg "$package"
done
distrib=$(lsb_release -is | tr '[:upper:]' '[:lower:]')
curl -fsSL https://download.docker.com/linux/${distrib}/gpg 2>>$installLog | apt-key add - &>>$installLog || msg_fatal "Could not download docker repository key"
add-apt-repository -r -y "deb [arch=amd64] https://download.docker.com/linux/${distrib} $(lsb_release -cs) stable" &>>$installLog
add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/${distrib} $(lsb_release -cs) stable" &>>$installLog
apt-cache policy docker-ce &>>$installLog
apt update &>>$installLog
install_pkg "docker-ce"
# Make sure the labca user has docker permissions
usermod -aG docker labca
msg_info "Install binary 'docker-compose'"
local dcver=""
[ -x /usr/local/bin/docker-compose ] && dcver="`/usr/local/bin/docker-compose --version`"
local vercmp=${dcver/$dockerComposeVersion/}
if [ "$dcver" == "" ] || [ "$dcver" == "$vercmp" ]; then
local v1test=${dcver/version 1./}
if [ "$dcver" != "$v1test" ] && [ "$dcver" != "" ]; then
mv /usr/local/bin/docker-compose /usr/local/bin/docker-compose-v1
fi
curl -sSL https://github.com/docker/compose/releases/download/$dockerComposeVersion/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose &>>$installLog || msg_fatal "Could not download docker-compose"
chmod +x /usr/local/bin/docker-compose
fi
msg_ok "Binary 'docker-compose' is installed"
}
# Configure the static web pages (for end users)
static_web() {
local rc=0
local msg="Static web pages"
msg_info "$msg"
if [ -d /etc/nginx ] && [ ! -d /etc/nginx.backup ]; then
# Migrate cert from host nginx to dockerized nginx
[ -d /home/labca/nginx_data/ssl ] || mkdir -p /home/labca/nginx_data/ssl
[ -d /etc/nginx/ssl/ ] && mv /etc/nginx/ssl/* /home/labca/nginx_data/ssl/ || true
mv /etc/nginx /etc/nginx.backup
fi
[ -d /home/labca/nginx_data/conf.d ] || mkdir -p /home/labca/nginx_data/conf.d
[ -d /home/labca/nginx_data/ssl ] || mkdir -p /home/labca/nginx_data/ssl
cp $cloneDir/nginx.conf /home/labca/nginx_data/conf.d/labca.conf
cp $cloneDir/proxy.conf /home/labca/nginx_data/conf.d/proxy.conf
if [ -f "$boulderLabCADir/setup_complete" ]; then
perl -i -p0e 's/\n # BEGIN temporary redirect\n location = \/ \{\n return 302 \/admin\/;\n }\n # END temporary redirect\n//igs' /home/labca/nginx_data/conf.d/labca.conf
fi
[ -d /home/labca/nginx_data/static ] || mkdir /home/labca/nginx_data/static
cd /home/labca/nginx_data/static
git config --global --add safe.directory /home/labca/nginx_data/static
git status --short &> /dev/null || rc=$?
if [ $rc -gt 0 ]; then
git init &>>$installLog
fi
git add --all &>/dev/null || true
git commit --all --quiet -m "LabCA before update $runId" &>>$installLog && { msg_ok "Commit existing modifications of $adminDir"; msg_info "$msg"; } || true
mkdir -p .well-known/acme-challenge
find .well-known/acme-challenge/ -type f -mtime +10 -exec rm {} \; # Clean up files older than 10 days
mkdir -p crl
[ -e cert ] || ln -s certs cert
cp -rp $cloneDir/gui/static/* .
[ -e $adminDir/data/root-ca.crl ] && cp $adminDir/data/root-ca.crl crl/ || true
[ -e $adminDir/data/root-ca.pem ] && cp $adminDir/data/root-ca.pem certs/ || true
[ -e $adminDir/data/root-ca.der ] && cp $adminDir/data/root-ca.der certs/ || true
[ -e $adminDir/data/issuer/ca-int.pem ] && cp $adminDir/data/issuer/ca-int.pem certs/ || true
[ -e $adminDir/data/issuer/ca-int.der ] && cp $adminDir/data/issuer/ca-int.der certs/ || true
local have_config=$(grep restarted $adminDir/data/config.json | grep true)
if [ "$have_config" != "" ]; then
$adminDir/apply-nginx
fi
git add --all &>/dev/null || true
git commit --all --quiet -m "LabCA after update $runId" &>>$installLog || true
msg_ok "$msg"
}
# Create a temporary self-signed certificate if there is no certificate yet
selfsigned_cert() {
if [ -e /home/labca/nginx_data/ssl/labca_cert.pem ]; then
msg_ok "Certificate is present"
else
local msg="Create self-signed certificate"
msg_info "$msg"
mkdir -p /home/labca/nginx_data/ssl
cd /home/labca/nginx_data/ssl
openssl req -x509 -nodes -sha256 -newkey rsa:2048 -keyout labca_key.pem -out labca_cert.pem -days 7 \
-subj "/O=LabCA/CN=$LABCA_FQDN" -reqexts SAN -extensions SAN \
-config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nbasicConstraints=CA:FALSE\nnsCertType=server\nsubjectAltName=DNS:$LABCA_FQDN")) &>>$installLog
msg_ok "$msg"
fi
}
# Clone or update the boulder code (Let's Encrypt (tm) implementation of ACME protocol)
get_boulder() {
export GOPATH="/home/labca/gopath"
sudo -u labca -H mkdir -p "$GOPATH/src/github.com/letsencrypt"
[ -h "$boulderDir" ] || sudo -u labca -H ln -s "$GOPATH/src/github.com/letsencrypt/boulder" "$boulderDir"
if [ -e "$boulderDir" ]; then
cd "$boulderDir"
sudo -u labca -H git checkout -- docker-compose.yml errors/errors.go policy/pa.go
sudo -u labca -H git reset --hard &>>$installLog
fi
clone_or_pull "$GOPATH/src/github.com/letsencrypt/boulder" "$boulderUrl"
cd "$boulderDir"
sudo -u labca -H git reset --hard $boulderTag &>>$installLog
if [ -e "sa/_db-next/migrations/20190221140139_AddAuthz2.sql" ]; then
sudo -u labca -H cp sa/_db-next/migrations/20190221140139_AddAuthz2.sql sa/_db/migrations/
fi
if [ -e "sa/_db-next/migrations/20190524120239_AddAuthz2ExpiresIndex.sql" ]; then
sudo -u labca -H cp sa/_db-next/migrations/20190524120239_AddAuthz2ExpiresIndex.sql sa/_db/migrations/
fi
msg_ok "Boulder checkout '$boulderTag'"
}
# Configure boulder based on their test subdirectory
config_boulder() {
local msg="Setup boulder configuration folder"
msg_info "$msg"
[ -d "$boulderLabCADir" ] || mkdir -p "$boulderLabCADir"
cd "$boulderLabCADir"
local rc=0
git config --global --add safe.directory "$boulderLabCADir"
git status --short &> /dev/null || rc=$?
if [ $rc -gt 0 ]; then
git init &>>$installLog
fi
[ -d ".backup" ] || mkdir -p ".backup"
git add --all &>/dev/null || true
[ "$installMode" == "normal" ] && git commit --all --quiet -m "LabCA before update $runId" &>>$installLog && { msg_ok "Commit existing modifications of $boulderLabCADir"; msg_info "$msg"; } || true
[ ! -e "$boulderLabCADir/secrets/smtp_password" ] || mv "$boulderLabCADir/secrets/smtp_password" "$boulderLabCADir/secrets/smtp_password_PRESERVE"
cp -r "$boulderDir/test" -T "$boulderLabCADir" &>>$installLog
[ ! -e "$boulderLabCADir/secrets/smtp_password_PRESERVE" ] || mv "$boulderLabCADir/secrets/smtp_password_PRESERVE" "$boulderLabCADir/secrets/smtp_password"
[ "$installMode" == "normal" ] && chown -R labca:labca "$boulderLabCADir" || /bin/true
rm -rf authz-filler challtestsrv gsb-test-srv
msg_ok "$msg"
msg="Configure the boulder application"
msg_info "$msg"
cd "$boulderDir"
if [ "$installMode" == "normal" ]; then
$cloneDir/patch.sh "sudo -u labca -H" &>>$installLog
sed -i -e "s/LABCA_FQDN: .*/LABCA_FQDN: $LABCA_FQDN/" docker-compose.yml
else
$cloneDir/patch.sh &>>$installLog
fi
git config --global --add safe.directory /home/labca/boulder_labca
cp docker-compose.yml "$boulderLabCADir/.backup/"
cp cmd/shell.go "$boulderLabCADir/.backup/"
cp core/interfaces.go "$boulderLabCADir/.backup/"
cp policy/pa.go "$boulderLabCADir/.backup/"
cp ra/ra.go "$boulderLabCADir/.backup/"
cp reloader/reloader.go "$boulderLabCADir/.backup/"
cp mail/mailer.go "$boulderLabCADir/.backup/"
cp cmd/expiration-mailer/main.go "$boulderLabCADir/.backup/"
cp cmd/notify-mailer/main.go "$boulderLabCADir/.backup/"
cp cmd/contact-auditor/main.go "$boulderLabCADir/.backup/"
cp cmd/bad-key-revoker/main.go "$boulderLabCADir/.backup/"
cp cmd/cert-checker/main.go "$boulderLabCADir/.backup/"
cp cmd/log-validator/main.go "$boulderLabCADir/.backup/"
cp cmd/boulder/main.go "$boulderLabCADir/.backup/"
cp ratelimit/rate-limits.go "$boulderLabCADir/.backup/"
cp errors/errors.go "$boulderLabCADir/.backup/"
cp log/log.go "$boulderLabCADir/.backup/"
cp sa/db/boulder_sa/20230419000000_CombinedSchema.sql "$boulderLabCADir/.backup/"
cp Makefile "$boulderLabCADir/.backup/"
if [ "$installMode" == "normal" ]; then
$cloneDir/patch-cfg.sh "sudo -u labca -H" "$boulderLabCADir" &>>$installLog
else
$cloneDir/patch-cfg.sh " " "$boulderLabCADir" &>>$installLog
fi
mkdir -p $baseDir/backup
if [ ! -z "$(docker ps | grep boulder-bmysql-1)" ]; then
docker exec boulder-bmysql-1 mysqldump --databases boulder_sa_integration >$baseDir/backup/dbdata-old-${runId}.sql
docker exec boulder-bmysql-1 mysql boulder_sa_integration -e 'delete from gorp_migrations;'
fi
if [ ! -z "$(docker ps | grep labca-bmysql-1)" ]; then
docker exec labca-bmysql-1 mysqldump --databases boulder_sa_integration >$baseDir/backup/dbdata-${runId}.sql
docker exec labca-bmysql-1 mysql boulder_sa_integration -e 'delete from gorp_migrations;'
fi
# housekeeping
for file in `ls -1t $baseDir/backup/dbdata-*.sql 2>&1 | tail -n +3 || true`; do
rm $file
done
if [ "$installMode" == "normal" ]; then
cd "$boulderLabCADir"
sed -i -e "s|https://boulder.service.consul:4431/terms/v7|https://$LABCA_FQDN/terms/v1|" config/wfe2.json
sed -i -e "s|boulder.service.consul:4000|$LABCA_FQDN|g" config/wfe2.json
sed -i -e "s|http://127.0.0.1:4002/|http://$LABCA_FQDN/ocsp/|g" config/ca-a.json
sed -i -e "s|http://127.0.0.1:4002/|http://$LABCA_FQDN/ocsp/|g" config/ca-b.json
sed -i -e "s|http://example.com/cps|http://$LABCA_FQDN/cps/|g" config/ca-a.json
sed -i -e "s|http://example.com/cps|http://$LABCA_FQDN/cps/|g" config/ca-b.json
sed -i -e "s|http://example.com/crl|http://$LABCA_FQDN/crl/|g" config/ca-a.json
sed -i -e "s|http://example.com/crl|http://$LABCA_FQDN/crl/|g" config/ca-b.json
sed -i -e "s|boulder.service.consul:4000|$LABCA_FQDN|g" config/va.json
sed -i -e "s|boulder.service.consul:4001|$LABCA_FQDN|g" config/va.json
sed -i -e "s|boulder.service.consul:4000|$LABCA_FQDN|g" config/va-remote-a.json
sed -i -e "s|boulder.service.consul:4001|$LABCA_FQDN|g" config/va-remote-a.json
sed -i -e "s|boulder.service.consul:4000|$LABCA_FQDN|g" config/va-remote-b.json
sed -i -e "s|boulder.service.consul:4001|$LABCA_FQDN|g" config/va-remote-b.json
cd "$boulderDir"
fi
([ -e mock-vendor.go ] && rm mock-vendor.go) || /bin/true
([ -e test-tools.go ] && rm test-tools.go) || /bin/true
if [ "$installMode" == "normal" ]; then
local have_config=$(grep restarted $adminDir/data/config.json 2>/dev/null | grep true)
if [ "$have_config" != "" ]; then
cd "$boulderLabCADir"
$adminDir/apply-boulder &>>$installLog
cd "$boulderDir"
else
chown -R labca:labca "$boulderLabCADir" || /bin/true
fi
fi
git add --all &>/dev/null || true
[ "$installMode" == "normal" ] && git commit --all --quiet -m "LabCA after update $runId" &>>$installLog || true
msg_ok "$msg"
}
# Cleanup any now obsolete files
cleanup() {
local msg="Cleaning up obsolete files"
msg_info "$msg"
if [ -d /var/www/html ]; then
rm -f /var/www/html/css/skeleton.css
rm -f /var/www/html/css/skeleton-tabs.css
rm -f /var/www/html/css/normalize.css
rm -f /var/www/html/css/font.css
rm -f /var/www/html/img/favicon.ico
rm -f /var/www/html/js/jquery-3.3.1.min.js
rm -f /var/www/html/js/skeleton-tabs.js
fi
rm -f $adminDir/templates/cert.tmpl
rm -f $adminDir/templates/error.tmpl
rm -f $adminDir/templates/final.tmpl
rm -f $adminDir/templates/footer.tmpl
rm -f $adminDir/templates/header.tmpl
rm -f $adminDir/templates/index.tmpl
rm -f $adminDir/templates/login.tmpl
rm -f $adminDir/templates/polling.tmpl
rm -f $adminDir/templates/register.tmpl
rm -f $adminDir/templates/setup.tmpl
rm -f $adminDir/templates/wrapup.tmpl
# Remove host nginx if installed, as we are now using the docker container
systemctl stop nginx &>>$installLog || true
systemctl disable nginx &>>$installLog || true
apt remove -y nginx &>>$installLog
msg_ok "$msg"
}
# Startup all the components
startup() {
local msg="Restart docker containers and service"
cd "$boulderDir"
let num=$(docker ps -a | grep " boulder-" | wc -l)
if [ $num -eq 0 ]; then
perl -i -p0e "s/(version:.*\n).*\n?(services:\n)/\1name: labca\n\2/" docker-compose.yml
fi
cnt=$(docker-compose ps | wc -l)
if [ "$cnt" -le "2" ]; then
msg="Download docker images and build containers"
fi
msg_info "$msg (this will take a while!!)"
docker-compose pull -q &>>$installLog
cnt=$(count $PS_CONTROL || echo "0")
docker-compose stop boulder bmysql labca nginx bconsul gui &>>$installLog || true
for ct in boulder_bhsm_1 boulder_bredis_1 boulder_bredis_2 boulder_bredis_3 boulder_bredis_4 boulder_bredis_5 boulder_bredis_6; do
[ -z "$(docker ps | grep $ct)" ] || docker stop $ct &>>$installLog
done
if [ $num -ne 0 ]; then
docker-compose stop control &>>$installLog || true
fi
wait_down $PS_NGINX &>>$installLog || true
wait_down $PS_MYSQL &>>$installLog || true
wait_down $PS_CONSUL &>>$installLog || true
wait_down $PS_LABCA &>>$installLog || true
wait_down $PS_BOULDER &>>$installLog || true
if [ $num -ne 0 ]; then
wait_down $PS_CONTROL &>>$installLog || true
cnt=0
fi
for ct in boulder_bhsm_1 boulder_bredis_1 boulder_bredis_2 boulder_bredis_3 boulder_bredis_4 boulder_bredis_5 boulder_bredis_6; do
[ -z "$(docker ps -a | grep -e "$ct\$")" ] || docker rm -f $ct &>>$installLog
done
local rc=0
service labca status &> /dev/null || rc=$?
if [ $rc -eq 0 ]; then
service labca stop &>>$installLog || true
update-rc.d labca disable &>>$installLog || true
[ -e "/etc/init.d/labca" ] && rm /etc/init.d/labca || true
fi
[ -d /home/labca/control_logs ] || mkdir -p /home/labca/control_logs
perl -i -p0e "s/(version:.*\n).*\n?(services:\n)/\1name: labca\n\2/" docker-compose.yml
docker network rm -f boulder_bluenet boulder_consulnet boulder_rednet &>>$installLog || /bin/true
docker rm -f boulder-control-1 boulder-boulder-1 boulder-labca-1 boulder-bmysql-1 boulder-bconsul-1 boulder-nginx-1 >/dev/null &>>$installLog
# Restore MySQL data when moving from boulder-bmysql-1 to labca-bmysql-1
if [ -z "$(docker volume ls | grep labca_dbdata)" ] && [ ! -z "$(docker volume ls | grep boulder_dbdata)" ]; then
docker volume create labca_dbdata &>>$installLog
dimg=$(grep mariadb: docker-compose.yml | sed -e "s/\s*image:\s*//")
docker run --rm -v boulder_dbdata:/old -v labca_dbdata:/new $dimg bash -c "cp -R /old/* /new/" &>>$installLog
fi
COMPOSE_HTTP_TIMEOUT=180 docker-compose up -d &>>$installLog
wait_up $PS_NGINX &>>$installLog || true
wait_up $PS_MYSQL &>>$installLog || true
wait_up $PS_CONSUL 2 &>>$installLog || true
wait_up $PS_LABCA &>>$installLog || true
wait_up $PS_CONTROL &>>$installLog || true
docker exec -i labca-bmysql-1 mysql_upgrade &>>$installLog
[ -f "$boulderLabCADir/setup_complete" ] && wait_up $PS_BOULDER $PS_BOULDER_COUNT &>>$installLog || /bin/true
if [ $cnt -gt 0 ]; then
COMPOSE_HTTP_TIMEOUT=180 docker-compose restart control &>>$installLog
fi
msg_ok "$msg"
}
# If the nginx certificate is self-signed then show extra text
first_time() {
local certFile="/home/labca/nginx_data/ssl/labca_cert.pem"
[ -e "$certFile" ] || msg_fatal "The SSL certificate $certFile does not exist"
local subject=$(openssl x509 -noout -in "$certFile" -subject_hash)
local issuer=$(openssl x509 -noout -in "$certFile" -issuer_hash)
if [ "$subject" == "$issuer" ]; then
echo
echo ========
echo
echo "Congratulations! LabCA is now installed and should be available at https://$LABCA_FQDN"
echo "Please go there now to finish the setup. Note that a TEMPORARY (7 days) self-signed certificate"
echo "is used; as part of the setup verification a new certificate will be issued."
echo
fi
}
check_dockeronly() {
set +e
wd=$(which docker)
set -e
if [ "$wd" != "" ]; then
let num=$(docker volume ls | grep labca_ | grep -v labca_dbdata | wc -l)
if [ $num -gt 0 ]; then
scriptname=$(basename $0)
echo "You can not run the $scriptname script when using dockeronly mode!"
exit 1
fi
fi
}
#
# The actual main function to tie it all together
#
main() {
local curdir="$PWD"
echo
check_dockeronly
start_temporary_log
check_root
install_pkg "git"
install_pkg "sudo"
install_pkg "patch"
labca_user
end_temporary_log
this=$0
[ -e $this ] || this="$curdir/$0"
curChecksum=$(md5sum $this 2>/dev/null | cut -d' ' -f1)
[ ! -e "$cloneDir/cron_d" ] || chown labca:labca "$cloneDir/cron_d"
parse_cmdline "$@"
if [ $keepLocal -eq 0 ]; then
clone_or_pull "$cloneDir" "$labcaUrl" "$cmdlineBranch"
checkout_release "$cmdlineBranch"
restart_if_updated
fi
if [ $alphaTest -eq 1 ]; then
install_extra
cd $(dirname $this)
local msg="TEST: build labca-gui binary"
msg_info "$msg"
# this will ultimately NOT be done on the target machine!
build/build.sh &>>$installLog || msg_fatal "Could not build docker images!"
msg_ok "$msg"
msg="TEST build local docker image"
msg_info "$msg"
build/tag_and_upload.sh &>>$installLog || msg_fatal "Could not tag (and upload) docker images!"
msg_ok "$msg"
msg_ok "That's it for now!"
exit 0
fi
get_fqdn
copy_admin
update_upgrade
install_extra
static_web
selfsigned_cert
get_boulder
config_boulder
#if [ $alphaTest -eq 1 ]; then
# msg="TEST modify docker-compose.yml"
# msg_info "$msg"
# cd "$boulderDir"
# patch -p1 < $(dirname $this)/build/tmp.patch &>>$installLog
# patch -p1 -o "$boulderLabCADir/startservers.py" < $(dirname $this)/build/tmp2.patch
# msg_ok "$msg"
#fi
cleanup
startup
echo -e "$DONE"
echo
first_time
cd "$curdir"
}
[ "$installMode" == "normal" ] && main "$@" || /bin/true