【问题标题】:Ansible: insert a single word on an existing line in a fileAnsible:在文件的现有行上插入一个单词
【发布时间】:2015-10-04 14:38:00
【问题描述】:

我必须使用 Ansible 模块来编辑 /etc/ssh/sshd_config 文件 - 每次创建新用户时,我都想将其附加到这两行:

AllowUsers root osadmin <new_user>
AllowGroups root staff <new_group>

此时我正在使用 shell 模块执行 sed 命令,但如果可能的话,我想使用 lineinfile

- shell: "sed -i '/^Allow/ s/$/ {{ user_name }}/' /etc/ssh/sshd_config"

任何建议将不胜感激。

【问题讨论】:

  • 在此类文件中使用sed -i 是危险的。至少,使用-i.bak 进行备份以防万一。
  • 我不想使用 sed,如果可能的话我想用 lineinfile 模块替换它
  • lineinfile 通常是一种反模式——在这种情况下,您可能希望将 sshd_config 文件带入配置管理中。
  • tedder42 在这个问题上似乎特别固执己见,因为我看到他在其他帖子上对lineinfile 的使用发表了同样的评论。真的,这是适合您的情况的问题。如果它符合您的目的,请不要犹豫使用 lineinfile。在模板中管理所有 sshd_config 可能没有意义。
  • 请注意,sshd中可以多次设置AllowUsers,不需要将所有用户放在同一行。

标签: ansible sshd


【解决方案1】:

所选答案假定完整的用户列表在运行时可用,而当用户名中有破折号时,最受欢迎的答案可能会失败,因为\b 将其解释为单词边界。以下解决方案假设 playbook 无法从头开始重新生成完整的用户名列表,并尝试处理破折号的极端情况:

name: add a user to the list of AllowUsers if not present
lineinfile:
  path: /etc/ssh/sshd_config
  backrefs: yes
  backup: yes
  regexp: "^AllowUsers((?:(?:\s+\S+(?!\S))(?<!\s{{ username }}))+\s*?)(\n?)$"
  line: "AllowUsers\1 {{ username }}\2"
  validate: /usr/sbin/sshd -t -f %s

作为奖励,我加入了 sshd_config 备份和验证。

正则表达式(有趣的部分)是如何工作的:

--------------------------+----------------------------------------------------
(                         |
--------------------------+----------------------------------------------------
  (?:                     | This group is not captured
--------------------------+----------------------------------------------------
    (?:\s+\S+(?!\S))      | Matches any sequence of whitespace characters fol-
                          | lowed by any sequence of non-whitespace characters,
                          | that is to say a leading space and a username. The
                          | negative look-ahead at the end prevents a "catast-
                          | rophic backtracking". Also, this group is not cap-
                          | tured.
--------------------------+----------------------------------------------------
    (?<!\s{{ username }}) | Applies a negative look-behind on the username, so
                          | that if the username found by the previous expres-
                          | sion matches, the regular expression fails. The
                          | match on a leading whitespace character ensures
                          | that the comparison is made on the complete string.
--------------------------+----------------------------------------------------
  )+                      | Groups the detection of a username and its negative
                          | look-behind together. The "+" quantifier is used
                          | here on the assumption that the file already cont-
                          | ains at least one username, but "*" could be used
                          | for a more relaxed matching.
--------------------------+----------------------------------------------------
  \s*?                    | Matches any trailing whitespace. The match is lazy
                          | in order to detect the newline character later on.
--------------------------+----------------------------------------------------
)                         | Captures the whole text after "AllowUsers" (this
                          | will be \1).
--------------------------+----------------------------------------------------
(\n?)                     | Captures either a newline character or an empty
                          | string (this will be \2).
--------------------------+----------------------------------------------------

如果正则表达式匹配,则表示该行存在且不包含{{ username }},所以我们追加它。

如果正则表达式不匹配,则表示该行不存在或包含{{ username }},我们什么也不做。

【讨论】:

  • yamllint 讨厌 (?:\s+\S+(?!\S)) 中的第一个 \s
  • @Electrawn 对不起,我不知道为什么会这样。这可能是因为验证正则表达式(尤其是这样一个复杂的表达式)很难,或者因为我使用了双引号而我不应该这样做?我无法再访问我的设置,因此无法轻松测试。
【解决方案2】:

我遇到了同样的问题。我需要将用户添加到 sudoers 组,让我们说 'testuser' 到行:

User_Alias SOMEADMIN = smoeuser1, someuser2, someuser3

这对我很有效:

- name: add testuser to end of line
      lineinfile:
        dest: /etc/sudoers.d/somegroup
        state: present
        regexp: '^(User_Alias(.*)$)'
        backrefs: yes
        line: '\1, testuser'

关键是,如果我在正则表达式中有 '^User_Alias(..)$'* 而不是 '^(User_Alias(..)$)'*它没有用,整条线都被替换了。使用 () 包围搜索文本,结果还可以:

User_Alias SOMEADMIN = smoeuser1, someuser2, someuser3, testuser

那么任何东西都可以在 line: 中工作,包括诸如 "{{ usernames | join(', ') }}"

之类的 ansible 变量

【讨论】:

    【解决方案3】:

    这对我有用

     - name: Add Group to AllowGroups
       lineinfile: 
         dest=/etc/ssh/sshd_config
         backup=True
         backrefs=True
         state=present
         regexp='^(AllowGroups(?!.*\b{{ groupname }}\b).*)$'
         line='\1 {{ groupname }}'
    

    【讨论】:

      【解决方案4】:

      replace module 将替换文件中正则表达式模式的所有实例。编写一个任务来匹配AllowUsers 行并将其替换为附加用户名的原始行。为了确保任务是幂等的,正则表达式中的否定前瞻断言检查用户名是否已经出现在行中。例如:

      - name: Add user to AllowUsers
        replace:
          backup: yes
          dest: /etc/ssh/sshd_config
          regexp: '^(AllowUsers(?!.*\b{{ user_name }}\b).*)$'
          replace: '\1 {{ user_name }}'
      

      【讨论】:

      • 如果您使用backrefs: yes,则此答案中的正则表达式也适用于lineinfile。我一直在努力解决这个问题,直到我找到了这个正则表达式 - 结果我缺少的秘诀是\b
      • 谁能解释一下\1是什么?或者我在哪里可以读到它?
      【解决方案5】:

      您可以使用换行符在一次播放中完成,但我认为为此使用两个 lineinfile 播放更简洁。

      - hosts: '127.0.0.1'
        vars:
          usernames:
             - larry
             - curly
             - moe
          usergroups:
             - stooges
             - admins
        tasks:
          - lineinfile:
              dest: /etc/ssh/sshd_config
              regexp: '^AllowUsers'
              line: "AllowUsers {{usernames | join(' ')}}"
          - lineinfile:
              dest: /etc/ssh/sshd_config
              regexp: '^AllowGroups'
              line: "AllowGroups {{usergroups | join(' ')}}"
      

      请注意,groups 是保留字,因此请勿将其用作变量名。

      【讨论】:

      • 添加insertafter: '^AllowUsers.+$' 会更可靠,因为如果找不到正则表达式,这将在文件末尾创建 AllowUsers 行。如果找到,它将替换该行。
      猜你喜欢
      • 1970-01-01
      • 2021-01-06
      • 1970-01-01
      • 2018-05-13
      • 1970-01-01
      • 1970-01-01
      • 2020-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多