From ffd2935cc438e8e9ef7b7953f3d2201b2b2c7e5d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 25 Sep 2014 16:16:15 +0200 Subject: [PATCH] complete rewrite - add support for authorized_keys options see sshd(8) - add support for explicit comment after key - do not allow a key to exist more then once in an authorized_keys file - remove all conflicting keys Signed-off-by: Steven Armstrong --- .../__ssh_authorized_keys/explorer/entries | 32 ++++++++++++++++ .../explorer/{passwd => file} | 12 ++++-- .../type/__ssh_authorized_keys/explorer/group | 3 +- .../conf/type/__ssh_authorized_keys/man.text | 38 ++++++++++++++----- .../conf/type/__ssh_authorized_keys/manifest | 34 +++++++---------- .../__ssh_authorized_keys/parameter/optional | 4 +- 6 files changed, 88 insertions(+), 35 deletions(-) create mode 100755 cdist/conf/type/__ssh_authorized_keys/explorer/entries rename cdist/conf/type/__ssh_authorized_keys/explorer/{passwd => file} (68%) diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/entries b/cdist/conf/type/__ssh_authorized_keys/explorer/entries new file mode 100755 index 00000000..04e25880 --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/explorer/entries @@ -0,0 +1,32 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# Find and sort any entries in the authorized_keys file that we care about + +file="$($__type_explorer/file)" + +( + while read key; do + # extract the keytype and base64 encoded key ignoring any options and comment + type_and_key="$(echo "$key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" + # emit any entries that match the type and key + grep ".*$type_and_key[ \n]" "$file" + done < "$__object/parameter/key" +) | sort diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/passwd b/cdist/conf/type/__ssh_authorized_keys/explorer/file similarity index 68% rename from cdist/conf/type/__ssh_authorized_keys/explorer/passwd rename to cdist/conf/type/__ssh_authorized_keys/explorer/file index e6352ee0..5a02721a 100755 --- a/cdist/conf/type/__ssh_authorized_keys/explorer/passwd +++ b/cdist/conf/type/__ssh_authorized_keys/explorer/file @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -18,6 +18,10 @@ # along with cdist. If not, see . # -owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" - -getent passwd "$owner" || true +if [ -f "$__object/parameter/file" ]; then + cat "$__object/parameter/file" +else + owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" + home=$(getent passwd "$owner" | cut -d':' -f 6) + echo "$home/.ssh/authorized_keys" +fi diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/group b/cdist/conf/type/__ssh_authorized_keys/explorer/group index cdea6fe7..72a4e314 100755 --- a/cdist/conf/type/__ssh_authorized_keys/explorer/group +++ b/cdist/conf/type/__ssh_authorized_keys/explorer/group @@ -18,5 +18,6 @@ # along with cdist. If not, see . # -gid="$("$__type_explorer/passwd" | cut -d':' -f 4)" +owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" +gid="$(getent passwd "$owner" | cut -d':' -f 4)" getent group "$gid" || true diff --git a/cdist/conf/type/__ssh_authorized_keys/man.text b/cdist/conf/type/__ssh_authorized_keys/man.text index 2e4202a7..d5523a6e 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.text +++ b/cdist/conf/type/__ssh_authorized_keys/man.text @@ -12,13 +12,13 @@ DESCRIPTION ----------- Adds or removes ssh keys from a authorized_keys file. -This type uses the __ssh_dot_ssh type to the directory containing -the authorized_keys file. -You can disable this feature with the --noparent boolean parameter. +This type uses the __ssh_dot_ssh type to manage the directory containing +the authorized_keys file. You can disable this feature with the --noparent +boolean parameter. The existence, ownership and permissions of the authorized_keys file itself are also managed. This can be disabled with the --nofile boolean parameter. It is -then left to the user to ensure that the file exists and that ownership and +then left to the user to ensure that the file exists and that ownership and permissions work with ssh. @@ -31,15 +31,23 @@ key:: OPTIONAL PARAMETERS ------------------- +comment:: + explicit comment instead of the one which may be trailing the given key + +file:: + an alternative destination file, defaults to ~$owner/.ssh/authorized_keys + +option:: + an option to set for all created authorized_key entries. + Can be specified multiple times. + See sshd(8) for available options. + owner:: the user owning the authorized_keys file, defaults to object_id. state:: if the given keys should be 'present' or 'absent', defaults to 'present'. -file:: - an alternative destination file, defaults to ~$owner/.ssh/authorized_keys - BOOLEAN PARAMETERS ------------------ @@ -64,13 +72,24 @@ __ssh_authorized_keys root \ __ssh_authorized_keys user-name \ --key "ssh-rsa AXYZAAB3NzaC1yc2..." +# allow key to login as user-name with options and expicit comment +__ssh_authorized_keys user-name \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ + --option no-agent-forwarding \ + --option 'from="*.example.com"' \ + --comment 'backup server' + # same as above, but with explicit owner and two keys +# note that the options are set for all given keys __ssh_authorized_keys some-fancy-id \ --owner user-name \ --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ - --key "ssh-rsa AZXYAAB3NzaC1yc2..." + --key "ssh-rsa AZXYAAB3NzaC1yc2..." \ + --option no-agent-forwarding \ + --option 'from="*.example.com"' \ + --comment 'backup server' -# same as above, but authorized_keys file in non standard location +# authorized_keys file in non standard location __ssh_authorized_keys some-fancy-id \ --file /etc/ssh/keys/user-name/authorized_keys \ --owner user-name \ @@ -89,6 +108,7 @@ __ssh_authorized_keys some-fancy-id \ SEE ALSO -------- - cdist-type(7) +- sshd(8) COPYING diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 5885ec77..0fcfed5b 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -21,16 +21,7 @@ owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" state="$(cat "$__object/parameter/state" 2>/dev/null)" -if [ -f "$__object/parameter/file" ]; then - file="$(cat "$__object/parameter/file")" -else - home="$(cut -d':' -f 6 "$__object/explorer/passwd")" - if [ -z "$home" ]; then - echo "Failed to get home directory from explorer." >&2 - exit 1 - fi - file="$home/.ssh/authorized_keys" -fi +file="$(cat "$__object/explorer/file")" if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; then group="$(cut -d':' -f 1 "$__object/explorer/group")" @@ -50,6 +41,7 @@ if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; --group "$group" \ --mode 0600 \ --state exists + export require="__file/$file" fi fi @@ -63,22 +55,24 @@ __block "$__object_name" \ --text - << DONE remove legacy block DONE +export require="__block/$__object_name" _cksum() { echo "$1" | cksum | cut -d' ' -f 1 } while read key; do - cksum_key="$(_cksum "$key")" - line_id="${owner}-${cksum_key}" - - set -- "$line_id" + type_and_key="$(echo "$key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" + object_id="$(_cksum "$file")-$(_cksum "$type_and_key")" + set -- "$object_id" set -- "$@" --file "$file" - set -- "$@" --regex ".*$key.*" - if [ "$state" = 'present' ]; then - set -- "$@" --line "$key" - fi + set -- "$@" --key "$key" set -- "$@" --state "$state" - # Ensure __line does not read stdin - require="__block/$__object_name" __line "$@" < /dev/null + if [ -f "$__object/parameter/option" ]; then + set -- "$@" --option "$(cat "$__object/parameter/option")" + fi + if [ -f "$__object/parameter/comment" ]; then + set -- "$@" --comment "$(cat "$__object/parameter/comment")" + fi + __ssh_authorized_key "$@" done < "$__object/parameter/key" diff --git a/cdist/conf/type/__ssh_authorized_keys/parameter/optional b/cdist/conf/type/__ssh_authorized_keys/parameter/optional index 989750b3..21f9bc29 100644 --- a/cdist/conf/type/__ssh_authorized_keys/parameter/optional +++ b/cdist/conf/type/__ssh_authorized_keys/parameter/optional @@ -1,3 +1,5 @@ +comment +file +option owner state -file