perf: 修改账号推送

pull/9246/head
ibuler 2022-12-27 15:27:33 +08:00
parent 795e952dc1
commit 3da9efc3fd
27 changed files with 121 additions and 235 deletions

View File

@ -1,18 +1,18 @@
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _
from rest_framework.response import Response
from rest_framework import status, mixins, viewsets
from rest_framework.response import Response
from orgs.mixins import generics
from assets import serializers
from assets.tasks import execute_automation
from assets.models import BaseAutomation, AutomationExecution
from assets.tasks import execute_automation
from common.const.choices import Trigger
from orgs.mixins import generics
__all__ = [
'AutomationAssetsListApi', 'AutomationRemoveAssetApi',
'AutomationAddAssetApi', 'AutomationNodeAddRemoveApi',
'ChangSecretExecutionViewSet', 'GatherAccountsExecutionViewSet',
'AutomationExecutionViewSet',
]
@ -115,19 +115,3 @@ class AutomationExecutionViewSet(
pid=automation.pk, trigger=Trigger.manual, tp=tp
)
return Response({'task': task.id}, status=status.HTTP_201_CREATED)
class ChangSecretExecutionViewSet(AutomationExecutionViewSet):
rbac_perms = (
("list", "assets.view_changesecretexecution"),
("retrieve", "assets.view_changesecretexecution"),
("create", "assets.add_changesecretexecution"),
)
class GatherAccountsExecutionViewSet(AutomationExecutionViewSet):
rbac_perms = (
("list", "assets.view_gatheraccountsexecution"),
("retrieve", "assets.view_gatheraccountsexecution"),
("create", "assets.add_gatheraccountsexecution"),
)

View File

@ -3,14 +3,15 @@
from rest_framework import mixins
from assets import serializers
from assets.models import ChangeSecretAutomation, ChangeSecretRecord, AutomationExecution
from common.utils import get_object_or_none
from orgs.mixins.api import OrgBulkModelViewSet, OrgGenericViewSet
from assets.models import ChangeSecretAutomation, ChangeSecretRecord, AutomationExecution
from assets import serializers
from .base import AutomationExecutionViewSet
__all__ = [
'ChangeSecretAutomationViewSet', 'ChangeSecretRecordViewSet'
'ChangeSecretAutomationViewSet', 'ChangeSecretRecordViewSet',
'ChangSecretExecutionViewSet'
]
@ -38,3 +39,11 @@ class ChangeSecretRecordViewSet(mixins.ListModelMixin, OrgGenericViewSet):
queryset = queryset.filter(execution=execution)
queryset = queryset.order_by('-date_started')
return queryset
class ChangSecretExecutionViewSet(AutomationExecutionViewSet):
rbac_perms = (
("list", "assets.view_changesecretexecution"),
("retrieve", "assets.view_changesecretexecution"),
("create", "assets.add_changesecretexecution"),
)

View File

@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
#
from orgs.mixins.api import OrgBulkModelViewSet
from assets.models import GatherAccountsAutomation
from assets import serializers
from assets.models import GatherAccountsAutomation
from orgs.mixins.api import OrgBulkModelViewSet
from .base import AutomationExecutionViewSet
__all__ = [
'GatherAccountsAutomationViewSet',
'GatherAccountsAutomationViewSet', 'GatherAccountsExecutionViewSet'
]
@ -16,3 +16,11 @@ class GatherAccountsAutomationViewSet(OrgBulkModelViewSet):
search_fields = filter_fields
ordering_fields = ('name',)
serializer_class = serializers.GatherAccountAutomationSerializer
class GatherAccountsExecutionViewSet(AutomationExecutionViewSet):
rbac_perms = (
("list", "assets.view_gatheraccountsexecution"),
("retrieve", "assets.view_gatheraccountsexecution"),
("create", "assets.add_gatheraccountsexecution"),
)

View File

@ -1,19 +1,19 @@
import os
import yaml
import shutil
from hashlib import md5
from copy import deepcopy
from socket import gethostname
from collections import defaultdict
from copy import deepcopy
from hashlib import md5
from socket import gethostname
import yaml
from django.conf import settings
from django.utils import timezone
from django.utils.translation import gettext as _
from common.utils import get_logger
from common.utils import ssh_pubkey_gen, ssh_key_string_to_obj
from assets.const import SecretType
from assets.automations.methods import platform_automation_methods
from assets.const import SecretType
from common.utils import get_logger, lazyproperty
from common.utils import ssh_pubkey_gen, ssh_key_string_to_obj
from ops.ansible import JMSInventory, PlaybookRunner, DefaultCallback
logger = get_logger(__name__)
@ -93,7 +93,7 @@ class BasePlaybookManager:
def get_assets_group_by_platform(self):
return self.automation.all_assets_group_by_platform()
@property
@lazyproperty
def runtime_dir(self):
ansible_dir = settings.ANSIBLE_DIR
dir_name = '{}_{}'.format(self.automation.name.replace(' ', '_'), self.execution.id)
@ -105,11 +105,6 @@ class BasePlaybookManager:
os.makedirs(path, exist_ok=True, mode=0o755)
return path
def prepare_playbook_dir(self):
for d in [self.runtime_dir]:
if not os.path.exists(d):
os.makedirs(d, exist_ok=True, mode=0o755)
def host_callback(self, host, automation=None, **kwargs):
enabled_attr = '{}_enabled'.format(self.__class__.method_type())
method_attr = '{}_method'.format(self.__class__.method_type())

View File

@ -1,16 +0,0 @@
- hosts: mongodb
gather_facts: no
vars:
ansible_python_interpreter: /usr/local/bin/python
tasks:
- name: Add user account.username
mongodb_user:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.specific.db_name }}"
db: "{{ jms_asset.specific.db_name }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"

View File

@ -1,6 +0,0 @@
id: push_account_mongodb
name: Push account from MongoDB
category: database
type:
- mongodb
method: push_account

View File

@ -1,15 +0,0 @@
- hosts: mysql
gather_facts: no
vars:
ansible_python_interpreter: /usr/local/bin/python
tasks:
- name: Add user account.username
community.mysql.mysql_user:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"
host: "%"

View File

@ -1,6 +0,0 @@
id: push_account_mysql
name: Push account from MySQL
category: database
type:
- mysql
method: push_account

View File

@ -1,16 +0,0 @@
- hosts: oracle
gather_facts: no
vars:
ansible_python_interpreter: /usr/local/bin/python
tasks:
- name: Add user account.username
oracle_user:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
login_database: "{{ jms_asset.specific.db_name }}"
mode: "{{ jms_account.mode }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"

View File

@ -1,6 +0,0 @@
id: push_account_oracle
name: Push account from Oracle
category: database
type:
- oracle
method: push_account

View File

@ -1,16 +0,0 @@
- hosts: postgresql
gather_facts: no
vars:
ansible_python_interpreter: /usr/local/bin/python
tasks:
- name: Add user account.username
community.postgresql.postgresql_user:
login_user: "{{ jms_account.username }}"
login_password: "{{ jms_account.secret }}"
login_host: "{{ jms_asset.address }}"
login_port: "{{ jms_asset.port }}"
db: "{{ jms_asset.specific.db_name }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"

View File

@ -1,6 +0,0 @@
id: push_account_postgresql
name: Push account for PostgreSQL
category: database
type:
- postgresql
method: push_account

View File

@ -1,19 +0,0 @@
- hosts: demo
gather_facts: no
tasks:
- name: Add user account.username
ansible.builtin.user:
name: "{{ account.username }}"
- name: Set account.username password
ansible.builtin.user:
name: "{{ account.username }}"
password: "{{ account.secret | password_hash('sha512') }}"
update_password: always
when: secret_type == "password"
- name: Set account.username SSH key
ansible.builtin.authorized_key:
user: "{{ account.username }}"
key: "{{ account.secret }}"
when: secret_type == "ssh_key"

View File

@ -1,7 +0,0 @@
id: push_account_posix
name: Push posix account
category: host
type:
- linux
- unix
method: push_account

View File

@ -1,13 +0,0 @@
- hosts: windows
gather_facts: yes
tasks:
- name: Add user account.username
ansible.windows.win_user:
vars:
fullname: "{{ account.username }}"
name: "{{ account.username }}"
password: "{{ account.secret }}"
state: present
password_expired: no
update_password: always
password_never_expires: yes

View File

@ -1,7 +0,0 @@
id: push_account_windows
name: Push account windows
version: 1
method: push_account
category: host
type:
- windows

View File

@ -12,7 +12,7 @@ DEFAULT_PASSWORD_RULES = {
class AutomationTypes(TextChoices):
ping = 'ping', _('Ping')
gather_facts = 'gather_facts', _('Gather facts')
push_account = 'push_account', _('Create account')
push_account = 'push_account', _('Push account')
change_secret = 'change_secret', _('Change secret')
verify_account = 'verify_account', _('Verify account')
gather_accounts = 'gather_accounts', _('Gather accounts')
@ -20,8 +20,9 @@ class AutomationTypes(TextChoices):
@classmethod
def get_type_model(cls, tp):
from assets.models import (
PingAutomation, GatherFactsAutomation, PushAccountAutomation,
ChangeSecretAutomation, VerifyAccountAutomation, GatherAccountsAutomation,
PingAutomation, GatherFactsAutomation,
PushAccountAutomation, ChangeSecretAutomation,
VerifyAccountAutomation, GatherAccountsAutomation,
)
type_model_dict = {
cls.ping: PingAutomation,

View File

@ -76,7 +76,6 @@ class HostTypes(BaseType):
{'name': 'macOS'},
{'name': 'BSD'},
{'name': 'AIX', 'automation': {
'push_account_method': 'push_account_aix',
'change_secret_method': 'push_secret_aix'
}}
],

View File

@ -1,11 +1,9 @@
# Generated by Django 3.1.14 on 2022-04-26 07:54
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('assets', '0095_auto_20220407_1726'),
]
@ -18,7 +16,8 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=32, verbose_name='Name')),
('port', models.IntegerField(verbose_name='Port')),
('setting', models.JSONField(default=dict, verbose_name='Setting')),
('platform', models.ForeignKey(on_delete=models.deletion.CASCADE, related_name='protocols', to='assets.platform'),),
('platform',
models.ForeignKey(on_delete=models.deletion.CASCADE, related_name='protocols', to='assets.platform'),),
('default', models.BooleanField(default=True, verbose_name='Default')),
('required', models.BooleanField(default=False, verbose_name='Required')),
],
@ -32,20 +31,24 @@ class Migration(migrations.Migration):
('ping_enabled', models.BooleanField(default=False, verbose_name='Ping enabled')),
('ping_method', models.CharField(blank=True, max_length=32, null=True, verbose_name='Ping method')),
('gather_facts_enabled', models.BooleanField(default=False, verbose_name='Gather facts enabled')),
('gather_facts_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method')),
('push_account_enabled', models.BooleanField(default=False, verbose_name='Create account enabled')),
('push_account_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Create account method')),
('gather_facts_method',
models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method')),
('change_secret_enabled', models.BooleanField(default=False, verbose_name='Change password enabled')),
('change_secret_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Change password method')),
('change_secret_method',
models.TextField(blank=True, max_length=32, null=True, verbose_name='Change password method')),
('verify_account_enabled', models.BooleanField(default=False, verbose_name='Verify account enabled')),
('verify_account_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Verify account method')),
('verify_account_method',
models.TextField(blank=True, max_length=32, null=True, verbose_name='Verify account method')),
('gather_accounts_enabled', models.BooleanField(default=False, verbose_name='Gather facts enabled')),
('gather_accounts_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method')),
('gather_accounts_method',
models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method')),
],
),
migrations.AddField(
model_name='platform',
name='automation',
field=models.OneToOneField(blank=True, null=True, on_delete=models.deletion.CASCADE, related_name='platform', to='assets.platformautomation', verbose_name='Automation'),
field=models.OneToOneField(blank=True, null=True, on_delete=models.deletion.CASCADE,
related_name='platform', to='assets.platformautomation',
verbose_name='Automation'),
),
]

View File

@ -75,16 +75,6 @@ class Migration(migrations.Migration):
name='updated_by',
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by'),
),
migrations.AlterField(
model_name='platformautomation',
name='push_account_enabled',
field=models.BooleanField(default=False, verbose_name='Push account enabled'),
),
migrations.AlterField(
model_name='platformautomation',
name='push_account_method',
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Push account method'),
),
migrations.AlterField(
model_name='platformprotocol',
name='default',

View File

@ -0,0 +1,50 @@
# Generated by Django 3.2.14 on 2022-12-27 07:04
import common.db.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0117_alter_gateway_options'),
]
operations = [
migrations.AddField(
model_name='pushaccountautomation',
name='password_rules',
field=models.JSONField(default=dict, verbose_name='Password rules'),
),
migrations.AddField(
model_name='pushaccountautomation',
name='secret',
field=common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret'),
),
migrations.AddField(
model_name='pushaccountautomation',
name='secret_strategy',
field=models.CharField(choices=[('specific', 'Specific'), ('random_one', 'All assets use the same random password'), ('random_all', 'All assets use different random password')], default='specific', max_length=16, verbose_name='Secret strategy'),
),
migrations.AddField(
model_name='pushaccountautomation',
name='secret_type',
field=models.CharField(choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), ('token', 'Token')], default='password', max_length=16, verbose_name='Secret type'),
),
migrations.AddField(
model_name='pushaccountautomation',
name='ssh_key_change_strategy',
field=models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (The key generated by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy'),
),
migrations.AddField(
model_name='pushaccountautomation',
name='username',
field=models.CharField(default='', max_length=128, verbose_name='Username'),
preserve_default=False,
),
migrations.AlterField(
model_name='baseautomation',
name='type',
field=models.CharField(choices=[('ping', 'Ping'), ('gather_facts', 'Gather facts'), ('push_account', 'Push account'), ('change_secret', 'Change secret'), ('verify_account', 'Verify account'), ('gather_accounts', 'Gather accounts')], max_length=16, verbose_name='Type'),
),
]

View File

@ -1,15 +1,15 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from assets.const import AutomationTypes, SecretType, SecretStrategy, SSHKeyStrategy
from common.db import fields
from common.db.models import JMSBaseModel
from assets.const import AutomationTypes, SecretType, SecretStrategy, SSHKeyStrategy
from .base import BaseAutomation
__all__ = ['ChangeSecretAutomation', 'ChangeSecretRecord']
__all__ = ['ChangeSecretAutomation', 'ChangeSecretRecord', 'ChangeSecretMixin']
class ChangeSecretAutomation(BaseAutomation):
class ChangeSecretMixin(models.Model):
secret_type = models.CharField(
choices=SecretType.choices, max_length=16,
default=SecretType.PASSWORD, verbose_name=_('Secret type')
@ -24,6 +24,12 @@ class ChangeSecretAutomation(BaseAutomation):
choices=SSHKeyStrategy.choices, max_length=16,
default=SSHKeyStrategy.add, verbose_name=_('SSH key change strategy')
)
class Meta:
abstract = True
class ChangeSecretAutomation(BaseAutomation, ChangeSecretMixin):
recipients = models.ManyToManyField('users.User', verbose_name=_("Recipient"), blank=True)
def save(self, *args, **kwargs):

View File

@ -1,23 +0,0 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from assets.const import AutomationTypes
from .change_secret import ChangeSecretAutomation
__all__ = ['CreateAccountAutomation']
class CreateAccountAutomation(ChangeSecretAutomation):
username = models.CharField(max_length=128, blank=True, verbose_name=_("Username"))
secret_type = models.CharField(max_length=16, verbose_name=_('Secret type'))
secret_strategy = models.CharField(max_length=16, default=SecretPolicy.random,
choices=SecretPolicy.choices, verbose_name=_("Secret strategy"))
secret = models.CharField(max_length=1024, blank=True, verbose_name=_("Secret"))
accounts = None
def save(self, *args, **kwargs):
self.type = AutomationTypes.push_account
super().save(*args, **kwargs)
class Meta:
verbose_name = _("Push asset account")

View File

@ -1,12 +1,16 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from assets.const import AutomationTypes
from .base import BaseAutomation
from .change_secret import ChangeSecretMixin
__all__ = ['PushAccountAutomation']
class PushAccountAutomation(BaseAutomation):
class PushAccountAutomation(BaseAutomation, ChangeSecretMixin):
accounts = None
username = models.CharField(max_length=128, verbose_name=_('Username'))
def save(self, *args, **kwargs):
self.type = AutomationTypes.push_account

View File

@ -44,8 +44,6 @@ class PlatformAutomation(models.Model):
ping_method = models.CharField(max_length=32, blank=True, null=True, verbose_name=_("Ping method"))
gather_facts_enabled = models.BooleanField(default=False, verbose_name=_("Gather facts enabled"))
gather_facts_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Gather facts method"))
push_account_enabled = models.BooleanField(default=False, verbose_name=_("Push account enabled"))
push_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Push account method"))
change_secret_enabled = models.BooleanField(default=False, verbose_name=_("Change password enabled"))
change_secret_method = models.TextField(
max_length=32, blank=True, null=True, verbose_name=_("Change password method"))

View File

@ -7,7 +7,6 @@ from django.utils.translation import ugettext_lazy as _
from common.utils import validate_ssh_private_key
__all__ = [
'private_key_validator',
]
@ -22,8 +21,6 @@ def private_key_validator(value):
def update_internal_platforms(platform_model):
from assets.const import AllTypes
platforms = [
{'name': 'Linux', 'category': 'host', 'type': 'linux'},
{'name': 'BSD', 'category': 'host', 'type': 'unix'},
@ -32,7 +29,6 @@ def update_internal_platforms(platform_model):
{'name': 'Windows', 'category': 'host', 'type': 'unix'},
{
'name': 'AIX', 'category': 'host', 'type': 'unix',
'push_account_method': 'create_account_aix',
'change_secret_method': 'change_secret_aix',
},
{'name': 'Windows', 'category': 'host', 'type': 'windows'},

View File

@ -45,22 +45,21 @@ class PlatformAutomationSerializer(serializers.ModelSerializer):
"ansible_enabled", "ansible_config",
"ping_enabled", "ping_method",
"gather_facts_enabled", "gather_facts_method",
"push_account_enabled", "push_account_method",
"change_secret_enabled", "change_secret_method",
"verify_account_enabled", "verify_account_method",
"gather_accounts_enabled", "gather_accounts_method",
]
extra_kwargs = {
"ping_enabled": {"label": "启用资产探测"},
"ping_method": {"label": "探测方式"},
"gather_facts_enabled": {"label": "启用收集信息"},
"ping_method": {"label": "资产探测方式"},
"gather_facts_enabled": {"label": "收集资产信息"},
"gather_facts_method": {"label": "收集信息方式"},
"verify_account_enabled": {"label": "启用校验账号"},
"verify_account_method": {"label": "校验账号方式"},
"push_account_enabled": {"label": "启用推送账号"},
"push_account_method": {"label": "推送账号方式"},
"change_secret_enabled": {"label": "启用账号改密"},
"change_secret_method": {"label": "账号创建改密方式"},
"change_secret_method": {"label": "账号改密方式"},
"gather_accounts_enabled": {"label": "启用账号收集"},
"gather_accounts_method": {"label": "收集账号方式"},
}