I have a fleet of linux computers ("nodes" from here on out) who are what I'll call ephemeral members of a network. The nodes are vehicle mounted and frequently move into and out of wifi coverage.
Of course, it's often beneficial for me to push the update of a single script, program or file to all nodes. What I came up with is this:
- Generate a key pair to be shared by all nodes
- Encrypt the new file version, with a header that contains installation path, on my workstation. My workstation of course has the public key.
- Place the encrypted update in a node-accessible network "staging" folder
- When a node finds itself with a good connection, it checks the staging folder.
- If there are new files, they're:
- copied to the node
- decrypted
- checked for integrity("Does the file header look good?")
- moved to the location prescribed by the header
Here's a simple version of my code. Is this a bad idea? Is there a more elegant way to deal with updating unattended nodes on a super flaky connection?
#!/bin/bash
#A method for autonomously retrieving distributed updates
#The latest and greatest files are here:
stageDir="/remoteDirectory/stage"
#Files are initially moved to a quarantine area
qDir="/localDirectory/quarantine"
#If all went well, put a copy of the encrypted file here:
aDir="/localDirectory/pulled"
#generic extension for encrypted files "Secure Up Date"
ext="sud"
for file in "$stageDir"/*."$ext"; do #For each "sud" file...
fname=$(basename $file)
if [ ! -f $aDir/$fname ]; then #If this file has not already been worked on...
cp "$file" "$qDir"/"$fname" #Move it to the quarantine directory
else
echo "$fname has already been pulled" #Move along
fi
done
if [ "$(ls $qDir)" ]; then #If there's something to do (i.e. files in the directory)
for file in "$qDir"/*."$ext"; do
fname=$(basename $file)
qPath="$qDir/$fname"
untrusted="$qPath.untrusted"
#Decrypt file
gpg --output "$untrusted" --yes --passphrase "supersecretpassphrase" --decrypt "$qPath" #Say yes to overwriting
headline=$(head -n 1 $untrusted) #Get the header (which is the first line of the file)
#Check to see if this is a valid file
if [[ $headline == "#LOOKSGOOD:"* ]]; then #All headers must start with "#LOOKSGOOD:" or something
#Get install path
installPath=$(echo $headline | cut -d ':' -f 2) #Get the stuff after the colon
tail -n +2 $untrusted > $installPath #Send everything but the header line to the install path
#Clean up our working files
rm $untrusted
mv $qPath "$aDir/$fname"
#Report what we did
echo $headline
else
#trash the file if it's not a legit file
echo "$fname is not a legit update...trashing it"
rm "$qDir/$fname"*
fi
done
fi