From 60b8c51d6772a1bd8ba9b2416968a74c09000f3b Mon Sep 17 00:00:00 2001 From: Jameson Graef Rollins Date: Sun, 4 May 2008 21:46:20 -0400 Subject: [PATCH] major overhaul of rhesus. it now handles creation of both authorized_keys and known_hosts files, and is capable of being used by an administrator to maintain authorized_keys files for users. monkeysphere.conf file was updated for use by system administrator. --- monkeysphere.conf | 17 +-- rhesus/README | 33 ++++- rhesus/rhesus | 322 +++++++++++++++++++++++++++++++--------------- 3 files changed, 256 insertions(+), 116 deletions(-) diff --git a/monkeysphere.conf b/monkeysphere.conf index 1a6cff1..a54b6bd 100644 --- a/monkeysphere.conf +++ b/monkeysphere.conf @@ -1,18 +1,15 @@ -# monkeysphere configuration file -# this is currently meant to be sourced by bash. +# monkeysphere system configuration file -# configuration directory -CONF_DIR=/etc/monkeysphere +# This is particular configuration is meant to be sourced by the +# rhesus shell script when run in administrative mode to maintain +# authorized_keys files for users. -# where the per-user authorized user id files are stored -AUTH_USER_IDS_DIR="$CONF_DIR"/auth_user_ids +AUTH_USER_FILE=/etc/monkeysphere/auth_user_ids/"$USER" -# where the per-user authorized_keys info is stored -#AUTH_KEYS_DIR=/var/lib/monkeysphere/authorized_keys -AUTH_KEYS_DIR="$CONF_DIR"/authorized_keys +STAGING_AREA=/var/lib/monkeysphere/stage/"$USER" # gpg home directory for server -GNUPGHOME="$CONF_DIR"/gnupg +GNUPGHOME=/etc/monkeysphere/gnupg # gpg keyserver to search for keys KEYSERVER=subkeys.pgp.net diff --git a/rhesus/README b/rhesus/README index 226361c..4d383d5 100644 --- a/rhesus/README +++ b/rhesus/README @@ -1,7 +1,30 @@ -rhesus is the monkeysphere authorized_keys generator. +rhesus is the monkeysphere authorized_keys/known_hosts generator. -It's goal is to take a user's auth_user_ids file, which contains gpg -user ids (and possibly authorized_keys options), use gpg to fetch the -keys of the specified users, do a monkeysphere policy check on each -id, and generate authorized_keys lines for verified id. +In authorized_keys mode, rhesus takes an auth_user_ids file, which +contains gpg user ids, uses gpg to fetch the keys of the specified +users, does a monkeysphere policy check on each id, and uses gpg2ssh +to generate authorized_keys lines for each verified id. The lines are +then combined with a user's traditional authorized_keys file to create +a new authorized_keys file. +In known_hosts mode, rhesus takes an auth_host_ids file, which +contains gpg user ids of the form ssh://URL, uses gpg to fetch the +keys of the specified hosts, does a monkeysphere policy check on each +id, and uses gpg2ssh to generate a known_hosts lines for each verified +id. The lines are then combined with a user's traditional known_hosts +file to create a new known_hosts file. + +When run as a normal user, no special configuration is needed. + +When run as an administrator to update system-maintained +authorized_keys files for each user, the following environment +variables should be defined first: + + MS_CONF=/etc/monkeysphere/monkeysphere.conf + USER=foo + +For example, the command might be run like this: + + for USER in $(ls -1 /home) ; do + MS_CONF=/etc/monkeysphere/monkeysphere.conf rhesus --authorized_keys + done diff --git a/rhesus/rhesus b/rhesus/rhesus index 0c7e100..fc2f2f5 100755 --- a/rhesus/rhesus +++ b/rhesus/rhesus @@ -1,25 +1,32 @@ -#!/bin/sh +#!/bin/sh -e -# rhesus: monkeysphere authorized_keys update script +# rhesus: monkeysphere authorized_keys/known_hosts generating script +# +# When run as a normal user, no special configuration is needed. +# +# When run as an administrator to update users' authorized_keys files, +# the following environment variables should be defined first: +# +# MS_CONF=/etc/monkeysphere/monkeysphere.conf +# USER=foo +# +# ie: +# +# for USER in $(ls -1 /home) ; do +# MS_CONF=/etc/monkeysphere/monkeysphere.conf rhesus --authorized_keys +# done # # Written by # Jameson Rollins # # Copyright 2008, released under the GPL, version 3 or later -################################################## -# load conf file -CONF_FILE=${CONF_FILE:-"/etc/monkeysphere/monkeysphere.conf"} -. "$CONF_FILE" - -export GNUPGHOME -################################################## - CMD=$(basename $0) usage() { cat < SKIPPING" + continue + fi + + # extract needed fields + key_trust=$(echo "$pub_info" | cut -d: -f2) + keyid=$(echo "$pub_info" | cut -d: -f5) + key_capability=$(echo "$pub_info" | cut -d: -f12) + + # check if key disabled + if echo "$key_capability" | grep -q '[D]' ; then + echo " key disabled -> SKIPPING" + continue + fi + + # check key capability + if echo "$key_capability" | grep -q '[$REQUIRED_KEY_CAPABILITY]' ; then + echo " key capability verified ('$key_capability')." + else + echo " unacceptable key capability ('$key_capability') -> SKIPPING" + continue + fi + + # if key is not fully trusted exit + # (this includes not revoked or expired) + # determine trust + echo -n " key " + case "$key_trust" in + 'i') + echo -n "invalid" ;; + 'r') + echo -n "revoked" ;; + 'e') + echo -n "expired" ;; + '-'|'q'|'n'|'m') + echo -n "has unacceptable trust" ;; + 'f'|'u') + echo -n "fully trusted" + gen_key=true + ;; + *) + echo -n "has unknown trust" ;; + esac + + if [ "$gen_key" ] ; then + # convert pgp key to ssh key, and write to cache file + echo -n " -> generating ssh key... " + gpg2ssh "$mode" "$keyid" > "$key_dir"/"$userid_hash" + echo "done." + else + echo ". -> SKIPPING" + fi + + else + echo " key not found." + fi + done +} + +######################################################################## +# MAIN +######################################################################## if [ -z "$1" ] ; then usage exit 1 fi -# user name of user to update -USERNAME="$1" -if ! id "$USERNAME" > /dev/null ; then - failure "User '$USERNAME' does not exist." -fi +# check mode +mode="$1" +shift 1 -AUTH_USER_IDS="$AUTH_USER_IDS_DIR"/"$USERNAME" -if [ ! -e "$AUTH_USER_IDS" ] ; then - failure "No auth_user_ids file for user '$USERNAME'." +# check user +if ! id -u "$USER" > /dev/null 2>&1 ; then + failure "invalid user '$USER'." fi -KEYDIR="$AUTH_KEYS_DIR"/"$USERNAME"/keys -AUTH_KEYS="$AUTH_KEYS_DIR"/authorized_keys +HOME=$(getent passwd "$USER" | cut -d: -f6) -# make sure the gnupg home exists with proper permissions -mkdir -p "$GNUPGHOME" -chmod 0700 "$GNUPGHOME" +MS_HOME=${MS_HOME:-"$HOME"/.config/monkeysphere} -# find number of user ids in auth_user_ids file -NLINES=$(meat "$AUTH_USER_IDS" | wc -l) +# load conf file +MS_CONF=${MS_CONF:-"$MS_HOME"/monkeysphere.conf} +[ -e "$MS_CONF" ] && . "$MS_CONF" -# clean out keys file and remake keys directory -rm -rf "$KEYDIR" -mkdir -p "$KEYDIR" +# set config variable defaults +STAGING_AREA=${STAGING_AREA:-"$MS_HOME"} +AUTH_HOST_FILE=${AUTH_HOST_FILE:-"$MS_HOME"/auth_host_ids} +AUTH_USER_FILE=${AUTH_USER_FILE:-"$MS_HOME"/auth_user_ids} +GNUPGHOME=${GNUPGHOME:-"$HOME"/.gnupg} +KEYSERVER=${KEYSERVER:-subkeys.pgp.net} +REQUIRED_KEY_CAPABILITY=${REQUIRED_KEY_CAPABILITY:-'a'} -# loop through all user ids, and generate ssh keys -for (( N=1; N<=$NLINES; N=N+1 )) ; do - # get user id - USERID=$(meat "$AUTH_USER_IDS" | cutline "$N" ) - USERID_HASH=$(echo "$USERID" | sha1sum | awk '{ print $1 }') +export USER +export GNUPGHOME - KEYFILE="$KEYDIR"/"$USERID_HASH" +host_keys_dir="$STAGING_AREA"/host_keys +user_keys_dir="$STAGING_AREA"/user_keys +known_hosts_stage_file="$STAGING_AREA"/known_hosts +authorized_keys_stage_file="$STAGING_AREA"/authorized_keys - # search for key on keyserver - echo "ms: validating: '$USERID'" - RETURN=$(echo 1 | gpg --quiet --batch --command-fd 0 --with-colons --keyserver "$KEYSERVER" --search ="$USERID") +# act on mode +if [ "$mode" = '--known_hosts' -o "$mode" = '-k' ] ; then - # if the key was found... - if [ "$RETURN" ] ; then - echo "ms: key found." - - # checking key attributes - # see /usr/share/doc/gnupg/DETAILS.gz: - - PUB_INFO=$(gpg --fixed-list-mode --with-colons --list-keys --with-fingerprint ="$USERID" | grep '^pub:') + # set variables for process_keys command + ids_file="$AUTH_HOST_FILE" + log -n "[$USER] " + if [ ! -s "$ids_file" ] ; then + echo "auth_host_ids file is empty or does not exist." + exit + else + echo "updating known_hosts file..." + fi + key_dir="$host_keys_dir" - # extract needed fields - KEY_TRUST=$(echo "$PUB_INFO" | cut -d: -f2) - KEY_CAPABILITY=$(echo "$PUB_INFO" | cut -d: -f12) - - # check if key disabled - if echo "$KEY_CAPABILITY" | grep -q '[D]' ; then - echo "ms: key disabled -> SKIPPING" - continue - fi + # process the keys + process_keys - # check key capability - REQUIRED_KEY_CAPABILITY=${REQUIRED_KEY_CAPABILITY:-'a'} - if echo "$KEY_CAPABILITY" | grep -q '[$REQUIRED_KEY_CAPABILITY]' ; then - echo "ms: key capability verified ('$KEY_CAPABILITY')." - else - echo "ms: unacceptable key capability ('$KEY_CAPABILITY') -> SKIPPING" - continue - fi + # write known_hosts file + > "$known_hosts_stage_file" + if [ $(ls "$key_dir") ] ; then + log -n "writing known_hosts stage file..." + cat "$key_dir"/* > "$known_hosts_stage_file" + echo "done." + else + log "no gpg keys to add to known_hosts file." + fi + if [ -s "$HOME"/.ssh/known_hosts ] ; then + log -n "adding user known_hosts file... " + cat "$HOME"/.ssh/known_hosts >> "$known_hosts_stage_file" + echo "done." + fi + log "known_hosts file updated: $known_hosts_stage_file" - echo -n "ms: key " - - # if key is not fully trusted exit - # (this includes not revoked or expired) - # determine trust - case "$KEY_TRUST" in - 'i') - echo -n "invalid" ;; - 'r') - echo -n "revoked" ;; - 'e') - echo -n "expired" ;; - '-'|'q'|'n'|'m') - echo -n "has unacceptable trust" ;; - 'f'|'u') - echo -n "fully trusted" - # convert pgp key to ssh key, and write to cache file - echo -n " -> generating ssh key..." - #gpg2ssh "$KEYID" | sed -e "s/COMMENT/$USERID/" > "$KEYFILE" - echo " done." - continue - ;; - *) - echo -n "has unknown trust" ;; - esac - echo ". -> SKIPPING" +elif [ "$mode" = '--authorized_keys' -o "$mode" = '-a' ] ; then + + # set variables for process_keys command + ids_file="$AUTH_USER_FILE" + log -n "[$USER] " + if [ ! -s "$ids_file" ] ; then + echo "auth_user_ids file is empty or does not exist." + exit else - echo "ms: key not found." + echo "updating authorized_keys file:" fi -done + key_dir="$user_keys_dir" + + # process the keys + process_keys -if [ $(ls "$KEYDIR") ] ; then - echo "ms: writing ms authorized_keys file..." - cat "$KEYDIR"/* > "$AUTH_KEYS" -else - echo "ms: no gpg keys to add to authorized_keys file." -fi -if [ -s ~"$USERNAME"/.ssh/authorized_keys ] ; then - echo "ms: adding user authorized_keys..." - cat ~"$USERNAME"/.ssh/authorized_keys >> "$AUTH_KEYS" + # write authorized_keys file + > "$authorized_keys_stage_file" + if [ $(ls "$key_dir") ] ; then + log -n "writing ms authorized_keys file... " + cat "$key_dir"/* > "$authorized_keys_stage_file" + echo "done." + else + log "no gpg keys to add to authorized_keys file." + fi + if [ -s "$HOME"/.ssh/authorized_keys ] ; then + log -n "adding user authorized_keys file... " + cat "$HOME"/.ssh/authorized_keys >> "$authorized_keys_stage_file" + echo "done." + fi + log "authorized_keys file updated: $authorized_keys_stage_file" fi -- 2.25.1