deploy-secrets.sh 4.39 KB
Newer Older
Matthew Clemente's avatar
Matthew Clemente committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
#!/bin/bash

## This script needs SSH access to one of the host nodes that already has Docker Swarm set up

## Set some colors for fun. Thanks to https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

## Confirm DOCKER_HOST
if [ -z ${DOCKER_HOST+x} ]; then 
  read -p "
We need an SSH user with access to one of the Swarm managers in order to create the secrets.

Please enter your Swarm Host SSH credentials in the format [email protected]: " SWARM_SSH_CREDENTIALS;
  ## Switch context to the remote server
  export DOCKER_HOST=ssh://$SWARM_SSH_CREDENTIALS
  
  printf "\n${GREEN}%s${NC}\n" "Thank you."

else
  ## Switch context to the remote server
  export DOCKER_HOST=$DOCKER_HOST
fi

## Provide prompt to make sure that user knows what they're doing
while true; do
    read -p "
This script will loop through the local /.secrets directory of this project and create secrets in your remote Swarm based on the name and contents of the files that it finds.

This will be done using the credentials: $DOCKER_HOST

Do you wish to continue? " yn
    case $yn in
        [Yy]* ) printf "\n${GREEN}%s${NC}\n" "Proceeding with secret creation."; break;;
        [Nn]* ) printf "\n${RED}%s${NC}\n" "Secret creation cancelled."; exit;;
        * ) printf "\n%s\n" "Please answer yes or no.";;
    esac
done

printf "\n%s\n" "Confirming SSH access via $DOCKER_HOST"

IS_SWARM_MANAGER=false
SSH_CONNECTION_FAILED=0
{
  IS_SWARM_MANAGER=$( docker info --format "{{.Swarm.ControlAvailable}}" )
} || {
  IS_SWARM_MANAGER=false
  SSH_CONNECTION_FAILED=1
}

if [ "$SSH_CONNECTION_FAILED" -eq 1 ]; then
  printf "\n${RED}%s${NC}\n" "SSH connection failed. Sometimes this happens due to rate-limiting. Please confirm that the Swarm host is accessible. Secret creation cancelled."
  exit
fi

if [ "$IS_SWARM_MANAGER" != true ]; then
  printf "\n${RED}%s${NC}\n" "Either a Swarm has not been init on the host or it is not a manager. Secret creation cancelled.";
  exit
fi

printf "\n${GREEN}%s${NC}\n" "SSH access to Swarm manager confirmed."

## Let's get the directory the script is in. Thanks to https://stackoverflow.com/questions/59895/get-the-source-directory-of-a-bash-script-from-within-the-script-itself
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

## Dependent on the structure of this repository to work. We're switching from build -> .secrets directory
DIR=$( sed 's+/build+/.secrets+g' <(echo $DIR) )

## We're going to cd into the .secrets directory for our loop
cd $DIR

## Get a list of the current secrets from the Swarm
SECRETS=$(docker secret ls --quiet --format "{{.Name}}")

## Convert the list to an array
SECRETS=($SECRETS)

printf "\n%s\n" "Found ${#SECRETS[@]} existing secret(s)."

## Sleeps here are to attempt to slow down consecutive calls via SSH, in case the firewall has rate limits

sleep 2

printf "\n%s\n" "Preparing to create secrets."

sleep 2

## Thank you https://stackoverflow.com/questions/3685970/check-if-a-bash-array-contains-a-value
elementIn () {
  local e match="$1"
  shift
  for e; do [[ "$e" == "$match" ]] && return 0; done
  return 1
}

## Loop over the secrets. Don't use those suffixed with .dev
find . -maxdepth 1 -type f ! -name "*.dev" ! -name "*.sh" ! -name "*.DS_Store" | while read f; do

    if elementIn "${f#./}" "${SECRETS[@]}" ; then
      printf "\n${RED}%s${NC}\n" "Skipping ${f#./} - it already exists in the Swarm";
    else
      printf "\n${GREEN}%s${NC}\n" "Creating secret: ${f#./}"
      sleep 5

      SLEEP_TIME=30s
      SECRET_SUCCESS=1
      n=0
      until [ $n -ge 5 ]
      do
        echo "Attempting to create secret"
        ## Run SSH command to create the secret
        docker secret create ${f#./} $f && break
        n=$[$n+1]
        ## If it failed, try to sleep, before retrying. Sometimes needed if UFW firewall is enabled and rate limiting
        if [ $n -lt 5 ]; then
          printf "\n${RED}%s${NC}\n" "Attempt $n failed. Sleeping $SLEEP_TIME before retry";
        else
          printf "\n${RED}%s${NC}\n" "Attempt $n failed. Could not create secret: ${f#./}";
          echo "Sleeping $SLEEP_TIME before continuing."
          SECRET_SUCCESS=0
        fi
        sleep $SLEEP_TIME
      done
      if [ $SECRET_SUCCESS -eq 1 ]; then
        printf "\n${GREEN}%s${NC}\n" "Successfully created secret: ${f#./}"
      fi;

    fi;

done

printf "\n${GREEN}%s${NC}\n" "Secret creation script completed."