selfprivacy_fork/static/server.sh

297 lines
11 KiB
Bash
Executable File

#!/bin/bash
# Collecting authentification data
InstallDependencies()
{
packagesNeeded='curl jq expect pwgen'
if [ -x "$(command -v apk)" ]; then sudo apk add --no-cache $packagesNeeded # Alpine Linux
elif [ -x "$(command -v apt-get)" ]; then sudo apt-get install $packagesNeeded # Debian/Ubuntu Linux
elif [ -x "$(command -v dnf)" ]; then sudo dnf install $packagesNeeded # Fedora Linux
elif [ -x "$(command -v rpm-ostree)" ]; then sudo rpm-ostree install $packagesNeeded # Fedora Linux Silverblue
elif [ -x "$(command -v zypper)" ]; then sudo zypper install $packagesNeeded # openSUSE Linux
elif [ -x "$(command -v pacman)" ]; then sudo pacman -S $packagesNeeded # Arch/Manjaro Linux
elif [ -x "$(command -v emerge)" ]; then sudo emerge --ask $packagesNeeded # Gentoo Linux
elif [ -x "$(command -v nix-env)" ]; then nix-env -iA $packagesNeeded # NixOS
else echo "FAILED TO INSTALL PACKAGE: Package manager not found. You must manually install: $packagesNeeded">&2; fi
wget https://selfprivacy.org/configuration.nix
wget https://selfprivacy.org/mailserver.nix
wget https://selfprivacy.org/goss.nix
wget https://selfprivacy.org/restic.nix
wget https://selfprivacy.org/restic.yaml
wget https://selfprivacy.org/s3cli
}
CollectData()
{
read -p "Please, paste your Hetzner API token here: " HETZNER_TOKEN
read -p "Please, paste your CloudFlare Token: " CLOUDFLARE_TOKEN
read -p "Please, paste your AWS Secret Access Key: " AWS_TOKEN
read -p "Please, paste your AWS Access Key ID: " AWS_TOKEN_ID
read -p "Please, define your domain there: " DOMAIN
read -p "Please, define your mail username: " USERNAME
read -p "Please, define your password: " PASSWORD && PASSWORD=$( mkpasswd -m sha-512 "$PASSWORD" )
}
# Generate SSH key
GenerateSSHKey()
{
echo "Generating SSH keys..."
mkdir ~/.nix-ms
ssh-keygen -f ~/.nix-ms/id_rsa > /dev/null
export sshKey=$( cat ~/.nix-ms/id_rsa.pub )
}
# Add SSH key to Hetzner
AddSSHKey()
{
echo "Adding SSH keys to Hetzner..."
curl -s \
-X POST \
-H "Authorization: Bearer $HETZNER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"nixosms","public_key":"'"${sshKey}"'","labels":{}}' \
'https://api.hetzner.cloud/v1/ssh_keys' > /dev/null
}
# Create NixOS config file
MakeConfig()
{
# Mailserver
sed -i '15s/.*/ fqdn = "'$DOMAIN'";/' mailserver.nix
sed -i '16s/.*/ domains = [ "'"$DOMAIN"'" ];/' mailserver.nix
sed -i '21s/.*/\t"'$USERNAME'@'$DOMAIN'" = {/' mailserver.nix
sed -i '22s/.*/\t hashedPassword = "'"$PASSWORD"'";/' mailserver.nix
sed -i '31s/.*/\t\t"'"$DOMAIN"'"/' mailserver.nix
sed -i '41s/.*/\t "admin@'"$DOMAIN"'" = "'"$USERNAME"'@'"$DOMAIN"'";/' mailserver.nix
sed -i '63s/.*/ email = "'"$USERNAME"'@'"$DOMAIN"'";/' mailserver.nix
# System Configuration
sed -i "15s,.*,\t\"${sshKey}\"," configuration.nix
sed -i "16s,.*,\t restic -r s3:s3.amazonaws.com/${AWS_BUCKET_NAME} backup /var/vmail /var/vmail ," restic.nix
}
MakeServer()
{
echo "Creating Server..."
curl -s \
-X POST \
-H "Authorization: Bearer $HETZNER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"nixos-mailserver","server_type":"cx11","start_after_create":true,"image":"ubuntu-20.04","ssh_keys":["nixosms"],"volumes":[],"networks":[],"user_data":"#cloud-config\nruncmd:\n- curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-20.03 bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":false}' \
'https://api.hetzner.cloud/v1/servers' > /dev/null
}
CreateS3BucketRaw()
{
local date="$(date -u '+%a, %e %b %Y %H:%M:%S +0000')"
local string_to_sign
local MD5=""
printf -v string_to_sign "%s\n%s\n\n%s\n%s" "PUT" "$MD5" "$date" "$path"
signature=$(echo -n "$string_to_sign" | openssl sha1 -binary -hmac "${AWS_SECRET_ACCESS_KEY}" | openssl base64)
curl -s \
-X PUT \
-H "Host: $AWS_TOKEN_ID.s3-control.us-east-2.amazonaws.com" \
-H "Content-Length: 0" \
-H "Date: $(date +'%a, %d %b %Y %H:%M:%S %Z')" \
-H "Authorization: AWS $AWS_TOKEN_ID:$signature"
}
CreateS3Bucket()
{
mkdir ~/.aws
touch ~/.aws/credentials
echo "[default]" >> ~/.aws/credentials
echo "aws_access_key_id=$AWS_TOKEN_ID" >> ~/.aws/credentials
echo "aws_secret_access_key=$AWS_TOKEN" >> ~/.aws/credentials
if [[ -z "$(./s3cli -e http://s3.us-east-2.amazonaws.com --ak "$AWS_TOKEN_ID" --sk "$AWS_TOKEN" --region us-east-2 bucket ls | grep backup)" ]]; then
read "AWS S3 bucket found in your account. Do you want to restore backup from there? (y/n) " RESTORE_MAILBACKUP
else
export AWS_BUCKET_NAME=$(pwgen -1 --no-capitalize 6)-backup
./s3cli -e http://s3.us-east-2.amazonaws.com --ak "$AWS_TOKEN_ID" --sk "$AWS_TOKEN" --region us-east-2 bucket create $AWS_BUCKET_NAME
fi
}
# Get machine IP
GetMachineIP()
{
curl -s \
-H "Authorization: Bearer $HETZNER_TOKEN" \
'https://api.hetzner.cloud/v1/servers' > .machine.json
export machineip=$( for i in {0..24}; do jq 'if .servers['$i'].name == "nixos-mailserver" then .servers['$i'].public_net.ipv4.ip else null end' .machine.json; done | grep -v null | sed 's/"//' | sed 's/"//' )
}
# Copy and apply mailserver config
ApplyConfig()
{
ssh -i ~/.nix-ms/id_rsa "root@$machineip" echo "Authentificated"
scp -i ~/.nix-ms/id_rsa mailserver.nix "root@$machineip:/root"
scp -i ~/.nix-ms/id_rsa configuration.nix "root@$machineip:/root"
scp -i ~/.nix-ms/id_rsa goss.nix "root@$machineip:/root"
scp -i ~/.nix-ms/id_rsa goss.yaml "root@$machineip:/root"
ssh -i ~/.nix-ms/id_rsa "root@$machineip" cp /root/mailserver.nix /etc/nixos/mailserver.nix
ssh -i ~/.nix-ms/id_rsa "root@$machineip" cp /root/configuration.nix /etc/nixos/configuration.nix
ssh -i ~/.nix-ms/id_rsa "root@$machineip" cp /root/goss.nix /etc/nixos/goss.nix
sleep 3
ssh -i ~/.nix-ms/id_rsa "root@$machineip" nixos-rebuild switch
ssh -i ~/.nix-ms/id_rsa "root@$machineip" export AWS_ACCESS_KEY_ID=$AWS_TOKEN_ID
ssh -i ~/.nix-ms/id_rsa "root@$machineip" export AWS_SECRET_ACCESS_KEY=$AWS_TOKEN
}
RestoreBackup()
{
ssh -i ~/.nix-ms/id_rsa "root@$machineip" restic -r s3:s3.amazonaws/$AWS_BUCKET_NAME restore latest --target /var/vmail /var/dkim
}
# Get DKIM keys from remote machine
GetDKIM()
{
scp -i ~/.nix-ms/id_rsa "root@$machineip:/var/dkim/$DOMAIN.selector.txt" .
sed -i '1d' $DOMAIN.selector.txt
sed -i 's/ ) ; ----- DKIM key selector for '$DOMAIN'//g' $DOMAIN.selector.txt
export dkim=$( cat $DOMAIN.selector.txt )
}
ClearTempFiles()
{
rm .machine.json
rm .cloudflare.json
rm $DOMAIN.selector.txt
rm -rf ~/.nix-ms/
rm ~/.ssh/known_hosts
rm .healthz.json
rm .hetzner_machines.json
}
# Cloudflare configuration
# Get zone ID
GetZoneID()
{
curl -s -X GET "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
-H "Content-Type: application/json" > .cloudflare.json
export zoneid=$( for i in {0..24}; do jq 'if .result['$i'].name == "'$DOMAIN'" then .result['$i'].id else null end' .cloudflare.json; done | grep -v null | sed -e 's/^"//' -e 's/"$//' )
}
# Create records
CreateARecord()
{
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" \
-H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
-H "Content-Type: application/json" \
--data '{"type":"A","name":"'$DOMAIN'","content":"'$machineip'","ttl":3600,"priority":10,"proxied":false}' > /dev/null
}
CreateMXRecord()
{
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" \
-H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
-H "Content-Type: application/json" \
--data '{"type":"MX","name":"@","content":"'$DOMAIN'","ttl":3600,"priority":10,"proxied":false}' > /dev/null
}
CreateDMARCRecord()
{
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" \
-H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
-H "Content-Type: application/json" \
--data '{"type":"TXT","name":"_dmarc","content":"v=DMARC1; p=none","ttl":18000,"priority":10,"proxied":false}' > /dev/null
}
CreateSPFRecord()
{
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" \
-H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
-H "Content-Type: application/json" \
--data '{"type":"TXT","name":"'$DOMAIN'","content":"v=spf1 a mx ip4:'$machineip' -all","ttl":18000,"priority":10,"proxied":false}' > /dev/null
}
CreateDKIMRecord()
{
export dkim=$( echo $dkim | sed -e 's/^"//' -e 's/"$//' )
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" -H "Authorization: Bearer $CLOUDFLARE_TOKEN" -H "Content-Type: application/json" --data '{"type":"TXT","name":"selector._domainkey","content":"v=DKIM1; '$dkim'","ttl":18000,"priority":10,"proxied":false}' > /dev/null
}
PostInstallation()
{
ssh -i ~/.nix-ms/id_rsa "root@$machineip" restic -r s3:s3.amazonaws.com/$AWS_BUCKET_NAME init
ssh -i ~/.nix-ms/id_rsa "root@$machineip" restic -r s3:s3.amazonaws.com/$AWS_BUCKET_NAME forget --prune --keep-hourly 2 --keep-daily 7 --keep-weekly 4
ssh -i ~/.nix-ms/id_rsa "root@$machineip" cp /root/result/bin/goss /root/
ssh -i ~/.nix-ms/id_rsa "root@$machineip" /root/goss serve --format json &
}
PerformTests()
{
curl $machineip:8080/healthz > .healthz.json
for i in {0..24}; do jq 'if .results['$i'].err != null then "FAIL" else "OK" end' .healthz.json;
done
}
RunPreFlightChecks()
{
curl -H "Authorization: Bearer $HETZNER_TOKEN" 'https://api.hetzner.cloud/v1/servers' > .hetzner_test.json
jq 'if .error != null then "Preflight checks failed" else "Success" end' .hetzner_test.json | if [ "Preflight checks failed" ]
then
echo "Hetzner Authorization failed"
exit -1
fi
}
if test -z "$HETZNER_TOKEN" || test -z "$CLOUDFLARE_TOKEN" || test -z "$PASSWORD"
then
CollectData
if [ ${#HETZNER_TOKEN} != 64 ]
then
echo "Hetzner Token is incorrect. Please double check your input"
exit -1
elif [ ${#CLOUDFLARE_TOKEN} != 40 ]
then
echo "Cloudflare Token is incorrect. Please double check your input"
exit -1
elif [[ ${DOMAIN} != *.* ]]
then
echo "Got unexpected domain. Possibly wrong input"
exit -1
fi
fi
#RunPreFlightChecks
InstallDependencies
GenerateSSHKey
printf "Importing SSH key into your Hetzner account..."
AddSSHKey
printf "done\n"
printf "Generating config file..."
MakeConfig
printf "done\n"
printf "Waiting for the server to create...\n"
MakeServer
sleep 30
printf "Waiting for nixos-infect to replace system files(this may take some time)...\n"
sleep 240
CreateS3Bucket
GetMachineIP
ApplyConfig
if [$RESTORE_MAILBACKUP == "y"]; then
RestoreBackup
fi
GetDKIM
echo "Beginning CloudFlare configuration"
GetZoneID
printf "Creating records..."
CreateARecord
CreateMXRecord
CreateDMARCRecord
CreateSPFRecord
CreateDKIMRecord
printf "done\n"
PostInstallation
#PerformTests
#while ! ping -c1 192.168.0.107 &>/dev/null
# do echo "Ping Fail - `date`"
#done
#echo "Host Found - `date`"
printf "Clearing temporary files..."
ClearTempFiles
printf "done\n"