Назад | Перейти на главную страницу

Управление /etc/security/access.conf с помощью ansible

Впервые в Ansible и у вас есть несколько машин, которые используют pam_access модуль, который настроен в /etc/security/access.conf. Несколько строк, указывающих РАЗРЕШЕНИЕ / ЗАПРЕТ (+/-), а затем либо пользователей, либо группы вместе с IP-адресами src для сопоставления.

Какой более чистый способ управлять этим файлом в Ansible?

Файл /etc/security/access.conf выглядит примерно так:

+ : root     : cron crond :0 ttyS0 tty1 tty2 tty3 tty4 tty5 tty6
+ : root     : 10.137.198.176
+ : inventory: 10.137.198.25
+ : sysadmin : 10.137.198.202
- : ALL : ALL

Большинство машин будут использовать этот базовый ACL, а затем при необходимости могут быть добавлены другие группы или пользователи. Веб-разработчики входят в систему через SFTP на двух веб-серверах, поэтому ACL будет вставлен для этой группы (перед - : ALL : ALL строка) вот так:

+ : webdev   : 10.137.198.0/24
- : ALL : ALL

Некоторые веб-серверы также запускают passenger. Разработчики этих систем выдвигают код как passenger user, поэтому этому пользователю разрешено использовать локальную сеть разработчика, но не на всех веб-серверах.

+ : passenger: 10.137.197.0/24
- : ALL : ALL

Правила становятся довольно специфичными для каждой машины, и я не вижу простого способа управления этим файлом. Я начал с playbook и group_vars ниже, которые работают, но для того, чтобы иметь несколько определений для одной и той же машины, нужна помощь. Возможно определение массива для line: в playbook необходимо и разбираться в этом.

Кроме того, эта модель потребовала бы перезаписи файла каждый раз после удаления хоста из group_vars не удаляет запись из access.conf. Единственные состояния для lineinfile являются absent или present. Мне нужно состояние под названием add_line_if_missing_remove_if_absent_from_vars. Есть ли способ лучше?


- hosts: all
  vars_files:
    - ../group_vars/test-etc-security-access-conf.yml
  gather_facts: false

  tasks:
    - name: "Set up /etc/security/access.conf for {{ inventory_hostname }}"
      when: inventory_hostname is match (item.name)
      lineinfile:
        dest  : /tmp/access.conf
        regexp: '{{ item.regexp }}'
        line: '{{ item.line }}'
      with_items: "{{ access_rules }}"

group_vars - должно быть лучше:

access_rules:
  - name: 10.137.1.66
    regexp: '.*passenger.*'
    line: '+ : passenger : 10.137.10.0/24'

  - name: 10.137.1.66
    regexp: '.*webdev.*'
    line: '+ : webdev : 10.137.198.0/24'

Это то, что я в итоге использовал. Может быть кому нибудь будет полезно. Плейбук применит базовый ACL к каждому хосту, а затем будет искать дополнительный ACL в каталоге. {{ acl_dir }} с именем текущего подготавливаемого хоста. Если он существует, он применяется. Наконец, правило запрета по умолчанию добавляется последним.

Я подумал, что было бы неплохо иметь комментарий в начале файла, когда он последний раз обновлялся. gather_facts добавляет много времени выполнения, поэтому выбрал shell: команда, чтобы вместо этого получить дату.

---
- hosts: all
  vars:
    dest_file: /etc/security/access.conf
    base_acl : base
    acl_dir  : ../group_vars/pam_access
  gather_facts: false

  tasks:
    - name: "Empty existing ACL and replace with base ACL"
      copy:
        content: ""
        dest   : "{{ dest_file }}"
        owner  : root
        group  : root
        mode   : 0644

    - name: "Get current date from shell rather than wait for gather_facts"
      shell: date '+%Y-%m-%d'
      register: date_now

    - name: "Add ansible header with modified date to beginning of file"
      copy:
        content: "# updated via ansible on {{ date_now.stdout }} by {{ lookup ('env', 'LOGNAME') }}"
        dest: "{{ dest_file }}"
        owner  : root
        group  : root
        mode   : 0644

    - name: "Add base ACL {{ acl_dir }}/base to {{ inventory_hostname }}"
      lineinfile:
        dest: "{{ dest_file }}"
        line: "{{ lookup ('file', '{{ acl_dir }}/{{ base_acl }}') }}"

    - name: "Check for additional ACL {{ acl_dir }}/{{ inventory_hostname }}..."
      stat:
        path  : "{{ acl_dir }}/{{ inventory_hostname }}"
      register: host_acl

    - name: "Add host specific ACL from {{ acl_dir }}/{{ inventory_hostname }}"
      when: host_acl.stat.exists
      lineinfile:
        dest: "{{ dest_file }}"
        line: "{{ lookup ('file', '{{ acl_dir }}/{{ inventory_hostname }}') }}"

    - name: "Add default DENY as last ACL as a security precaution"
      lineinfile:
        dest: "{{ dest_file }}"
        line: "- : ALL : ALL"

базовый ACL:

+ : root     : cron crond :0 ttyS0 tty1 tty2 tty3 tty4 tty5 tty6
+ : root     : 10.137.198.176
+ : inventory: 10.137.198.25
+ : sysadmin : 10.137.198.202

дополнительный ACL хоста с именем websrv01.mydom.com:

+ : webdev   : 10.137.198.0/24
+ : passenger: 10.137.197.0/24