From 4e2aebde6cdc4eaf6d181933ee84840b0401d14a Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 14 Oct 2022 16:33:24 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E6=94=B9=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/automations/base/manager.py | 16 ++++- .../change_secret/host/aix/main.yml | 4 +- .../change_secret/host/linux/main.yml | 28 ++++---- .../change_secret/host/windows/main.yml | 27 +++---- .../automations/change_secret/manager.py | 32 +++++++-- .../roles/change_password/tasks/main.yml | 4 +- .../gather_facts/host/posix/manifest.yml | 1 - .../automations/ping/host/posix/main.yml | 2 +- .../automations/ping/host/posix/manifest.yml | 1 - .../ping/host/windows/manifest.yml | 2 +- apps/assets/const/host.py | 3 + apps/ops/ansible/inventory.py | 71 +++++++++++++------ utils/playbooks/change_password/main.yml | 4 +- 13 files changed, 126 insertions(+), 69 deletions(-) diff --git a/apps/assets/automations/base/manager.py b/apps/assets/automations/base/manager.py index 81f4c3227..59a5bf75c 100644 --- a/apps/assets/automations/base/manager.py +++ b/apps/assets/automations/base/manager.py @@ -123,8 +123,22 @@ class BasePlaybookManager: runners.append(runer) return runners + def on_host_success(self, host, result): + pass + + def on_host_error(self, host, error, result): + pass + def on_runner_success(self, runner, cb): - raise NotImplementedError + summary = cb.summary + for state, hosts in summary.items(): + for host in hosts: + result = cb.result.get(host) + if state == 'ok': + self.on_host_success(host, result) + else: + error = hosts.get(host) + self.on_host_error(host, error, result) def on_runner_failed(self, runner, e): print("Runner failed: {} {}".format(e, self)) diff --git a/apps/assets/automations/change_secret/host/aix/main.yml b/apps/assets/automations/change_secret/host/aix/main.yml index 483554a1e..41e093df8 100644 --- a/apps/assets/automations/change_secret/host/aix/main.yml +++ b/apps/assets/automations/change_secret/host/aix/main.yml @@ -1,7 +1,7 @@ - hosts: demo tasks: - name: ping - ping: + ansible.builtin.ping: #- name: print variables # debug: @@ -22,7 +22,7 @@ when: account.public_key - name: Verify password - ping: + ansible.builtin.ping: vars: ansible_user: "{{ account.username }}" ansible_pass: "{{ account.password }}" diff --git a/apps/assets/automations/change_secret/host/linux/main.yml b/apps/assets/automations/change_secret/host/linux/main.yml index a7f5d8c18..39c5d0996 100644 --- a/apps/assets/automations/change_secret/host/linux/main.yml +++ b/apps/assets/automations/change_secret/host/linux/main.yml @@ -2,29 +2,33 @@ gather_facts: no tasks: - name: Test privileged account - ping: - - #- name: print variables - # debug: - # msg: "Username: {{ account.username }}, Secret: {{ account.secret }}, Secret type: {{ account.secret_type }}" + ansible.builtin.ping: +# +# - name: print variables +# debug: +# msg: "Username: {{ account.username }}, Secret: {{ account.secret }}, Secret type: {{ account.secret_type }}" - name: Change password - user: + ansible.builtin.user: name: "{{ account.username }}" password: "{{ account.secret | password_hash('sha512') }}" update_password: always - when: account.secret_type == 'password' + when: account.secret_type == "password" - name: Change public key - authorized_key: + ansible.builtin.authorized_key: user: "{{ account.username }}" key: "{{ account.public_key }}" state: present - when: account.public_key + when: account.secret_type == "public_key" + + - name: Refresh connection + ansible.builtin.meta: reset_connection - name: Verify password - ping: + ansible.builtin.ping: + become: no vars: ansible_user: "{{ account.username }}" - ansible_pass: "{{ account.secret }}" - ansible_ssh_connection: paramiko + ansible_password: "{{ account.secret }}" + ansible_become: no diff --git a/apps/assets/automations/change_secret/host/windows/main.yml b/apps/assets/automations/change_secret/host/windows/main.yml index d10c3681e..bc66486dc 100644 --- a/apps/assets/automations/change_secret/host/windows/main.yml +++ b/apps/assets/automations/change_secret/host/windows/main.yml @@ -2,29 +2,24 @@ gather_facts: no tasks: - name: ping - ping: + ansible.windows.win_ping: - #- name: print variables - # debug: - # msg: "Username: {{ account.username }}, Password: {{ account.password }}" +# - name: Print variables +# debug: +# msg: "Username: {{ account.username }}, Password: {{ account.secret }}" - name: Change password - user: + ansible.windows.win_user: name: "{{ account.username }}" - password: "{{ account.password | password_hash('des') }}" + password: "{{ account.secret }}" update_password: always - when: account.password + when: account.secret_type == "password" - - name: Change public key - authorized_key: - user: "{{ account.username }}" - key: "{{ account.public_key }}" - state: present - when: account.public_key + - name: Refresh connection + ansible.builtin.meta: reset_connection - name: Verify password - ping: + ansible.windows.win_ping: vars: ansible_user: "{{ account.username }}" - ansible_pass: "{{ account.password }}" - ansible_ssh_connection: paramiko + ansible_password: "{{ account.secret }}" diff --git a/apps/assets/automations/change_secret/manager.py b/apps/assets/automations/change_secret/manager.py index 3fabe4792..379323b69 100644 --- a/apps/assets/automations/change_secret/manager.py +++ b/apps/assets/automations/change_secret/manager.py @@ -1,11 +1,13 @@ -from copy import deepcopy -from collections import defaultdict import random import string +from copy import deepcopy +from collections import defaultdict + +from django.utils import timezone from common.utils import lazyproperty, gen_key_pair -from ..base.manager import BasePlaybookManager from assets.models import ChangeSecretRecord, SecretStrategy +from ..base.manager import BasePlaybookManager string_punctuation = '!#$%&()*+,-.:;<=>?@[]^_~' DEFAULT_PASSWORD_LENGTH = 30 @@ -121,10 +123,26 @@ class ChangeSecretManager(BasePlaybookManager): ChangeSecretRecord.objects.bulk_create(records) return inventory_hosts - def on_runner_success(self, runner, cb): - summary = cb.summary - print("Summary: ") - print(summary) + def on_host_success(self, host, result): + recorder = self.name_recorder_mapper.get(host) + if not recorder: + return + recorder.status = 'succeed' + recorder.date_finished = timezone.now() + recorder.save() + + account = recorder.account + account.secret = recorder.new_secret + account.save(update_fields=['secret']) + + def on_host_error(self, host, error, result): + recorder = self.name_recorder_mapper.get(host) + if not recorder: + return + recorder.status = 'failed' + recorder.date_finished = timezone.now() + recorder.error = error + recorder.save() def on_runner_failed(self, runner, e): pass diff --git a/apps/assets/automations/gather_facts/database/sqlserver/roles/change_password/tasks/main.yml b/apps/assets/automations/gather_facts/database/sqlserver/roles/change_password/tasks/main.yml index 903cd9115..cb6480235 100644 --- a/apps/assets/automations/gather_facts/database/sqlserver/roles/change_password/tasks/main.yml +++ b/apps/assets/automations/gather_facts/database/sqlserver/roles/change_password/tasks/main.yml @@ -1,5 +1,5 @@ - name: ping - ping: + ansible.builtin.ping: #- name: print variables # debug: @@ -20,7 +20,7 @@ when: account.public_key - name: Verify password - ping: + ansible.builtin.ping: vars: ansible_user: "{{ account.username }}" ansible_pass: "{{ account.password }}" diff --git a/apps/assets/automations/gather_facts/host/posix/manifest.yml b/apps/assets/automations/gather_facts/host/posix/manifest.yml index e5622cf28..b59b701aa 100644 --- a/apps/assets/automations/gather_facts/host/posix/manifest.yml +++ b/apps/assets/automations/gather_facts/host/posix/manifest.yml @@ -3,6 +3,5 @@ name: Gather posix facts category: host type: - linux - - windows - unix method: gather_facts diff --git a/apps/assets/automations/ping/host/posix/main.yml b/apps/assets/automations/ping/host/posix/main.yml index c4c740367..8e5f375dd 100644 --- a/apps/assets/automations/ping/host/posix/main.yml +++ b/apps/assets/automations/ping/host/posix/main.yml @@ -2,4 +2,4 @@ gather_facts: no tasks: - name: Posix ping - ping: + ansible.builtin.ping: diff --git a/apps/assets/automations/ping/host/posix/manifest.yml b/apps/assets/automations/ping/host/posix/manifest.yml index b07caa7f8..4b9afde37 100644 --- a/apps/assets/automations/ping/host/posix/manifest.yml +++ b/apps/assets/automations/ping/host/posix/manifest.yml @@ -3,6 +3,5 @@ name: Posix ping category: host type: - linux - - windows - unix method: ping diff --git a/apps/assets/automations/ping/host/windows/manifest.yml b/apps/assets/automations/ping/host/windows/manifest.yml index fd8cb27a9..6218e5978 100644 --- a/apps/assets/automations/ping/host/windows/manifest.yml +++ b/apps/assets/automations/ping/host/windows/manifest.yml @@ -1,7 +1,7 @@ id: win_ping name: Windows ping version: 1 -method: change_secret +method: ping category: host type: - windows diff --git a/apps/assets/const/host.py b/apps/assets/const/host.py index a26663220..a8db5f022 100644 --- a/apps/assets/const/host.py +++ b/apps/assets/const/host.py @@ -33,6 +33,9 @@ class HostTypes(BaseType): return { '*': { 'choices': ['ssh', 'telnet', 'vnc', 'rdp'] + }, + cls.WINDOWS: { + 'choices': ['rdp', 'ssh', 'vnc'] } } diff --git a/apps/ops/ansible/inventory.py b/apps/ops/ansible/inventory.py index 4408b38b6..ce2c69a46 100644 --- a/apps/ops/ansible/inventory.py +++ b/apps/ops/ansible/inventory.py @@ -10,15 +10,15 @@ __all__ = ['JMSInventory'] class JMSInventory: - def __init__(self, assets, account='', account_policy='smart', host_callback=None): + def __init__(self, assets, account_policy='smart', account_prefer='root,administrator', host_callback=None): """ :param assets: - :param account: account username name if not set use account_policy + :param account_prefer: account username name if not set use account_policy :param account_policy: :param host_callback: after generate host, call this callback to modify host """ self.assets = self.clean_assets(assets) - self.account_username = account + self.account_prefer = account_prefer self.account_policy = account_policy self.host_callback = host_callback @@ -58,6 +58,46 @@ class JMSInventory: ) return {"ansible_ssh_common_args": proxy_command} + @staticmethod + def make_account_ansible_vars(account): + var = { + 'ansible_user': account.username, + } + if not account.secret: + return var + if account.secret_type == 'password': + var['ansible_password'] = account.secret + elif account.secret_type == 'ssh_key': + var['ansible_ssh_private_key_file'] = account.private_key_file + return var + + def make_ssh_account_vars(self, host, asset, account, automation, protocols, platform, gateway): + if not account: + host['error'] = _("No account available") + return host + + ssh_protocol_matched = list(filter(lambda x: x.name == 'ssh', protocols)) + ssh_protocol = ssh_protocol_matched[0] if ssh_protocol_matched else None + host['ansible_host'] = asset.address + host['ansible_port'] = ssh_protocol.port if ssh_protocol else 22 + + su_from = account.su_from + if platform.su_enabled and su_from: + host.update(self.make_account_ansible_vars(su_from)) + become_method = 'sudo' if platform.su_method != 'su' else 'su' + host['ansible_become'] = True + host['ansible_become_method'] = 'sudo' + host['ansible_become_user'] = account.username + if become_method == 'sudo': + host['ansible_become_password'] = su_from.secret + else: + host['ansible_become_password'] = account.secret + else: + host.update(self.make_account_ansible_vars(account)) + + if gateway: + host.update(self.make_proxy_command(gateway)) + def asset_to_host(self, asset, account, automation, protocols, platform): host = { 'name': '{}'.format(asset.name), @@ -73,14 +113,12 @@ class JMSInventory: } if account else None } ansible_config = dict(automation.ansible_config) - ansible_connection = ansible_config.pop('ansible_connection', 'ssh') + ansible_connection = ansible_config.get('ansible_connection', 'ssh') host.update(ansible_config) gateway = None if asset.domain: gateway = asset.domain.select_gateway() - ssh_protocol_matched = list(filter(lambda x: x.name == 'ssh', protocols)) - ssh_protocol = ssh_protocol_matched[0] if ssh_protocol_matched else None if ansible_connection == 'local': if gateway: host['ansible_host'] = gateway.address @@ -91,29 +129,16 @@ class JMSInventory: else: host['ansible_connection'] = 'local' else: - host['ansible_host'] = asset.address - host['ansible_port'] = ssh_protocol.port if ssh_protocol else 22 - if account: - host['ansible_user'] = account.username - - if account.secret_type == 'password' and account.secret: - host['ansible_password'] = account.secret - elif account.secret_type == 'private_key' and account.secret: - host['ssh_private_key'] = account.private_key_file - else: - host['error'] = _("No account found") - - if gateway: - host.update(self.make_proxy_command(gateway)) + self.make_ssh_account_vars(host, asset, account, automation, protocols, platform, gateway) return host def select_account(self, asset): accounts = list(asset.accounts.all()) account_selected = None - account_username = self.account_username + account_username = self.account_prefer - if isinstance(self.account_username, str): - account_username = [self.account_username] + if isinstance(self.account_prefer, str): + account_username = self.account_prefer.split(',') if account_username: for username in account_username: diff --git a/utils/playbooks/change_password/main.yml b/utils/playbooks/change_password/main.yml index 3a981fdb2..31748fe1c 100644 --- a/utils/playbooks/change_password/main.yml +++ b/utils/playbooks/change_password/main.yml @@ -7,7 +7,7 @@ tasks: - name: 监测特权用户密码 - ping: + ansible.builtin.ping: - name: 更改用户密码 user: @@ -19,5 +19,5 @@ vars: - ansible_user: '{{ user1 }}' ansible_ssh_password: '{{ user1password }}' - ping: + ansible.builtin.ping: