我们组织中的用户创建策略是在首次登录时强制更改密码并使用 SSH 密钥进行远程连接;密码仅用于sudo
本地运行或登录。
为了强制更改密码,我们通常运行chage -d 0 <username>
。因此,我需要在 Ansible 中运行它,但是仅有的如果它只是在前一个任务中的同一个剧本中创建了用户。
我使用模块创建用户ansible.builtin.user
。我的计划是将其输出注册到变量中,然后我想运行shell
模块,但需要满足一些条件,并且我需要确定精确的条件。
我目前的策略是:
- hosts: hosts
vars_files:
- users-config.yaml
tasks:
- name: create users
user:
name: "{{ item.username }}"
state: "{{ item.state }}"
comment: "{{ item.gecos }}"
shell: /bin/bash
groups: "{{ item.groups }}"
loop: "{{ users }}"
register: users_processed
- name: set password age to 0 to force change on next login for new users
debug:
var: "{{ item }}"
loop: "{{ users_processed.results }}"
到目前为止,我发现user
模块返回有用的已更改和失败的,所以我的条件肯定会包含item.changed and not item.failed
,但我还需要什么其他条件才能正确捕获新创建的用户而不是仅仅更新预先存在的用户?
作为参考,在下面的示例输出中apushkin
没有改变,nkhrushchov
被更新了,但是不需要需要重置密码年龄,并且只有rraskolnikov
刚刚创建且需要重置密码年龄的人。
ok: [host3] => (item={'comment': 'Alexander Pushkin', 'shell': '/bin/bash', 'group': 1000, 'name': 'apushkin', 'changed': False, 'state': 'present', 'groups': 'wheel', 'invocation': {'module_args': {'comment': 'Alexander Pushkin', 'ssh_key_bits': 0, 'update_password': 'always', 'non_unique': False, 'force': False, 'ssh_key_type': 'rsa', 'create_home': True, 'password_lock': None, 'ssh_key_passphrase': None, 'uid': None, 'home': None, 'append': False, 'skeleton': None, 'ssh_key_comment': 'ansible-generated on host3', 'group': None, 'system': False, 'state': 'present', 'role': None, 'hidden': None, 'local': None, 'authorization': None, 'profile': None, 'shell': '/bin/bash', 'expires': None, 'ssh_key_file': None, 'groups': ['wheel'], 'move_home': False, 'password': None, 'name': 'apushkin', 'seuser': None, 'remove': False, 'login_class': None, 'generate_ssh_key': None}}, 'home': '/home/apushkin', 'move_home': False, 'append': False, 'uid': 1000, 'failed': False, 'item': {'username': 'apushkin', 'gecos': 'Alexander Pushkin', 'state': 'present', 'groups': 'wheel'}, 'ansible_loop_var': 'item'}) => {
"<class 'dict'>": "VARIABLE IS NOT DEFINED!",
"ansible_loop_var": "item",
"item": {
"ansible_loop_var": "item",
"append": false,
"changed": false,
"comment": "Alexander Pushkin",
"failed": false,
"group": 1000,
"groups": "wheel",
"home": "/home/apushkin",
"invocation": {
"module_args": {
"append": false,
"authorization": null,
"comment": "Alexander Pushkin",
"create_home": true,
"expires": null,
"force": false,
"generate_ssh_key": null,
"group": null,
"groups": [
"wheel"
],
"hidden": null,
"home": null,
"local": null,
"login_class": null,
"move_home": false,
"name": "apushkin",
"non_unique": false,
"password": null,
"password_lock": null,
"profile": null,
"remove": false,
"role": null,
"seuser": null,
"shell": "/bin/bash",
"skeleton": null,
"ssh_key_bits": 0,
"ssh_key_comment": "ansible-generated on host3",
"ssh_key_file": null,
"ssh_key_passphrase": null,
"ssh_key_type": "rsa",
"state": "present",
"system": false,
"uid": null,
"update_password": "always"
}
},
"item": {
"gecos": "Alexander Pushkin",
"groups": "wheel",
"state": "present",
"username": "apushkin"
},
"move_home": false,
"name": "apushkin",
"shell": "/bin/bash",
"state": "present",
"uid": 1000
}
}
ok: [host3] => (item={'comment': '', 'shell': '/bin/bash', 'group': 1001, 'name': 'nhrushchov', 'changed': True, 'state': 'present', 'groups': 'wheel', 'invocation': {'module_args': {'comment': 'Nikita Khrushchov', 'ssh_key_bits': 0, 'update_password': 'always', 'non_unique': False, 'force': False, 'ssh_key_type': 'rsa', 'create_home': True, 'password_lock': None, 'ssh_key_passphrase': None, 'uid': None, 'home': None, 'append': False, 'skeleton': None, 'ssh_key_comment': 'ansible-generated on host3', 'group': None, 'system': False, 'state': 'present', 'role': None, 'hidden': None, 'local': None, 'authorization': None, 'profile': None, 'shell': '/bin/bash', 'expires': None, 'ssh_key_file': None, 'groups': ['wheel'], 'move_home': False, 'password': None, 'name': 'nhrushchov', 'seuser': None, 'remove': False, 'login_class': None, 'generate_ssh_key': None}}, 'home': '/home/nhrushchov', 'move_home': False, 'append': False, 'uid': 1001, 'failed': False, 'item': {'username': 'nhrushchov', 'gecos': 'Nikita Khrushchov', 'state': 'present', 'groups': 'wheel'}, 'ansible_loop_var': 'item'}) => {
"<class 'dict'>": "VARIABLE IS NOT DEFINED!",
"ansible_loop_var": "item",
"item": {
"ansible_loop_var": "item",
"append": false,
"changed": true,
"comment": "",
"failed": false,
"group": 1001,
"groups": "wheel",
"home": "/home/nhrushchov",
"invocation": {
"module_args": {
"append": false,
"authorization": null,
"comment": "Nikita Khrushchov",
"create_home": true,
"expires": null,
"force": false,
"generate_ssh_key": null,
"group": null,
"groups": [
"wheel"
],
"hidden": null,
"home": null,
"local": null,
"login_class": null,
"move_home": false,
"name": "nhrushchov",
"non_unique": false,
"password": null,
"password_lock": null,
"profile": null,
"remove": false,
"role": null,
"seuser": null,
"shell": "/bin/bash",
"skeleton": null,
"ssh_key_bits": 0,
"ssh_key_comment": "ansible-generated on host3",
"ssh_key_file": null,
"ssh_key_passphrase": null,
"ssh_key_type": "rsa",
"state": "present",
"system": false,
"uid": null,
"update_password": "always"
}
},
"item": {
"gecos": "Nikita Khrushchov",
"groups": "wheel",
"state": "present",
"username": "nhrushchov"
},
"move_home": false,
"name": "nhrushchov",
"shell": "/bin/bash",
"state": "present",
"uid": 1001
}
}
ok: [host3] => (item={'invocation': {'module_args': {'comment': 'Rodion Raskolnikov', 'ssh_key_bits': 0, 'update_password': 'always', 'non_unique': False, 'force': False, 'ssh_key_type': 'rsa', 'create_home': True, 'password_lock': None, 'ssh_key_passphrase': None, 'uid': None, 'home': None, 'append': False, 'skeleton': None, 'ssh_key_comment': 'ansible-generated on host3', 'group': None, 'system': False, 'state': 'present', 'role': None, 'hidden': None, 'local': None, 'authorization': None, 'profile': None, 'shell': '/bin/bash', 'expires': None, 'ssh_key_file': None, 'groups': ['wheel'], 'move_home': False, 'password': None, 'name': 'rraskolnikov', 'seuser': None, 'remove': False, 'login_class': None, 'generate_ssh_key': None}}, 'changed': True, 'failed': False, 'item': {'username': 'rraskolnikov', 'gecos': 'Rodion Raskolnikov', 'state': 'present', 'groups': 'wheel'}, 'ansible_loop_var': 'item'}) => {
"<class 'dict'>": "VARIABLE IS NOT DEFINED!",
"ansible_loop_var": "item",
"item": {
"ansible_loop_var": "item",
"changed": true,
"failed": false,
"invocation": {
"module_args": {
"append": false,
"authorization": null,
"comment": "Rodion Raskolnikov",
"create_home": true,
"expires": null,
"force": false,
"generate_ssh_key": null,
"group": null,
"groups": [
"wheel"
],
"hidden": null,
"home": null,
"local": null,
"login_class": null,
"move_home": false,
"name": "rraskolnikov",
"non_unique": false,
"password": null,
"password_lock": null,
"profile": null,
"remove": false,
"role": null,
"seuser": null,
"shell": "/bin/bash",
"skeleton": null,
"ssh_key_bits": 0,
"ssh_key_comment": "ansible-generated on host3",
"ssh_key_file": null,
"ssh_key_passphrase": null,
"ssh_key_type": "rsa",
"state": "present",
"system": false,
"uid": null,
"update_password": "always"
}
},
"item": {
"gecos": "Rodion Raskolnikov",
"groups": "wheel",
"state": "present",
"username": "rraskolnikov"
}
}
}
我只是在努力从这个输出中推断出正确的可靠条件。模块手册说的append
是当用户存在当force
状态不存在且用户存在。“存在”是指“模块运行前就存在”吗?使用以下条件是否安全:
when: item.changed and not item.failed and item.append is not defined and item.force is not defined
或者有更好的方法可以做到这一点?
答案1
使用盖特恩并创建当前用户列表
- name: Get all users
getent:
database: passwd
- name: Set present users
set_fact:
present_users: "{{ ansible_facts.getent_passwd.keys()|list }}"
更新用户后获取新用户列表
- name: Get all users
getent:
database: passwd
- name: Set new users
set_fact:
new_users: "{{ ansible_facts.getent_passwd.keys()|
difference(present_users) }}"
完整剧本的示例
- hosts: test_11
vars:
users:
- username: alice
state: present
gecos: Alice
groups: [guest]
- username: bob
state: present
gecos: Bob
groups: [guest]
tasks:
- name: Get all users
getent:
database: passwd
- name: Set present users
set_fact:
present_users: "{{ ansible_facts.getent_passwd.keys()|list }}"
- name: Create users
user:
name: "{{ item.username }}"
state: "{{ item.state }}"
comment: "{{ item.gecos }}"
shell: /bin/bash
groups: "{{ item.groups }}"
loop: "{{ users }}"
loop_control:
label: "{{ item.username }}"
- name: Get all users
getent:
database: passwd
- name: Set new users
set_fact:
new_users: "{{ ansible_facts.getent_passwd.keys()|
difference(present_users) }}"
- debug:
var: new_users
- debug:
msg: "Force change on next login for {{ item }}"
loop: "{{ new_users }}"
给出
PLAY [test_11] *******************************************************************************
TASK [Get all users] *************************************************************************
ok: [test_11]
TASK [Set present users] *********************************************************************
ok: [test_11]
TASK [Create users] **************************************************************************
changed: [test_11] => (item=alice)
changed: [test_11] => (item=bob)
TASK [Get all users] *************************************************************************
ok: [test_11]
TASK [Set new users] *************************************************************************
ok: [test_11]
TASK [debug] *********************************************************************************
ok: [test_11] =>
new_users:
- alice
- bob
TASK [debug] *********************************************************************************
ok: [test_11] => (item=alice) =>
msg: Force change on next login for alice
ok: [test_11] => (item=bob) =>
msg: Force change on next login for bob
PLAY RECAP ***********************************************************************************
test_11: ok=7 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
该剧本是幂等的。