anthcourtney / ansible-role-cis-amazon-linux

Ansible role to apply CIS Amazon Linux Benchmark v2.0.0
MIT License
154 stars 140 forks source link

6.2.6 ignores nonexistent directory in root's PATH #68

Open arronax opened 4 years ago

arronax commented 4 years ago

Root's PATH in Amazon Linux (and CentOS, and likely other similar distributions) by default has /root/bin in it, which doesn't exist:

[root@ip-192-168-3-209 ~]# env | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@ip-192-168-3-209 ~]# ls -ld /root/bin
ls: cannot access /root/bin: No such file or directory

That should trigger an action in item 6.2.6, but it skips over. Looks like ansible's script module doesn't set environment as it's expected in the role.

PLAY [ip-192-168-3-209] ***************************************************************************

TASK [6.2.6 - Audit root PATH Integrity] **********************************************************
ok: [ip-192-168-3-209]

TASK [6.2.6 - Ensure root PATH Integrity] *********************************************************
skipping: [ip-192-168-3-209]

TASK [6.2.6 - Ensure root PATH Integrity] *********************************************************
skipping: [ip-192-168-3-209]

PLAY RECAP ****************************************************************************************
ip-192-168-3-209           : ok=1    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0

Running audit_6.2.6.sh directly on the hosts provides expected results.

[root@ip-192-168-3-209 ~]# /tmp/audit_6.2.6.sh
/root/bin is not a directory
chandanchowdhury commented 4 years ago

Hi Sergey (@arronax), thanks a lot for creating the issue and submitting the pull request.

This is a tricky situation.

Quick question, have you thought about trying to run the script as sudo and see if that works?

arronax commented 4 years ago

I think, the reason for all of this is the different invocation of bash. I'll check this, but it appears that ansible's script gets interactive non-login shell, while we need login shell in order to get full env present.

Quoting man bash

When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for _~/.bashprofile, _~/.bashlogin, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior.

Behavior can be shown using ssh or sudo.

$ sudo /tmp/audit_6.2.6.sh
$ sudo bash /tmp/audit_6.2.6.sh
$ sudo bash -l /tmp/audit_6.2.6.sh
/root/bin is not a directory
$ ssh -q ip-192-168-3-209 "/tmp/audit_6.2.6.sh"
$ ssh -q ip-192-168-3-209 "bash /tmp/audit_6.2.6.sh"
$ ssh -q ip-192-168-3-209 "bash -l /tmp/audit_6.2.6.sh"
/home/ec2-user/.local/bin is not a directory
/home/ec2-user/bin is not a directory

Better yet, it can be shown directly through PATH (script has single env | grep PATH line)

$ sudo /tmp/env-path.sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
$ sudo bash /tmp/env-path.sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
$ sudo bash -l /tmp/env-path.sh
PATH=/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
arronax commented 4 years ago

Some trivial testing through ansible.

$ cat env.sh
#!/bin/bash
env | grep PATH
  tasks:
    - name: Copy test script to the remote machine
      copy:
        src: env.sh
        dest: /tmp/env.sh
        mode: 0700

    - name: Get environment using `script`
      script: env.sh
      register: script_out

    - name: debug print output
      debug:
        msg: "{{ script_out.stdout }}"

    - name: Get environment using `script` and do become
      script: env.sh
      become: yes
      register: script_become_out

    - name: debug print output
      debug:
        msg: "{{ script_become_out.stdout }}"

    - name: Get environment using `command`
      command: /tmp/env.sh
      register: command_out

    - name: debug print output
      debug:
        msg: "{{ command_out.stdout }}"

    - name: Get environment using `command` and do become
      command: /tmp/env.sh
      become: yes
      register: command_become_out

    - name: debug print output
      debug:
        msg: "{{ command_become_out.stdout }}"

    - name: Get environment using `shell`
      shell: /tmp/env.sh
      register: shell_out

    - name: debug print output
      debug:
        msg: "{{ shell_out.stdout }}"

    - name: Get environment using `shell` and do become
      shell: /tmp/env.sh
      become: yes
      register: shell_become_out

    - name: debug print output
      debug:
        msg: "{{ shell_become_out.stdout }}"

    - name: Get environment using `command` with bash invocation
      command: bash /tmp/env.sh
      register: command_bash_out

    - name: debug print output
      debug:
        msg: "{{ command_bash_out.stdout }}"

    - name: Get environment using `command` with bash invocation and do become
      command: /tmp/env.sh
      become: yes
      register: command_become_bash_out

    - name: debug print output
      debug:
        msg: "{{ command_become_bash_out.stdout }}"

    - name: Get environment using `command` with bash login invocation
      command: bash -l /tmp/env.sh
      register: command_bash_login_out

    - name: debug print output
      debug:
        msg: "{{ command_bash_login_out.stdout }}"

    - name: Get environment using `command` with bash login invocation and do become
      command: bash -l /tmp/env.sh
      become: yes
      register: command_become_bash_login_out

    - name: debug print output
      debug:
        msg: "{{ command_become_bash_login_out.stdout }}"
PLAY [ip-192-168-3-209] ******************************************************************************************

TASK [Copy test script to the remote machine] ********************************************************************
ok: [ip-192-168-3-209]

TASK [Get environment using `script`] ****************************************************************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/usr/local/bin:/usr/bin\r\n"
}

TASK [Get environment using `script` and do become] **************************************************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/sbin:/bin:/usr/sbin:/usr/bin\r\n"
}

TASK [Get environment using `command`] ***************************************************************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/usr/local/bin:/usr/bin"
}

TASK [Get environment using `command` and do become] *************************************************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/sbin:/bin:/usr/sbin:/usr/bin"
}

TASK [Get environment using `shell`] *****************************************************************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/usr/local/bin:/usr/bin"
}

TASK [Get environment using `shell` and do become] ***************************************************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/sbin:/bin:/usr/sbin:/usr/bin"
}

TASK [Get environment using `command` with bash invocation] ******************************************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/usr/local/bin:/usr/bin"
}

TASK [Get environment using `command` with bash invocation and do become] ****************************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/sbin:/bin:/usr/sbin:/usr/bin"
}

TASK [Get environment using `command` with bash login invocation] ************************************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/ec2-user/.local/bin:/home/ec2-user/bin"
}

TASK [Get environment using `command` with bash login invocation and do become] **********************************
changed: [ip-192-168-3-209]

TASK [debug print output] ****************************************************************************************
ok: [ip-192-168-3-209] => {
    "msg": "PATH=/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"
}

PLAY RECAP *******************************************************************************************************
ip-192-168-3-209           : ok=21   changed=10   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
arronax commented 4 years ago

I do not think that ansible will support login shells any time soon, and I am personally not sure that's required, as there are workarounds available. Environment variables and scripts are sometimes tricky, and can break whatever ansible is running.

Some ansible team answers to the related issues.

https://github.com/ansible/ansible/issues/4854#issuecomment-37657751 https://github.com/ansible/ansible/issues/29637#issuecomment-380672737

chandanchowdhury commented 4 years ago

Thanks again @arronax for doing all the research and hardwork.

One tiny request. Could you please send the pull request to build instead of master. We are trying to follow this approach so to allow others to test run build and report any bugs they find before we merge the changes in master which will become prodcuction version.

chandanchowdhury commented 4 years ago

@arronax Please ignore the request, was able to modify the PR to pull into build