Minimal SSH certificate authority.
[ssh-ca] / bin / update-ssh-certs
CommitLineData
eb8701bb
MW
1#! /bin/bash
2###
3### Update the site's SSH certificates.
4
5set -e
6cd "${0%/*}/.."
7
8###--------------------------------------------------------------------------
9### General setup stuff.
10
11## Read in a configuration file.
12if [ -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.
21cakeytypes=""
22for kt in $keytypes; do
23 cakeytypes="$cakeytypes ${kt%:*}"
24done
25
26## Make the keys if necessary.
27mkdir -p keys
28for 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
38done
39
40## Functions for managing concurrency.
41kids=""
42mkdir -p log
43run () {
44 tag=$1; shift
45 "$@" >log/$tag 2>&1&
46 kids="$kids $tag:$!"
47}
48
49reap () {
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.
67dohost () {
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
96dotry () {
97 host=$1; shift
98 ping -c5 -q $host >/dev/null 2>&1 || return 0
99 dohost "$host" "$@"
100}
101
102must () { run "$1" dohost "$@"; }
103try () { run "$1" dotry "$@"; }
104
105. etc/hosts
106reap
107
108last=%%%
109for 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,^,| ,'
115done >distorted-host-keys.new
116mv distorted-host-keys.new distorted-host-keys