chiark / gitweb /
Minimal SSH certificate authority.
[ssh-ca] / bin / update-ssh-certs
1 #! /bin/bash
2 ###
3 ### Update the site's SSH certificates.
4
5 set -e
6 cd "${0%/*}/.."
7
8 ###--------------------------------------------------------------------------
9 ### General setup stuff.
10
11 ## Read in a configuration file.
12 if [ -f etc/config ]; then . etc/config; fi
13 : ${keytypes="rsa:3072 dsa:1024"}
14 : ${domain="your.site.example"}
15 : ${cacomment="ssh-ca@$domain"}
16 : ${scope="*.$domain"}
17 : ${validity="-1d:+7d"}
18
19 ## The key types are adorned with bit lengths.  Work out the raw key type
20 ## names.
21 cakeytypes=""
22 for kt in $keytypes; do
23   cakeytypes="$cakeytypes ${kt%:*}"
24 done
25
26 ## Make the keys if necessary.
27 mkdir -p keys
28 for kt in $keytypes; do
29   case $kt in
30     *:*) bits=-b${kt#*:} kt=${kt%:*} ;;
31     *) bits="" ;;
32   esac
33   if [ ! -f keys/ca-$kt ]; then
34     ssh-keygen -fkeys/ca-$kt -t$kt $bits -C"$cacomment" -N ""
35   fi
36   read pub <keys/ca-$kt.pub
37   echo "@cert-authority $scope $pub" >keys/ca-$kt.entry
38 done
39
40 ## Functions for managing concurrency.
41 kids=""
42 mkdir -p log
43 run () {
44   tag=$1; shift
45   "$@" >log/$tag 2>&1&
46   kids="$kids $tag:$!"
47 }
48
49 reap () {
50   outcome=0
51   for kid in $kids; do
52     tag=${kid%:*}
53     set +e; wait ${kid#*:}; rc=$?; set -e
54     case $rc in
55       0) ;;
56       *)
57         echo >&2 "$0: $tag failed (rc = $rc)"
58         sed 's,^,| ,' log/$tag
59         outcome=1
60         ;;
61     esac
62   done
63   return $outcome
64 }
65
66 ## Read the hosts.
67 dohost () {
68   host=$1; shift
69
70   set -x
71   hostkeytypes=$(
72     ssh $host "
73         cd /etc/ssh
74         for kt in $cakeytypes; do
75           if [ -f ssh_host_\${kt}_key.pub ]; then echo \$kt; fi
76         done"
77   )
78   names=""
79   for n in "$host" "$@"; do
80     names=${names:+$names,}$n
81     case "$n" in ".") ;; *) names=${names:+$names,}$n.$domain ;; esac
82   done
83   any=nil
84   for kt in $hostkeytypes; do
85     scp $host:/etc/ssh/ssh_host_${kt}_key.pub keys/$host-$kt.pub
86     ssh-keygen -skeys/ca-$kt \
87       -h -I"$cacomment:$host.$domain" -n$names \
88       -V$validity \
89       keys/$host-$kt.pub
90     scp keys/$host-$kt-cert.pub $host:/etc/ssh/ssh_host_${kt}_key-cert.pub
91     any=t
92   done
93   case "$any" in nil) echo >&2 "no matching key types"; exit 1 ;; esac
94 }
95
96 dotry () {
97   host=$1; shift
98   ping -c5 -q $host >/dev/null 2>&1 || return 0
99   dohost "$host" "$@"
100 }
101
102 must () { run "$1" dohost "$@"; }
103 try () { run "$1" dotry "$@"; }
104
105 . etc/hosts
106 reap
107
108 last=%%%
109 for i in keys/*.pub; do
110   case "$i" in *-cert.pub) continue ;; esac
111   host=${i%-*}
112   case "$host" in "$last") ;; *) echo; echo "$host" ;; esac
113   last=$host
114   ssh-keygen -lv -f "$i" | sed 's,^,| ,'
115 done >distorted-host-keys.new
116 mv distorted-host-keys.new distorted-host-keys