From 9b49494f9533d10c14ab16e018b6a7af7376c801 Mon Sep 17 00:00:00 2001 From: jaisejose1123 Date: Thu, 13 Jun 2024 15:43:37 +0530 Subject: [PATCH] Fixed encrypted playbook not running issue --- lib/ansible/runner.rb | 28 ++++++++++++- .../data/hello_world_vault_encrypted.yml | 41 +++++++++++++++++++ spec/lib/ansible/runner/data/password.yml | 1 + spec/lib/ansible/runner_execution_spec.rb | 6 +++ 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 spec/lib/ansible/runner/data/hello_world_vault_encrypted.yml create mode 100644 spec/lib/ansible/runner/data/password.yml diff --git a/lib/ansible/runner.rb b/lib/ansible/runner.rb index b305c93e721..2360d2057de 100644 --- a/lib/ansible/runner.rb +++ b/lib/ansible/runner.rb @@ -79,6 +79,18 @@ def run(env_vars, extra_vars, playbook_path, tags: nil, hosts: ["localhost"], cr :become_enabled => become_enabled) end + def run_vault(env_vars, extra_vars, playbook_path, tags: nil, hosts: ["localhost"], credentials: [], verbosity: 0, become_enabled: false) + run_via_cli(hosts, + credentials, + env_vars, + extra_vars, + :tags => tags, + :playbook => playbook_path, + :test_vault => true, + :verbosity => verbosity, + :become_enabled => become_enabled) + end + # Runs a role directly via ansible-runner, a simple playbook is then automatically created, # see: https://ansible-runner.readthedocs.io/en/latest/standalone.html#running-roles-directly # @@ -194,7 +206,7 @@ def run_in_queue(method_name, user_id, queue_opts, args) # @param verbosity [Integer] ansible-runner verbosity level 0-5 # @param playbook_or_role_args [Hash] Hash that includes the :playbook key or :role keys # @return [Ansible::Runner::Response] Response object with all details about the ansible run - def run_via_cli(hosts, credentials, env_vars, extra_vars, tags: nil, ansible_runner_method: "run", verbosity: 0, become_enabled: false, **playbook_or_role_args) + def run_via_cli(hosts, credentials, env_vars, extra_vars, tags: nil, ansible_runner_method: "run", test_vault: false, verbosity: 0, become_enabled: false, **playbook_or_role_args) # If we are running against only localhost and no other value is set for ansible_connection # then assume we don't want to ssh locally extra_vars["ansible_connection"] ||= "local" if hosts == ["localhost"] @@ -204,7 +216,13 @@ def run_via_cli(hosts, credentials, env_vars, extra_vars, tags: nil, ansible_run base_dir = Pathname.new(Dir.mktmpdir("ansible-runner")).realpath debug = verbosity.to_i >= 5 || env_vars["ANSIBLE_KEEP_REMOTE_FILES"] - cred_command_line, cred_env_vars, cred_extra_vars = credentials_info(credentials, base_dir) + if test_vault + cred_command_line = {} + cred_extra_vars = {} + cred_env_vars = {"ANSIBLE_VAULT_PASSWORD_FILE" => File.join(File.dirname(playbook_or_role_args[:playbook]), "password.yml")} + else + cred_command_line, cred_env_vars, cred_extra_vars = credentials_info(credentials, base_dir) + end command_line_hash = tags.present? ? {:tags => tags} : {} if become_enabled @@ -231,6 +249,12 @@ def run_via_cli(hosts, credentials, env_vars, extra_vars, tags: nil, ansible_run end res = response(base_dir, ansible_runner_method, result, debug) + if !cred_env_vars.empty? + command_line = res.instance_variable_get(:@command_line) + new_command = "export #{cred_env_vars['ANSIBLE_VAULT_PASSWORD_FILE']} ; #{command_line}" + res.instance_variable_set(:@command_line, new_command) + end + res ensure # Clean up the tmp dir for the sync method, for async we will clean it up after the job is finished and we've # read the output, that will be written into this directory. diff --git a/spec/lib/ansible/runner/data/hello_world_vault_encrypted.yml b/spec/lib/ansible/runner/data/hello_world_vault_encrypted.yml new file mode 100644 index 00000000000..47ec68fbb1e --- /dev/null +++ b/spec/lib/ansible/runner/data/hello_world_vault_encrypted.yml @@ -0,0 +1,41 @@ +# Note: The password for `encrypted_msg` is just 'vault' +# +# This playbook is just used for testing vault integration, so when provided +# with the correct password the message displayed should be: +# +# "Hello World! (NOTE: This message has been encrypted with ansible-vault)" +# +# This var was generated by running the following: +# +# $ ansible-vault encrypt_string --ask-vault-pass --stdin-name "encrypted_msg" +# New Vault password: +# Confirm New Vault password: +# Reading plaintext input from stdin. (ctrl-d to end input) +# Hello World! +# encrypted_msg: !vault | +# $ANSIBLE_VAULT;1.1;AES256 +# 66383635373066393337333631383930366166656134653935663164636636623239333861643936 +# 3664613065666439303135323331616666383030383839310a303461623264646233623037313363 +# 63626562616166353466366232363562353461366162396262363461666439386165663565643832 +# 3239396633396466630a616463393237303338633562656664653433633437383161353933303737 +# 3764 +# Encryption successful +# +# (NOTE: When running the above, Ctrl-D was required twice for `ansible-vault` +# to respond. Most likely due to the '!' character in the base string.) +# +- name: Hello World Sample (Vault Encrypted) + hosts: localhost + vars: + encrypted_msg: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 66383635373066393337333631383930366166656134653935663164636636623239333861643936 + 3664613065666439303135323331616666383030383839310a303461623264646233623037313363 + 63626562616166353466366232363562353461366162396262363461666439386165663565643832 + 3239396633396466630a616463393237303338633562656664653433633437383161353933303737 + 3764 + tasks: + - name: Hello Message + debug: + msg: "{{encrypted_msg}} (NOTE: This message has been encrypted with ansible-vault)" + diff --git a/spec/lib/ansible/runner/data/password.yml b/spec/lib/ansible/runner/data/password.yml new file mode 100644 index 00000000000..3bf0753e0a7 --- /dev/null +++ b/spec/lib/ansible/runner/data/password.yml @@ -0,0 +1 @@ +vault \ No newline at end of file diff --git a/spec/lib/ansible/runner_execution_spec.rb b/spec/lib/ansible/runner_execution_spec.rb index a1e4a8de0d5..8c640adfb0c 100644 --- a/spec/lib/ansible/runner_execution_spec.rb +++ b/spec/lib/ansible/runner_execution_spec.rb @@ -13,5 +13,11 @@ expect(response.return_code).to eq(0), "ansible-runner failed with:\n#{response.stderr}" expect(response.human_stdout).to include('"msg": "Hello, world!"') end + it "runs a hello-world-vault-encrypted playbook" do + response = Ansible::Runner.run_vault(env_vars, extra_vars, File.join(__dir__, "runner/data/hello_world_vault_encrypted.yml")) + + expect(response.return_code).to eq(0), "ansible-runner failed with:\n#{response.stderr}" + expect(response.human_stdout).to include('"msg": "Hello World! (NOTE: This message has been encrypted with ansible-vault)"') + end end end