Project

General

Profile

User story #4441 » sshKeyDisable.st

Alex Tkachenko, 2014-02-15 01:47

 
# Remove SSH keys from user's configuration (typically ~user/.ssh/authorized_keys)
#
# By Alex Tkachenko <alex.sysadm@gmail.com>
#
bundle agent rudder_disable_ssh_keys
{
vars:

any::
"technique_name" string => "SSH keys removal";
"component_name" string => "SSH key";

# "config_basename" string => "&SSH_DISABLE_KEY_CONFIG_BASENAME&";
"config_basename" string => "authorized_keys";

&SSH_DISABLE_KEY_TAG:{tag |"sshkey_disable_tag[&i&]" string => "&tag&";
}&
&SSH_DISABLE_KEY_USERNAME:{username |"sshkey_disable_name[&i&]" string => "&username&";
}&
&SSH_DISABLE_KEY_KEYSPEC:{keyspec |"sshkey_disable_key[&i&]" string => "&keyspec&";
}&
&TRACKINGKEY:{uuid |"sshkey_disable_uuid[&i&]" string => "&uuid&";
}&

"sshkey_disable_index"
slist => getindices("sshkey_disable_name");
"sshkey_class_prefix[${sshkey_disable_index}]"
string => canonify("${sshkey_disable_tag[${sshkey_disable_index}]}_${sshkey_disable_uuid[${sshkey_disable_index}]}");
"userdata_${sshkey_disable_index}"
string => execresult("/usr/bin/getent passwd ${sshkey_disable_name[${sshkey_disable_index}]}", "noshell");
"no_${sshkey_disable_index}"
int => parsestringarray("userarray_${sshkey_disable_index}", "${userdata_${sshkey_disable_index}}", "", ":", "1000", "200000" );
"homedir[${sshkey_disable_index}]"
string => "${userarray_${sshkey_disable_index}[${sshkey_disable_name[${sshkey_disable_index}]}][5]}";

classes:

any::
"begin_evaluation"
expression => isvariable("sshkey_disable_index");

begin_evaluation::
"user_${sshkey_disable_index}_exists"
expression => userexists("${sshkey_disable_name[${sshkey_disable_index}]}");

"cfgfile_${sshkey_disable_index}_exists"
ifvarclass => canonify("user_${sshkey_disable_index}_exists"),
expression => fileexists("${homedir[${sshkey_disable_index}]}/.ssh/${config_basename}");


files:

"${homedir[${sshkey_disable_index}]}/.ssh/${config_basename}"
comment => "Remove key from ${config_basename}",
edit_line => remove_ssh_key("${sshkey_disable_key[${sshkey_disable_index}]}"),
ifvarclass => "cfgfile_${sshkey_disable_index}_exists",
classes => rudder_common_classes("${sshkey_class_prefix[${sshkey_disable_index}]}");

methods:

"No User Exist Report"
ifvarclass => "!user_${sshkey_disable_index}_exists",
usebundle => rudder_common_report(
"${technique_name}", "result_success",
"${sshkey_disable_uuid[${sshkey_disable_index}]}", "${component_name}", "${sshkey_disable_tag[${sshkey_disable_index}]}", "The user ${sshkey_disable_name[${sshkey_disable_index}]} does NOT exist on this machine...skipping this check"
);
"No ${config_basename} File Exist Report"
ifvarclass => "user_${sshkey_disable_index}_exists.!cfgfile_${sshkey_disable_index}_exists",
usebundle => rudder_common_report(
"${technique_name}", "result_success",
"${sshkey_disable_uuid[${sshkey_disable_index}]}", "${component_name}", "${sshkey_disable_tag[${sshkey_disable_index}]}", "The user ${sshkey_disable_name[${sshkey_disable_index}]} does NOT have ${config_basename} file on this machine...skipping this check"
);

# Removal Key Reports - rudder_common_reports_generic is not used as the messaging is reversed
"Report key not found"
usebundle => rudder_common_report(
"${technique_name}", "result_success", "${sshkey_disable_uuid[${sshkey_disable_index}]}", "${component_name}", "${sshkey_disable_tag[${sshkey_disable_index}]}",
"SSH key \"${sshkey_disable_tag[${sshkey_disable_index}]}\" was not found in user ${sshkey_disable_name[${sshkey_disable_index}]} ${config_basename} file"),
ifvarclass => "${sshkey_class_prefix[${sshkey_disable_index}]}_kept.!${sshkey_class_prefix[${sshkey_disable_index}]}_repaired.!${sshkey_class_prefix[${sshkey_disable_index}]}_error";

"Report key removed"
usebundle => rudder_common_report(
"${technique_name}", "result_repaired", "${sshkey_disable_uuid[${sshkey_disable_index}]}", "${component_name}", "${sshkey_disable_tag[${sshkey_disable_index}]}",
"SSH key \"${sshkey_disable_tag[${sshkey_disable_index}]}\" for user ${sshkey_disable_name[${sshkey_disable_index}]} was removed"),
ifvarclass => "${sshkey_class_prefix[${sshkey_disable_index}]}_repaired.!${sshkey_class_prefix[${sshkey_disable_index}]}_error";

"Report removal failure"
usebundle => rudder_common_report(
"${technique_name}", "result_error", "${sshkey_disable_uuid[${sshkey_disable_index}]}", "${component_name}", "${sshkey_disable_tag[${sshkey_disable_index}]}",
"SSH key \"${sshkey_disable_tag[${sshkey_disable_index}]}\" for user ${sshkey_disable_name[${sshkey_disable_index}]} could not be removed"),
ifvarclass => "${sshkey_class_prefix[${sshkey_disable_index}]}_error";
}

# Remove ssh key from the file. The key is matched by the key value
# (i.e. comments, options in the keyspec are ignored).
bundle edit_line remove_ssh_key(keyspec)
{
vars:
key_parsed::
"ckey" string => canonify($(keybits[3]));
"ekey" string => escape($(keybits[3]));

classes:
"key_parsed"
# If the key hash happens to exceed 1000 chars $keybits[3] is going to be undefined because
# of some weird cfengine bugs, probably this one: https://cfengine.com/dev/issues/1258
# Therefore we limit the regex to extract as much of the hash as possible to make it unique enough
# without exceeding 1000 charachter limit.
# The hashes of that length apparently correspond to DSS 2048 bits keys, generated i.e. on rhel 4,
# with openssh v3.9p1-redhat. I believe that since openssh v4 DSS bitlengh is limited to 1024,
# as required by FIPS.
expression => regextract("(.*\s+)?(ssh-rsa|ssh-dss)\s+(\S{1,1000})\S*=(\s+.+)?\Z", "$(keyspec)", "keybits" );

delete_lines:
".*\s$(ekey)\s?.*"
ifvarclass => "key_parsed";
}
(4-4/4)