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