diff --git a/cdist/conf/type/__block/gencode-remote b/cdist/conf/type/__block/gencode-remote
index 973e9922..2e2147e5 100755
--- a/cdist/conf/type/__block/gencode-remote
+++ b/cdist/conf/type/__block/gencode-remote
@@ -46,13 +46,13 @@ tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX)
if [ -f "$file" ]; then
cp -p "$file" "\$tmpfile"
fi
-awk -v prefix="^$prefix\\\$" -v suffix="^$suffix\\\$" '
+awk -v prefix="^$prefix\$" -v suffix="^$suffix\$" '
{
- if (index(\$0,prefix)) {
+ if (match(\$0,prefix)) {
triggered=1
}
if (triggered) {
- if (index(\$0,suffix)) {
+ if (match(\$0,suffix)) {
triggered=0
}
} else {
diff --git a/cdist/conf/type/__ssh_authorized_key/explorer/entry b/cdist/conf/type/__ssh_authorized_key/explorer/entry
new file mode 100755
index 00000000..78031ab5
--- /dev/null
+++ b/cdist/conf/type/__ssh_authorized_key/explorer/entry
@@ -0,0 +1,26 @@
+#!/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 .
+#
+
+# extract the keytype and base64 encoded key ignoring any options and comment
+type_and_key="$(cat "$__object/parameter/key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')"
+file="$(cat $__object/parameter/file)"
+
+# get any entries that match the type and key
+grep ".*$type_and_key[ \n]" "$file" || true
diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote
new file mode 100755
index 00000000..62c79ed2
--- /dev/null
+++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote
@@ -0,0 +1,109 @@
+#!/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 .
+#
+
+set -u
+
+remove_line() {
+ file="$1"
+ line="$2"
+ cat << DONE
+tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX)
+# preserve ownership and permissions of existing file
+if [ -f "$file" ]; then
+ cp -p "$file" "\$tmpfile"
+fi
+grep -v -F -x '$line' '$file' > \$tmpfile || true
+mv -f "\$tmpfile" "$file"
+DONE
+}
+
+add_line() {
+ file="$1"
+ line="$2"
+ # escape single quotes
+ line_sanitised=$(echo "$line" | sed -e "s/'/'\"'\"'/g")
+ printf '%s' "printf '%s\n' '$line_sanitised' >> $file"
+}
+
+
+file="$(cat "$__object/parameter/file")"
+mkdir "$__object/files"
+
+# Generate the entry as it should be
+(
+ if [ -f "$__object/parameter/option" ]; then
+ # comma seperated list of options
+ options="$(cat "$__object/parameter/option" | tr '\n' ',')"
+ printf '%s ' "${options%*,}"
+ fi
+ if [ -f "$__object/parameter/comment" ]; then
+ # extract the keytype and base64 encoded key ignoring any options and comment
+ printf '%s ' "$(cat "$__object/parameter/key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')"
+ # override the comment with the one explicitly given
+ printf '%s' "$(cat "$__object/parameter/comment")"
+ else
+ printf '%s' "$(cat "$__object/parameter/key")"
+ fi
+ printf '\n'
+) > "$__object/files/should"
+
+# Remove conflicting entries if any
+if [ -s "$__object/explorer/entry" ]; then
+ # Note that the files have to be sorted for comparison with `comm`.
+ sort "$__object/explorer/entry" > "$__object/files/is"
+ comm -13 "$__object/files/should" "$__object/files/is" | {
+ while read entry; do
+ remove_line "$file" "$entry"
+ done
+ }
+fi
+
+# Determine the current state
+entry="$(cat "$__object/files/should")"
+state_should="$(cat "$__object/parameter/state")"
+num_existing_entries=$(grep -c -F -x "$entry" "$__object/explorer/entry")
+if [ $num_existing_entries -eq 1 ]; then
+ state_is="present"
+else
+ # Posix grep does not define the -m option, so we can not remove a single
+ # occurence of a string from a file in the `remove_line` function. Instead
+ # _all_ occurences are removed.
+ # By using `comm` to detect conflicting entries this could lead to the
+ # situation that the key we want to add is actually removed.
+ # To workaround this we must treat 0 or more then 1 existing entries to
+ # mean current state is 'absent'. By doing this, the key is readded
+ # again after cleaning up conflicting entries.
+ state_is="absent"
+fi
+
+# Manage the actual entry as it should be
+if [ "$state_should" = "$state_is" ]; then
+ # Nothing to do
+ exit 0
+fi
+
+case "$state_should" in
+ present)
+ add_line "$file" "$entry"
+ ;;
+ absent)
+ remove_line "$file" "$entry"
+ ;;
+esac
diff --git a/cdist/conf/type/__ssh_authorized_key/man.text b/cdist/conf/type/__ssh_authorized_key/man.text
new file mode 100644
index 00000000..b519222c
--- /dev/null
+++ b/cdist/conf/type/__ssh_authorized_key/man.text
@@ -0,0 +1,67 @@
+cdist-type__ssh_authorized_key(7)
+=================================
+Steven Armstrong
+
+
+NAME
+----
+cdist-type__ssh_authorized_key - manage a single ssh authorized key entry
+
+
+DESCRIPTION
+-----------
+Manage a single authorized key entry in an authorized_key file.
+This type was created to be used by the __ssh_authorized_keys type.
+
+
+REQUIRED PARAMETERS
+-------------------
+file::
+ the authorized_keys file to which the given key should be added
+
+key::
+ a string containing the ssh keytype, base 64 encoded key and optional
+ trailing comment which shall be added to the given authorized_keys file.
+
+
+OPTIONAL PARAMETERS
+-------------------
+comment::
+ explicit comment instead of the one which may be trailing the given key
+
+option::
+ an option to set for this authorized_key entry.
+ Can be specified multiple times.
+ See sshd(8) for available options.
+
+state::
+ if the given keys should be 'present' or 'absent', defaults to 'present'.
+
+
+EXAMPLES
+--------
+
+--------------------------------------------------------------------------------
+__ssh_authorized_key some-id \
+ --file "/home/user/.ssh/autorized_keys" \
+ --key "$(cat ~/.ssh/id_rsa.pub)"
+
+__ssh_authorized_key some-id \
+ --file "/home/user/.ssh/autorized_keys" \
+ --key "$(cat ~/.ssh/id_rsa.pub)" \
+ --option 'command="/path/to/script"' \
+ --option 'environment="FOO=bar"' \
+ --comment 'one to rule them all'
+--------------------------------------------------------------------------------
+
+
+SEE ALSO
+--------
+- cdist-type(7)
+- cdist__ssh_authorized_keys(7)
+- sshd(8)
+
+COPYING
+-------
+Copyright \(C) 2014 Steven Armstrong. Free use of this software is
+granted under the terms of the GNU General Public License version 3 (GPLv3).
diff --git a/cdist/conf/type/__ssh_authorized_key/parameter/default/state b/cdist/conf/type/__ssh_authorized_key/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__ssh_authorized_key/parameter/default/state
@@ -0,0 +1 @@
+present
diff --git a/cdist/conf/type/__ssh_authorized_key/parameter/optional b/cdist/conf/type/__ssh_authorized_key/parameter/optional
new file mode 100644
index 00000000..89e8d966
--- /dev/null
+++ b/cdist/conf/type/__ssh_authorized_key/parameter/optional
@@ -0,0 +1,2 @@
+comment
+state
diff --git a/cdist/conf/type/__ssh_authorized_key/parameter/optional_multiple b/cdist/conf/type/__ssh_authorized_key/parameter/optional_multiple
new file mode 100644
index 00000000..01925a15
--- /dev/null
+++ b/cdist/conf/type/__ssh_authorized_key/parameter/optional_multiple
@@ -0,0 +1 @@
+option
diff --git a/cdist/conf/type/__ssh_authorized_key/parameter/required b/cdist/conf/type/__ssh_authorized_key/parameter/required
new file mode 100644
index 00000000..d51426c3
--- /dev/null
+++ b/cdist/conf/type/__ssh_authorized_key/parameter/required
@@ -0,0 +1,2 @@
+file
+key
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..6a536e1b 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,25 @@ __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
+ # Ensure __ssh_authorized_key does not read stdin
+ __ssh_authorized_key "$@" < /dev/null
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