1#!/bin/bash
2shopt -s nullglob
3
4# We want to iterate over all system users, check if they are opted-in to ssh
5# authorized_keys building, and then construct their keyfile
6while read -r user; do
7  home="$(eval echo "~$user")" || continue
8  link="$(readlink "$home"/.ssh/authorized_keys 2>/dev/null)" || continue
9  # Users are only opted-in if they symlink to our well-known directory where
10  # the final output of this script lives.
11  if [[ $link != "/run/authorized_keys/$user" ]]; then
12    echo "Ignoring $user $home/.ssh/authorized_keys" >&2
13    continue
14  fi
15
16  echo "Updating $link" >&2
17  declare -A basemap=()
18  declare -a dirs=(
19    "/usr/share/authorized_keys.d/$user"
20    "$home/.ssh/authorized_keys.d"
21    "/run/authorized_keys.d/$user"
22  )
23  # Build a map that can be used for sorting directories by their priority
24  # and prioritizing the last listed directories over the later ones. We
25  # append a counter to ensure that there is a stable sorting mechanism for
26  # duplicate filenames. Duplicate filenames will be overridden by higher
27  # priority directories.
28  # Ex.
29  #   /usr/share/authorized_keys.d/root/10-key
30  #   /usr/share/authorized_keys.d/root/15-key
31  #   /run/authorized_keys.d/root/10-key
32  #   /run/authorized_keys.d/root/20-key
33  #  Becomes
34  #   ["10-key"]="/run/authorized_keys.d/root/10-key"
35  #   ["15-key"]="/usr/share/authorized_keys.d/root/15-key"
36  #   ["20-key"]="/run/authorized_keys.d/root/20-key"
37  for dir in "${dirs[@]}"; do
38    for file in "$dir"/*; do
39      basemap["${file##*/}"]="$file"
40    done
41  done
42  rm -f /run/authorized_keys.tmp
43  touch /run/authorized_keys.tmp
44  for key in $(printf "%s\n" "${!basemap[@]}" | sort -r); do
45    echo "  Including ${basemap[$key]}" >&2
46    cat "${basemap[$key]}" >>/run/authorized_keys.tmp
47  done
48  mkdir -p /run/authorized_keys
49  mv /run/authorized_keys.tmp /run/authorized_keys/"$user"
50  chown "$user" /run/authorized_keys/"$user"
51done < <(cut -d':' -f1 /etc/passwd)
52