From 99cea85e6c2fda0c9c38c60aa1a371e56f09ad64 Mon Sep 17 00:00:00 2001 From: Luis Toledo Date: Thu, 2 Jan 2020 16:05:35 -0300 Subject: [PATCH 1/2] getting password ot passphrase from job option --- contents/ssh-copy.sh | 27 +++++++++++++++++++++- contents/ssh-exec.sh | 32 ++++++++++++++++++++++++-- plugin.yaml | 53 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/contents/ssh-copy.sh b/contents/ssh-copy.sh index 42e2f68..b11029f 100755 --- a/contents/ssh-copy.sh +++ b/contents/ssh-copy.sh @@ -45,6 +45,15 @@ SSHOPTS="-p -P $PORT -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no authentication=$RD_CONFIG_AUTHENTICATION +if [[ -n "${RD_CONFIG_SSH_PASSWORD_OPTION:-}" ]] ; then + option="$(sed 's/option.//g' <<<$RD_CONFIG_SSH_PASSWORD_OPTION)" + rd_secure_password=$(echo "RD_PRIVATE_$option" | awk '{ print toupper($0) }') +fi + +if [[ -n "${RD_CONFIG_SSH_KEY_PASSPHRASE_OPTION:-}" ]] ; then + option="$(sed 's/option.//g' <<<$RD_CONFIG_SSH_KEY_PASSPHRASE_OPTION)" + rd_secure_passphrase=$(echo "RD_PRIVATE_$option" | awk '{ print toupper($0) }') +fi if [[ "privatekey" == "$authentication" ]] ; then @@ -65,6 +74,16 @@ if [[ "privatekey" == "$authentication" ]] ; then fi RUNSCP="scp $SSHOPTS $FILE $USER@$HOST:$DIR" + if [[ -n "${!rd_secure_passphrase}" ]]; then + mkdir -p "/tmp/.ssh-exec" + SSH_KEY_PASSPHRASE_STORAGE_PATH=$(mktemp "/tmp/.ssh-exec/ssh-passfile.$USER@$HOST.XXXXX") + echo "${!rd_secure_passphrase}" > "$SSH_PASS_STORAGE_PATH" + + RUNSSH="sshpass -P passphrase -f $SSH_KEY_PASSPHRASE_STORAGE_PATH ssh $SSHOPTS $USER@$HOST $CMD" + + trap 'rm "$SSH_KEY_PASSPHRASE_STORAGE_PATH"' EXIT + fi + ## add PASSPHRASE for key if [[ -n "${RD_CONFIG_SSH_KEY_PASSPHRASE_STORAGE_PATH:-}" ]] then @@ -81,7 +100,13 @@ fi if [[ "password" == "$authentication" ]] ; then mkdir -p "/tmp/.ssh-exec" SSH_PASS_STORAGE_PATH=$(mktemp "/tmp/.ssh-exec/ssh-passfile.$USER@$HOST.XXXXX") - echo "$RD_CONFIG_SSH_PASSWORD_STORAGE_PATH" > "$SSH_PASS_STORAGE_PATH" + + if [[ -n "${!rd_secure_password}" ]]; then + echo "${!rd_secure_password}" > "$SSH_PASS_STORAGE_PATH" + else + echo "$RD_CONFIG_SSH_PASSWORD_STORAGE_PATH" > "$SSH_PASS_STORAGE_PATH" + fi + RUNSCP="sshpass -f $SSH_PASS_STORAGE_PATH scp $SSHOPTS $FILE $USER@$HOST:$DIR" trap 'rm "$SSH_PASS_STORAGE_PATH"' EXIT diff --git a/contents/ssh-exec.sh b/contents/ssh-exec.sh index d7b509a..5cd11b9 100755 --- a/contents/ssh-exec.sh +++ b/contents/ssh-exec.sh @@ -41,6 +41,18 @@ SSHOPTS="-p $PORT -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o authentication=$RD_CONFIG_AUTHENTICATION + +if [[ -n "${RD_CONFIG_SSH_PASSWORD_OPTION:-}" ]] ; then + option="$(sed 's/option.//g' <<<$RD_CONFIG_SSH_PASSWORD_OPTION)" + rd_secure_password=$(echo "RD_PRIVATE_$option" | awk '{ print toupper($0) }') +fi + +if [[ -n "${RD_CONFIG_SSH_KEY_PASSPHRASE_OPTION:-}" ]] ; then + option="$(sed 's/option.//g' <<<$RD_CONFIG_SSH_KEY_PASSPHRASE_OPTION)" + rd_secure_passphrase=$(echo "RD_PRIVATE_$option" | awk '{ print toupper($0) }') +fi + + if [[ "privatekey" == "$authentication" ]] ; then #use ssh-keyfile node attribute from env vars @@ -60,6 +72,16 @@ if [[ "privatekey" == "$authentication" ]] ; then fi RUNSSH="ssh $SSHOPTS $USER@$HOST $CMD" + if [[ -n "${!rd_secure_passphrase}" ]]; then + mkdir -p "/tmp/.ssh-exec" + SSH_KEY_PASSPHRASE_STORAGE_PATH=$(mktemp "/tmp/.ssh-exec/ssh-passfile.$USER@$HOST.XXXXX") + echo "${!rd_secure_passphrase}" > "$SSH_PASS_STORAGE_PATH" + + RUNSSH="sshpass -P passphrase -f $SSH_KEY_PASSPHRASE_STORAGE_PATH ssh $SSHOPTS $USER@$HOST $CMD" + + trap 'rm "$SSH_KEY_PASSPHRASE_STORAGE_PATH"' EXIT + fi + ## add PASSPHRASE for key if [[ -n "${RD_CONFIG_SSH_KEY_PASSPHRASE_STORAGE_PATH:-}" ]] then @@ -74,15 +96,21 @@ if [[ "privatekey" == "$authentication" ]] ; then fi if [[ "password" == "$authentication" ]] ; then + mkdir -p "/tmp/.ssh-exec" SSH_PASS_STORAGE_PATH=$(mktemp "/tmp/.ssh-exec/ssh-passfile.$USER@$HOST.XXXXX") - echo "$RD_CONFIG_SSH_PASSWORD_STORAGE_PATH" > "$SSH_PASS_STORAGE_PATH" + + if [[ -n "${!rd_secure_password}" ]]; then + echo "${!rd_secure_password}" > "$SSH_PASS_STORAGE_PATH" + else + echo "$RD_CONFIG_SSH_PASSWORD_STORAGE_PATH" > "$SSH_PASS_STORAGE_PATH" + fi + RUNSSH="sshpass -f $SSH_PASS_STORAGE_PATH ssh $SSHOPTS $USER@$HOST $CMD" trap 'rm "$SSH_PASS_STORAGE_PATH"' EXIT fi - #if ssh-test is set to "true", do a dry run if [[ "true" == "$RD_CONFIG_DRY_RUN" ]] ; then echo "[ssh-exec]" "$RUNSSH" diff --git a/plugin.yaml b/plugin.yaml index e1ab3e8..e330f68 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -1,8 +1,17 @@ name: openssh node execution services -rundeckPluginVersion: 1.2 -author: Alex Honor -date: 08/14/2015 -version: 1.0 +rundeckPluginVersion: 2.0 +author: "@author@" +date: "@date@" +version: "@version@" +url: "@url@" +description: "OpenSSH Node Executor" +rundeckCompatibilityVersion: "3.2.x" +targetHostCompatibility: "all" +license: "Apache 2.0" +tags: + - script + - NodeExecutor + - FileCopier providers: - name: ssh-exec service: NodeExecutor @@ -72,7 +81,23 @@ providers: description: "Add custom settings to SSH connection. Eg: -o ConnectTimeout=10. A node attribute named ssh-options will override this value." scope: Instance renderingOptions: - instance-scope-node-attribute: "ssh-options" + instance-scope-node-attribute: "ssh-options" + - name: ssh_password_option + title: SSH Password with a Job Option + type: String + required: false + description: "Get the password form a job option (eg: `option.password`). The Job must define a Secure Remote Authentication Option to prompt the user for the password before execution. A node attribute named ssh-password-option will override this value" + scope: Instance + renderingOptions: + instance-scope-node-attribute: "ssh-password-option" + - name: ssh_key_passphrase_option + title: SSH Passphrase with a Job Option + type: String + required: false + description: "Get the passphrase form a job option (eg: `option.passphrase`). The Job must define a Secure Remote Authentication Option to prompt the user for the passphrase before execution. A node attribute named ssh-key-passphrase-option will override this value" + scope: Instance + renderingOptions: + instance-scope-node-attribute: "ssh-key-passphrase-option" - name: ssh-copier service: FileCopier title: 'openssh / file-copier' @@ -141,4 +166,20 @@ providers: description: "Add custom settings to SSH connection. Eg: -o ConnectTimeout=10. A node attribute named ssh-options will override this value." scope: Instance renderingOptions: - instance-scope-node-attribute: "ssh-options" + instance-scope-node-attribute: "ssh-options" + - name: ssh_password_option + title: SSH Password with a Job Option + type: String + required: false + description: "Get the password form a job option (eg: `option.password`). The Job must define a Secure Remote Authentication Option to prompt the user for the password before execution. A node attribute named ssh-password-option will override this value" + scope: Instance + renderingOptions: + instance-scope-node-attribute: "ssh-password-option" + - name: ssh_key_passphrase_option + title: SSH Passphrase with a Job Option + type: String + required: false + description: "Get the passphrase form a job option (eg: `option.passphrase`). The Job must define a Secure Remote Authentication Option to prompt the user for the passphrase before execution. A node attribute named ssh-key-passphrase-option will override this value" + scope: Instance + renderingOptions: + instance-scope-node-attribute: "ssh-key-passphrase-option" From c8cba87564d0cf5de285c65b919ac39588d82a83 Mon Sep 17 00:00:00 2001 From: Luis Toledo Date: Thu, 2 Jan 2020 17:02:34 -0300 Subject: [PATCH 2/2] - getting password or passphrase from secure remote option (rundeck 3.2.x needed) - dynamic username --- README.md | 105 +++++++++++++++++++++++++++++++++++++++++++ contents/ssh-copy.sh | 11 +++++ contents/ssh-exec.sh | 12 +++++ 3 files changed, 128 insertions(+) diff --git a/README.md b/README.md index bb252e4..8051060 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,55 @@ The plugin can be configured as a default node executor and file copier for a Pr Also, you can define the configuration at Node Level, setting the node-executor and file-copier attributes. +Settings: + +* **authentication**: Authentication.Authentication SSH Type (password or privatekey). A node attribute named ssh-authentication will override this value. +* **ssh_key_storage_path**: SSH key Storage Path. Optional storage path for ssh-key saved on the key storage. Can contain property references to node attributes. A node attribute named ssh-key-storage-path will override this value. +* **ssh_key_passphrase_storage_path**: SSH key Passphrase Storage Path. Optional storage path for ssh-key Passphrase. Can contain property references to node attributes. A node attribute named ssh-key-passphrase-storage-path will override this value. +* **ssh_password_storage_path**: SSH Password Storage Path. Optional storage path for ssh-key Passphrase. Can contain property references to node attributes. A node attribute named ssh-key-passphrase-storage-path will override this value. +* **ssh_options**: SSH Custom Options. Add custom settings to SSH connection. Eg: -o ConnectTimeout=10. A node attribute named ssh-options will override this value. +* **ssh_password_option**: SSH Password with a Job Option. Get the password form a job option (eg: `option.password`). The Job must define a Secure Remote Authentication Option to prompt the user for the password before execution. A node attribute named ssh-password-option will override this value. +* **ssh_key_passphrase_option**: SSH Passphrase with a Job Option. Get the passphrase form a job option (eg: `option.passphrase`). The Job must define a Secure Remote Authentication Option to prompt the user for the passphrase before execution. A node attribute named ssh-key-passphrase-option will override this value. + +## Dynamic Username + +You can use a dynamic username, defining the username value( `username` node attribute) from the job runner or from an input option. + +* ${job.username} - uses the username of the user executing the Rundeck execution. +* ${option.username} - uses the value of a job option named "username". + + +## Password or Passphrase from Secure Remote Authentication + +You can pass Password or Passphrase from a Job's Secure Remote Authentication Option. + +* ssh-password-option = "option.NAME" where NAME is the name of the Job's Secure Remote Authentication Option. +* ssh-key-passphrase-option = "option.NAME" where NAME is the name of the Job's Secure Remote Authentication Option. + + +## Examples + +Default project properties examples: + +``` +service.FileCopier.default.provider=ssh-copier +service.NodeExecutor.default.provider=ssh-exec + +project.plugin.NodeExecutor.ssh-exec.authentication=password +project.plugin.NodeExecutor.ssh-exec.ssh_key_passphrase_option=option.passphrase +project.plugin.NodeExecutor.ssh-exec.ssh_options=-o ConnectTimeout\=10 +project.plugin.NodeExecutor.ssh-exec.ssh_password_option=option.password +project.plugin.NodeExecutor.ssh-exec.ssh_password_storage_path=keys/node/user.password + +project.plugin.FileCopier.ssh-copier.authentication=password +project.plugin.FileCopier.ssh-copier.ssh_key_passphrase_option=option.passphrase +project.plugin.FileCopier.ssh-copier.ssh_options=-o ConnectTimeout\=10 +project.plugin.FileCopier.ssh-copier.ssh_password_option=option.password +project.plugin.FileCopier.ssh-copier.ssh_password_storage_path=keys/node/user.password +``` + + +Basic node definition (overwrite the default settings) ``` ``` + +Using password from option Secure Remote Authentication +``` + +``` +*a Secure Remote Authentication Option must be created on the job + +Using dynamic username +``` + +``` + +Using dynamic username from job option +``` + +``` +*a option called `username` must be added to the job \ No newline at end of file diff --git a/contents/ssh-copy.sh b/contents/ssh-copy.sh index b11029f..63406ff 100755 --- a/contents/ssh-copy.sh +++ b/contents/ssh-copy.sh @@ -55,6 +55,17 @@ if [[ -n "${RD_CONFIG_SSH_KEY_PASSPHRASE_OPTION:-}" ]] ; then rd_secure_passphrase=$(echo "RD_PRIVATE_$option" | awk '{ print toupper($0) }') fi +if [[ "$RD_NODE_USERNAME" =~ \$\{(.*)\} ]]; then + username=${BASH_REMATCH[1]} + if [[ "job.username" == "$username" ]] ; then + USER=$RD_JOB_USERNAME + fi + + if [[ "option.username" == "$username" ]] ; then + USER=$RD_OPTION_USERNAME + fi +fi + if [[ "privatekey" == "$authentication" ]] ; then #use ssh-keyfile node attribute from env vars diff --git a/contents/ssh-exec.sh b/contents/ssh-exec.sh index 5cd11b9..460eb77 100755 --- a/contents/ssh-exec.sh +++ b/contents/ssh-exec.sh @@ -53,6 +53,18 @@ if [[ -n "${RD_CONFIG_SSH_KEY_PASSPHRASE_OPTION:-}" ]] ; then fi +if [[ "$RD_NODE_USERNAME" =~ \$\{(.*)\} ]]; then + username=${BASH_REMATCH[1]} + if [[ "job.username" == "$username" ]] ; then + USER=$RD_JOB_USERNAME + fi + + if [[ "option.username" == "$username" ]] ; then + USER=$RD_OPTION_USERNAME + fi +fi + + if [[ "privatekey" == "$authentication" ]] ; then #use ssh-keyfile node attribute from env vars