#! /bin/bash ### ### Update the site's SSH certificates. set -e cd "${0%/*}/.." ###-------------------------------------------------------------------------- ### General setup stuff. ## Read in a configuration file. if [ -f etc/config ]; then . etc/config; fi : ${keytypes="rsa:3072 dsa:1024"} : ${domain="your.site.example"} : ${cacomment="ssh-ca@$domain"} : ${scope="*.$domain"} : ${validity="-1d:+7d"} ## The key types are adorned with bit lengths. Work out the raw key type ## names. cakeytypes="" for kt in $keytypes; do cakeytypes="$cakeytypes ${kt%:*}" done ## Make the keys if necessary. mkdir -p keys for kt in $keytypes; do case $kt in *:*) bits=-b${kt#*:} kt=${kt%:*} ;; *) bits="" ;; esac if [ ! -f keys/ca-$kt ]; then ssh-keygen -fkeys/ca-$kt -t$kt $bits -C"$cacomment" -N "" fi read pub keys/ca-$kt.entry done ## Functions for managing concurrency. kids="" mkdir -p log run () { tag=$1; shift "$@" >log/$tag 2>&1& kids="$kids $tag:$!" } reap () { outcome=0 for kid in $kids; do tag=${kid%:*} set +e; wait ${kid#*:}; rc=$?; set -e case $rc in 0) ;; *) echo >&2 "$0: $tag failed (rc = $rc)" sed 's,^,| ,' log/$tag outcome=1 ;; esac done return $outcome } ## Read the hosts. dohost () { host=$1; shift set -x hostkeytypes=$( ssh $host " cd /etc/ssh for kt in $cakeytypes; do if [ -f ssh_host_\${kt}_key.pub ]; then echo \$kt; fi done" ) names="" for n in "$host" "$@"; do names=${names:+$names,}$n case "$n" in ".") ;; *) names=${names:+$names,}$n.$domain ;; esac done any=nil for kt in $hostkeytypes; do scp $host:/etc/ssh/ssh_host_${kt}_key.pub keys/$host-$kt.pub ssh-keygen -skeys/ca-$kt \ -h -I"$cacomment:$host.$domain" -n$names \ -V$validity \ keys/$host-$kt.pub scp keys/$host-$kt-cert.pub $host:/etc/ssh/ssh_host_${kt}_key-cert.pub any=t done case "$any" in nil) echo >&2 "no matching key types"; exit 1 ;; esac } dotry () { host=$1; shift ping -c5 -q $host >/dev/null 2>&1 || return 0 dohost "$host" "$@" } must () { run "$1" dohost "$@"; } try () { run "$1" dotry "$@"; } . etc/hosts reap last=%%% for i in keys/*.pub; do case "$i" in *-cert.pub) continue ;; esac host=${i%-*} case "$host" in "$last") ;; *) echo; echo "$host" ;; esac last=$host ssh-keygen -lv -f "$i" | sed 's,^,| ,' done >distorted-host-keys.new mv distorted-host-keys.new distorted-host-keys