Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to decode a Base64 var to a binary file with Ansible module

I am reading a base64 file from HashiCorp’s vault with the help of the hashi_vault module. Sample of code:

- name: Vault get b64.pfx file
  set_fact:
      b64_pfx: "{{ lookup('hashi_vault',
                    'secret={{ path_pfx }} token={{ token }} url={{ url }} cacert={{ role_path}}/files/CA.pem')}}"

Then as a next step I need to decode this base64 var to a binary format and store it in in a file. I am currently using shell module to do the work. Sample of code:

- name: Decode Base64 file to binary
  shell: "echo {{ b64_pfx }} | base64 --decode > {{ pfxFile }}"
  delegate_to: localhost

I was looking online for possible solutions e.g. ( Copy module with base64-encoded binary file adds extra character and How to upload encrypted file using ansible vault?).

But the only working solution that I can found is using the shell module. Since this is an old problem is there any workaround on this?

Update:

Do not use Python 2.7 as there seems to be a bug on the b64decode filter (sample below):

<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /tmp/ansible-tmp-1573819503.84-50241917358990 `" && echo ansible-tmp-1573819503.84-50241917358990="` echo /tmp/ansible-tmp-1573819503.84-50241917358990 `" ) && sleep 0'
Using module file /usr/lib/python2.7/site-packages/ansible/modules/commands/command.py
<localhost> PUT /tmp/ansible-local-18pweKi1/tmpjQGOz8 TO /tmp/ansible-tmp-1573819503.84-50241917358990/AnsiballZ_command.py
<localhost> EXEC /bin/sh -c 'chmod u+x /tmp/ansible-tmp-1573819503.84-50241917358990/ /tmp/ansible-tmp-1573819503.84-50241917358990/AnsiballZ_command.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /tmp/ansible-tmp-1573819503.84-50241917358990/AnsiballZ_command.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /tmp/ansible-tmp-1573819503.84-50241917358990/ > /dev/null 2>&1 && sleep 0'
changed: [hostname -> localhost] => {
    "changed": true,
    "cmd": "shasum -a 1 /tmp/binary_file\nshasum -a 1 /tmp/binary_file.ansible\n",
    "delta": "0:00:00.126279",
    "end": "2019-11-15 13:05:04.227933",
    "invocation": {
        "module_args": {
            "_raw_params": "shasum -a 1 /tmp/binary_file\nshasum -a 1 /tmp/binary_file.ansible\n",
            "_uses_shell": true,
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": null,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true,
            "warn": true
        }
    },
    "rc": 0,
    "start": "2019-11-15 13:05:04.101654",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "4a71465d449a0337329e76106569e39d6aaa5ef0  /tmp/binary_file\nead5cb632f3ee80ce129ef5fe02396686c2761e0  /tmp/binary_file.ansible",
    "stdout_lines": [
        "4a71465d449a0337329e76106569e39d6aaa5ef0  /tmp/binary_file",
        "ead5cb632f3ee80ce129ef5fe02396686c2761e0  /tmp/binary_file.ansible"
    ]
}

Solution: use Python 3 with b64decode filter (sample below):

<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /tmp/ansible-tmp-1573819490.9511943-224511378311227 `" && echo ansible-tmp-1573819490.9511943-224511378311227="` echo /tmp/ansible-tmp-1573819490.9511943-224511378311227 `" ) && sleep 0'
Using module file /usr/local/lib/python3.6/site-packages/ansible/modules/commands/command.py
<localhost> PUT /tmp/ansible-local-18epk_0jsv/tmp4t3gnm7u TO /tmp/ansible-tmp-1573819490.9511943-224511378311227/AnsiballZ_command.py
<localhost> EXEC /bin/sh -c 'chmod u+x /tmp/ansible-tmp-1573819490.9511943-224511378311227/ /tmp/ansible-tmp-1573819490.9511943-224511378311227/AnsiballZ_command.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /tmp/ansible-tmp-1573819490.9511943-224511378311227/AnsiballZ_command.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /tmp/ansible-tmp-1573819490.9511943-224511378311227/ > /dev/null 2>&1 && sleep 0'
changed: [hostname -> localhost] => {
    "changed": true,
    "cmd": "shasum -a 1 /tmp/binary_file\nshasum -a 1 /tmp/binary_file.ansible\n",
    "delta": "0:00:00.135427",
    "end": "2019-11-15 13:04:51.239969",
    "invocation": {
        "module_args": {
            "_raw_params": "shasum -a 1 /tmp/binary_file\nshasum -a 1 /tmp/binary_file.ansible\n",
            "_uses_shell": true,
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": null,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true,
            "warn": true
        }
    },
    "rc": 0,
    "start": "2019-11-15 13:04:51.104542",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "4a71465d449a0337329e76106569e39d6aaa5ef0  /tmp/binary_file\n4a71465d449a0337329e76106569e39d6aaa5ef0  /tmp/binary_file.ansible",
    "stdout_lines": [
        "4a71465d449a0337329e76106569e39d6aaa5ef0  /tmp/binary_file",
        "4a71465d449a0337329e76106569e39d6aaa5ef0  /tmp/binary_file.ansible"
    ]
}

Since Python 2 is reaching the end of life in (January 1, 2020) there is no point of raising the bug.

like image 751
Thanos Avatar asked Nov 13 '19 15:11

Thanos


People also ask

How do I decode a Base64 encoded file?

To decode a file with contents that are base64 encoded, you simply provide the path of the file with the --decode flag. As with encoding files, the output will be a very long string of the original file. You may want to output stdout directly to a file.

Can browser decode Base64?

Encoding and Decoding Strings with Base64 btoa() and atob() are two Base64 helper functions that are a core part of the HTML specification and available in all modern browsers.


1 Answers

Using the b64decode filter at least on ansible 2.9 does what you want:

- copy:
    dest: '{{ pfxFile }}'
    content: '{{ b64_pfx | b64decode }}'
  delegate_to: localhost

I confirmed it writes only the specified bytes (no trailing whitespace) and is binary safe.

If you tried that behavior, and it doesn't work for you, then update your question to say that and to include the version of ansible you are using. I also think that bug you linked to has been fixed, because I tried their exact case on ansible 2.9 and it did the right thing:

- hosts: localhost
  connection: local
  gather_facts: no
  tasks:
  - set_fact:
      string_in_base64: 'sxZARwIVokeqOMGPygc1S20CaGPiKDRGRzg0oSVGmCF2oXHua+9fVhriUQRd8vkmvpHoBmSsI6Y='
  - copy:
      dest: binary_file.ansible
      content: '{{ string_in_base64 | b64decode }}'
  - shell: |
      echo '{{ string_in_base64 }}' | base64 --decode > binary_file
      shasum -a 1 binary_file
      shasum -a 1 binary_file.ansible
{
  "changed": true,
  "cmd": "echo 'sxZARwIVokeqOMGPygc1S20CaGPiKDRGRzg0oSVGmCF2oXHua+9fVhriUQRd8vkmvpHoBmSsI6Y=' | base64 --decode > binary_file\nshasum -a 1 binary_file\nshasum -a 1 binary_file.ansible\n",
  "delta": "0:00:00.162251",
  "end": "2019-11-13 13:10:56.683186",
  "rc": 0,
  "start": "2019-11-13 13:10:56.520935",
  "stderr": "",
  "stderr_lines": [],
  "stdout": "7e88df04cf47019ae22e9c658b62c26b706c6ea5  binary_file\n7e88df04cf47019ae22e9c658b62c26b706c6ea5  binary_file.ansible",
  "stdout_lines": [
    "7e88df04cf47019ae22e9c658b62c26b706c6ea5  binary_file",
    "7e88df04cf47019ae22e9c658b62c26b706c6ea5  binary_file.ansible"
  ]
}
like image 60
mdaniel Avatar answered Oct 18 '22 17:10

mdaniel