Ansible-playbook批量更改sudoers文件里的NOPASSWD:ALL

由于我们有海外业务,于是就要接受GDPR检查,在检查里有一项就是要求不可以在/etc/sudoers文件里配置普通用户 ALL=(root) NOPASSWD:ALL这一项,要根据实际需要缩小范围,于是就要用ansible-playbook去批量修改这个问题。

获取AWS的外网IP

AWS的EC2控制台跟阿里云不一样,不提供一个类似excel表格来获取当前区域内所有云服务器的资料。于是只能通过API获取,不过好在AWS的python SDK比较简单。

首先先pip install boto3pip install awscli。然后再命令行执行aws configure,分别输入自己的AK、SK以及其他资料如下:

1
2
3
4
AWS Access Key ID [None]: 你的AK
AWS Secret Access Key [None]: 你的SK
Default region name [None]: 对应区域 详情可见:https://docs.aws.amazon.com/general/latest/gr/rande.html
Default output format [None]: json #建议选择json

然后就会在/root/.aws(普通用户就会在/homt/用户名/)下看到configcredentials,这里面就是你刚刚输入的内容。

获取所有running状态的ec2的内网IP地址的脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import boto3

def main():
ec2 = boto3.resource('ec2')

instances = ec2.instances.filter(
Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]
)
for instance in instances:
print(instance.private_ip_address) # 获取内网IP地址
print(instance.public_ip_address) # 获取公网IP地址
print(instance.tags) #服务器名称

if __name__ == '__main__':
main()

简单的一匹。

编写play-book

获取到了该区域所有的服务器内网IP之后,先在vim状态下使用:g/^172./d,把老网段的服务器(172开头)的IP过滤掉。然后编写playbook,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- hosts: all        #默认执行hosts里的所有IP
remote_user: root
any_errors_fatal: no
gather_facts: no #不采集对方机器的数据,提高执行速度
serial:
- 5 #5台机器一组
tasks:
- name: judge NOPASSWD:ALL
shell: grep "zabbix ALL=(root) NOPASSWD" /etc/sudoers
ignore_errors: True
register: result

- name: change
lineinfile:
dest: /etc/sudoers
state: present
regexp: '^zabbix '
line: 'zabbix ALL=(root) NOPASSWD: /usr/bin/python'
when: result.stdout.find("NOPASSWD:ALL") != -1

- name: del
lineinfile:
dest: /etc/sudoers
state: absent
regexp: 'NOPASSWD:ALL$' # 将所有NOPASSWD:ALL结尾的字段删除

这里有一点要注意,如果使用shell去用sed -i写的话,那么面临一个很尬的境地:ansible-playbook对冒号空格的搭配默认会识别成key:value的形式。

比如说,在shell里使用sed -i 's/NOPASSWD:ALL/NOPASSWD: \/usr\/bin\/python/g' /etc/sudoers是OK的,但是在shell就会爆格式错误,然后执意要走shell的话,就会可能掉入嵌套地狱…

如果想要在文件后追加多行

ansible里的lineinfile模块是常见的修改文件内容的模块,但是如果要在文件末尾追加多行内容,一般人可能会想到使用with_items搭配lineinfile做循环。其实在ansible 2+的版本有一个更加优雅的方法:blockinfile,写法如下:

1
2
3
4
5
6
7
8
9
tasks:         
- name: addApollo
blockinfile: |
dest=/tmp/chenprofile #目标文件
backup=yes
content="export public_cloud_config_host=apollo.imou.com
export public_cloud_config_port=28080
export public_cloud_config_group=default
export public_cloud_config_namespace=imou.commonsource.mysql,imou.commonsource.cs,imou.commonsource.redis,imou.commonsource.mq,imou.commonsource.lb,imou.saascommonconfig,imou.originalcommonconfig,application"

然后去对应的文件就能看到结果,但是要注意,这里使用等号,而不是冒号,用冒号会报错,可能是ansible的一个小bug。

补充

  1. 如果发现本机已经安装了awscli,但是爆错aws: command not found,检查一下python的virtualenv环境是否正确;
  2. 如果目标机器不在默认的inventory文件里被设置,可以通过加逗号的方式被ansible识别,比如ansible all -i 172.16.1.7, -m ping
  3. 如果playbook想指定其他inventory文件,使用-i参数;
感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------