listdictionaryansiblesudoersjson-query

Ansible - remove user from group x if already in other group


I am looking for the easiest way to remove users from group x when they are already in group google-sudo. I store users in group vars in this kind of list and dictionary combination:

user_account:
  - name: jenny
    authorized_keys:
      - jenny_01
    groups:
      - "{% if not googlesudo.stat.exists %}sudo{% else %}google-sudo{% endif %}"

  - name: jerry
    authorized_keys:
      - jerry_01
    groups: 
      - "{% if not googlesudo.stat.exists %}sudo{% else %}google-sudo{% endif %}"
...

These are tasks I already created:

- name: Check if google-sudo file exists
  stat:
    path: /etc/sudoers.d/google_sudo
  register: googlesudo
  tags:
    - add_user_group
    - remove_from_x

- debug: var=googlesudo verbosity=2
  tags:
    - add_user_group
    - remove_from_x

- debug:
    msg: "User account to create: {{ item.name }}"
  with_items: "{{ user_account }}"

- name: "Creating user"
  user:
    name: "{{ item.name }}"
    group: users
    shell: /bin/bash
  with_items: "{{ user_account }}"

- name: Add user to additional groups
  user:
    name: "{{ item.0.name }}"
    groups: "{{ item.1 }}"
    append: yes
  with_subelements:
    - "{{ user_account }}"
    - groups
  tags:
    - remove_from_x

- name: Check if user already in google-sudo
  command: "groups {{ item.name }}"
  with_items:
    - "{{ user_account }}"
  register: root_users
  tags:
    - remove_from_x

- name: View root users
  debug:
    msg: "{{ item }}"
    verbosity: 2
  with_items:
    - "{{ root_users }}"
  tags:
    - remove_from_x

- name: Save state
  set_fact:
    is_in_googlesudo: "{{ root_users.results.0.stdout_lines }}"
  tags:
     - remove_from_x

- name: List
  debug: msg='{{ user_account |json_query("[?groups==`google-sudo`]")}}'
  tags:
    - remove_from_x

- name: Remove from x group
  shell: "deluser {{ item.name }} x"
  with_items:
    - "{{ user_account }}"
  when: "'x in is_in_googlesudo' and 'google-sudo in is_in_googlesudo'"
  tags:
    - remove_from_x

I was testing json_query to extract user name if he is in google-sudo and x group, but without success. Tried to list users when group is defined, however I get empty output, using this:

msg='{{ user_account |json_query("[?groups==`google-sudo`]")}}'

I wonder if is there any shorter way to remove users from group x after checking on server (using eg. groups command) or in user_account -> group if he's already in google-sudo.

Probably there is some nice and elegant way to write this code, I will appreciate any ideas how to deal with it.


Solution

  • Let's simplify the data, e.g.

      vars:
        my_group: "{{ googlesudo.stat.exists|ternary('google-sudo', 'sudo') }}"
        user_account:
          - name: jenny
            groups: "{{ my_group }}"
          - name: jerry
            groups: "{{ my_group }}"
    

    The code works as expected, e.g.

        - stat:
            path: /tmp/google_sudo
          register: googlesudo
        - debug:
            var: user_account
        - debug:
            msg: '{{ user_account|json_query("[?groups==`google-sudo`].name") }}'
    

    gives if /tmp/google_sudo exists

      user_account:
      - groups: google-sudo
        name: jenny
      - groups: google-sudo
        name: jerry
    
      msg:
      - jenny
      - jerry
    

    otherwise

      user_account:
      - groups: sudo
        name: jenny
      - groups: sudo
        name: jerry
    
      msg: []
    

    Q: "Remove user from group x if already in another group."

    A: Use getent to get the list of users in a group. For example, to list users in the group sudo

        - getent:
            database: group
        - debug:
            var: getent_group.sudo.2
    

    Test action if a user is a member of the group sudo, e.g.

        - debug:
            msg: "Remove user {{ item.name }} from group x"
          loop: "{{ user_account }}"
          when: item.name in getent_group.sudo.2
    

    Q: "Have groups as a list. (Probably I should use contains function.)"

    A: Yes. Use contains, e.g given the lists

      vars:
        user_account:
          - name: jenny
            groups: [google-sudo, group2]
          - name: jerry
            groups: [google-sudo, group3]
    

    the task

        - debug:
            msg: "{{ user_account|json_query('[?contains(groups, `group2`)].name') }}"
    

    gives

      msg:
      - jenny