Get command error output

Hello guys,

I’m trying to manually configure the SSL certificate for the API of my proxmox servers.
Since I had a lot of error, I find a way using the command openssl s_client -connect which returns me a very big output and the certificate I need.
I made a topic for it.

I just need Ansible to get the output of the command on a file, using some REGEX I could get the SSL certificate and update my ca-certificates.crt file.

There’s the Playbook I’ve tried:

- name: Fetch certificate from output
  hosts: PROXMOX
  become: true
  tasks:
    - name: Run command to fetch certificate
      ansible.builtin.command: "openssl s_client -connect 172.16.20.11:8006"
      register: certificate_output
      changed_when: true # With and without this option, also tried a "ignore_errors: true"

    - name: Extract certificate content
      ansible.builtin.set_fact:
        certificate_content: "{{ certificate_output.stdout | regex_search('(?<=-----BEGIN CERTIFICATE-----)(.*?)(?=-----END CERTIFICATE-----)', multiline=True) | first }}"

    - name: Save certificate content to file
      ansible.builtin.copy:
        content: "{{ certificate_content }}"
        dest: /usr/local/share/ca-certificates/lets-encrypt.crt
        owner: root
        group: root
        mode: '0644'

I can provide you the output, but as I said, it is VERY long…
This is the beginning of the error when running the playbook:

TASK [Run command to fetch certificate] ********************************************************************************************************************************************************************
fatal: [172.16.20.11]: FAILED! => {"changed": true, "cmd": ["openssl", "s_client", "-connect", "172.16.20.11:8006"], "delta": "0:00:05.073686", "end": "2024-03-08 15:53:12.865630", "msg": "non-zero return code", "rc": 1, "start": "2024-03-08 15:53:07.791944", "stderr":

Regards

It may be long, but it will contain information necessary to further diagnose what’s wrong. As it is, all we know is the openssl s_client command returned a non-zero return code.

The way I typically get a certificate from a server would look like this (slightly untested tested!):

- name: Run openssl pipeline to fetch certificate
  ansible.builtin.shell: |
    set -o pipefail
    echo | openssl s_client -connect 172.16.20.11:8006 | openssl x509
  register: certificate_output
  when: true           # because we always want to run it
  changed_when: false  # because it doesn't change anything

You can then skip the set_fact, because certificate_output.stdout will only contain the certificate in the format you need. Use that instead of certificate_content in your copy task.

However, whatever is currently breaking your command: task may well break the above shell: task, so we may need to see that long output in any case.

Hello,

Thank you :slight_smile:, I don’t know why but the problem seams to be solved by using the ansible.builtin.shell instead of the ansible.builtin.command.
Also, my shell seams to not support the pipefail option:

"stderr": "/bin/sh: 1: set: Illegal option -o pipefail",
    "stderr_lines": [
        "/bin/sh: 1: set: Illegal option -o pipefail"
    ],

there’s my playbook:

- name: Run command to fetch certificate
  ansible.builtin.shell: |
    echo | openssl s_client -connect 172.16.20.11:8006 | openssl x509
  register: certificate_output
  when: true
  changed_when: false

- name: Save certificate content to file
  ansible.builtin.copy:
    content: "{{ certificate_output }}"
    dest: /usr/local/share/ca-certificates/lets-encrypt.crt
    owner: root
    group: root
    mode: '0644'

Regards

WRT the pipefail issue: Older bash (like 4.2.46; I don’t know what version this changed) doesn’t support pipefail when run as /bin/sh. Later versions of bash will support set -o pipefail even when invoked as sh. On many systems, sh is a symbolic link to bash, so even though ansible.builtin.shell is invoking /bin/sh, it’s really bash underneath trying to emulate the POSIX shell sh.

Although ansible.builtin.shell uses /bin/sh by default. You can make it run /bin/bash instead like below, so you can still set the pipefail option on systems with an older bash:

- name: Run /bin/bash instead of /bin/sh
  ansible.builtin.shell: |
    set -o pipefail
    echo $BASH_VERSION
  args:
    executable: /bin/bash
1 Like

Hello,

Well, even if I saw a way to change the executable I did not try, what I was doing when needed was only something like:

- name: some command with bash
      ansible.builtin.command: "/usr/sbin/[the_command]"

I just tried by changing the executable and it worked, thank you.

Just to let you know:

echo $BASH_VERSION
5.2.15(1)-release

So I really don’t know why my system don’t want the set pipefail option haha…

Regards

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.