perf: squash migrations

pull/14430/head
ibuler 2024-11-01 18:49:03 +08:00
parent 78fa7438f7
commit 3164b13e6d
17 changed files with 267 additions and 377 deletions

View File

@ -1,5 +1,6 @@
from .backup import *
from .base import *
from .change_secret import *
from .check_account import *
from .gather_accounts import *
from .push_account import *

View File

@ -1,8 +1,5 @@
# -*- coding: utf-8 -*-
#
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from accounts import serializers
from accounts.const import AutomationTypes
@ -13,7 +10,7 @@ from .base import AutomationExecutionViewSet
__all__ = [
'CheckAccountsAutomationViewSet', 'CheckAccountExecutionViewSet',
'AccountRiskViewSet'
'AccountRiskViewSet', 'AccountCheckEngineViewSet',
]
@ -49,9 +46,26 @@ class AccountRiskViewSet(OrgBulkModelViewSet):
'sync_accounts': 'assets.add_AccountRisk',
}
@action(methods=['post'], detail=False, url_path='sync-accounts')
def sync_accounts(self, request, *args, **kwargs):
gathered_account_ids = request.data.get('gathered_account_ids')
gathered_accounts = self.model.objects.filter(id__in=gathered_account_ids)
self.model.sync_accounts(gathered_accounts)
return Response(status=status.HTTP_201_CREATED)
class AccountCheckEngineViewSet(OrgBulkModelViewSet):
search_fields = ('name',)
serializer_class = serializers.AccountCheckEngineSerializer
rbac_perms = {
'list': 'assets.view_accountcheckautomation',
}
def get_queryset(self):
return [
{
'id': 1,
'name': 'check_gathered_account',
'display_name': '检查发现的账号',
'description': '基于自动发现的账号结果进行检查分析 '
},
{
'id': 2,
'name': 'check_account_secret',
'display_name': '检查账号密码强弱',
'description': '基于账号密码的安全性进行检查分析'
}
]

View File

@ -59,7 +59,7 @@ class GatherAccountsManager(AccountBasePlaybookManager):
for username, info in result.items():
self.asset_usernames_mapper[asset].add(username)
d = {'asset': asset, 'username': username, 'present': True, **info}
d = {'asset': asset, 'username': username, 'remote_present': True, **info}
if len(d['address_last_login']) > 32:
d['address_last_login'] = d['address_last_login'][:32]
accounts.append(d)
@ -112,11 +112,11 @@ class GatherAccountsManager(AccountBasePlaybookManager):
# 新增创建,不用处理状态
# 远端上 比 收集账号少的
# 标识 present=False, 标记为待处理
# 标识 remote_present=False, 标记为待处理
# 远端资产上不存在的,标识为待处理,需要管理员介入
lost_users = ori_ga_users - remote_users
if lost_users:
queryset.filter(username__in=lost_users).update(status='', present=False)
queryset.filter(username__in=lost_users).update(status='', remote_present=False)
# 收集的账号 比 账号列表多的, 有可能是账号中删掉了, 但这时候状态已经是 confirm 了
# 标识状态为 待处理, 让管理员去确认
@ -128,18 +128,21 @@ class GatherAccountsManager(AccountBasePlaybookManager):
# 这个好像不不用对比,原始情况就这样
# 远端账号 比 账号列表少的
# 创建收集账号,标识 present=False, 状态待处理
# 创建收集账号,标识 remote_present=False, 状态待处理
# 远端账号 比 账号列表多的
# 正常情况, 不用处理,因为远端账号会创建到收集账号,收集账号再去对比
# 远端存在的账号,标识为已存在
queryset.filter(username__in=remote_users, present=False).update(present=True)
# 不过这个好像也处理一下 status因为已存在这是状态应该是确认
(queryset.filter(username__in=ori_users)
.exclude(status=ConfirmOrIgnore.confirmed)
.update(status=ConfirmOrIgnore.confirmed))
# 远端存在的账号,标识为已存在
queryset.filter(username__in=remote_users, remote_present=False).update(remote_present=True)
# 资产上没有的,标识为为存在
queryset.exclude(username__in=ori_users).filter(present=False).update(present=True)
def batch_create_gathered_account(self, d, batch_size=20):
if d is None:
@ -222,7 +225,7 @@ class GatherAccountsManager(AccountBasePlaybookManager):
asset_ids = self.asset_usernames_mapper.keys()
assets = Asset.objects.filter(id__in=asset_ids).prefetch_related('accounts')
gather_accounts = GatheredAccount.objects.filter(asset_id__in=asset_ids, present=True)
gather_accounts = GatheredAccount.objects.filter(asset_id__in=asset_ids, remote_present=True)
asset_id_map = {str(asset.id): asset for asset in assets}
asset_id_username = list(assets.values_list('id', 'accounts__username'))

View File

@ -1,15 +1,69 @@
# Generated by Django 4.1.13 on 2024-10-12 03:20
# Generated by Django 4.1.13 on 2024-11-01 10:24
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
("assets", "0006_baseautomation_start_time"),
("accounts", "0004_alter_changesecretrecord_account_and_more"),
]
operations = [
migrations.CreateModel(
name="AccountCheckAutomation",
fields=[
(
"baseautomation_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="assets.baseautomation",
),
),
],
options={
"verbose_name": "Gather account automation",
},
bases=("accounts.accountbaseautomation",),
),
migrations.AddField(
model_name="account",
name="change_secret_status",
field=models.CharField(
blank=True,
max_length=16,
null=True,
verbose_name="Change secret status",
),
),
migrations.AddField(
model_name="account",
name="date_change_secret",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Date change secret"
),
),
migrations.AddField(
model_name="account",
name="date_last_login",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Date last access"
),
),
migrations.AddField(
model_name="account",
name="login_by",
field=models.CharField(
blank=True, max_length=128, null=True, verbose_name="Access by"
),
),
migrations.AddField(
model_name="account",
name="secret_reset",
@ -26,10 +80,165 @@ class Migration(migrations.Migration):
),
),
migrations.AddField(
model_name="account",
name="date_last_access",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Date last access"
model_name="gatheredaccount",
name="authorized_keys",
field=models.TextField(
blank=True, default="", verbose_name="Authorized keys"
),
),
migrations.AddField(
model_name="gatheredaccount",
name="groups",
field=models.TextField(blank=True, default="", verbose_name="Groups"),
),
migrations.AddField(
model_name="gatheredaccount",
name="remote_present",
field=models.BooleanField(default=True, verbose_name="Remote present"),
),
migrations.AddField(
model_name="gatheredaccount",
name="status",
field=models.CharField(
blank=True,
choices=[("confirmed", "Confirmed"), ("ignored", "Ignored")],
default="",
max_length=32,
verbose_name="Status",
),
),
migrations.AddField(
model_name="gatheredaccount",
name="sudoers",
field=models.TextField(blank=True, default="", verbose_name="Sudoers"),
),
migrations.AlterField(
model_name="account",
name="connectivity",
field=models.CharField(
choices=[
("-", "Unknown"),
("na", "N/A"),
("ok", "OK"),
("err", "Error"),
],
default="-",
max_length=16,
verbose_name="Connectivity",
),
),
migrations.AlterField(
model_name="gatheredaccount",
name="present",
field=models.BooleanField(default=False, verbose_name="Present"),
),
migrations.CreateModel(
name="GatheredAccountDiff",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("diff", models.TextField(default="", verbose_name="Diff")),
(
"item",
models.CharField(default="", max_length=32, verbose_name="Item"),
),
(
"date_created",
models.DateTimeField(
auto_now_add=True, verbose_name="Date created"
),
),
(
"account",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="accounts.gatheredaccount",
verbose_name="Gathered account",
),
),
],
),
migrations.CreateModel(
name="AccountRisk",
fields=[
(
"created_by",
models.CharField(
blank=True, max_length=128, null=True, verbose_name="Created by"
),
),
(
"updated_by",
models.CharField(
blank=True, max_length=128, null=True, verbose_name="Updated by"
),
),
(
"date_created",
models.DateTimeField(
auto_now_add=True, null=True, verbose_name="Date created"
),
),
(
"date_updated",
models.DateTimeField(auto_now=True, verbose_name="Date updated"),
),
(
"comment",
models.TextField(blank=True, default="", verbose_name="Comment"),
),
(
"id",
models.UUIDField(
default=uuid.uuid4, primary_key=True, serialize=False
),
),
(
"org_id",
models.CharField(
blank=True,
db_index=True,
default="",
max_length=36,
verbose_name="Organization",
),
),
(
"risk",
models.CharField(
choices=[
("zombie", "Zombie"),
("ghost", "Ghost"),
("weak_password", "Weak password"),
("long_time_no_change", "Long time no change"),
],
max_length=128,
verbose_name="Risk",
),
),
(
"confirmed",
models.BooleanField(default=False, verbose_name="Confirmed"),
),
(
"account",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="risks",
to="accounts.account",
verbose_name="Account",
),
),
],
options={
"verbose_name": "Account risk",
},
),
]

View File

@ -1,112 +0,0 @@
# Generated by Django 4.1.13 on 2024-10-22 06:36
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
("assets", "0006_baseautomation_start_time"),
("accounts", "0005_account_secret_reset"),
]
operations = [
migrations.CreateModel(
name="AccountCheckAutomation",
fields=[
(
"baseautomation_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="assets.baseautomation",
),
),
],
options={
"verbose_name": "Gather account automation",
},
bases=("accounts.accountbaseautomation",),
),
migrations.CreateModel(
name="AccountRisk",
fields=[
(
"created_by",
models.CharField(
blank=True, max_length=128, null=True, verbose_name="Created by"
),
),
(
"updated_by",
models.CharField(
blank=True, max_length=128, null=True, verbose_name="Updated by"
),
),
(
"date_created",
models.DateTimeField(
auto_now_add=True, null=True, verbose_name="Date created"
),
),
(
"date_updated",
models.DateTimeField(auto_now=True, verbose_name="Date updated"),
),
(
"comment",
models.TextField(blank=True, default="", verbose_name="Comment"),
),
(
"id",
models.UUIDField(
default=uuid.uuid4, primary_key=True, serialize=False
),
),
(
"org_id",
models.CharField(
blank=True,
db_index=True,
default="",
max_length=36,
verbose_name="Organization",
),
),
(
"risk",
models.CharField(
choices=[
("zombie", "Zombie"),
("ghost", "Ghost"),
("weak_password", "Weak password"),
("long_time_no_change", "Long time no change"),
],
max_length=128,
verbose_name="Risk",
),
),
(
"confirmed",
models.BooleanField(default=False, verbose_name="Confirmed"),
),
(
"account",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="risks",
to="accounts.account",
verbose_name="Account",
),
),
],
options={
"abstract": False,
},
),
]

View File

@ -1,42 +0,0 @@
# Generated by Django 4.1.13 on 2024-10-24 07:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0006_accountcheckautomation_accountrisk"),
]
operations = [
migrations.AddField(
model_name="account",
name="date_change_secret",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Date change secret"
),
),
migrations.AddField(
model_name="account",
name="date_discovery",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Date discovery"
),
),
migrations.AlterField(
model_name="account",
name="connectivity",
field=models.CharField(
choices=[
("-", "Unknown"),
("na", "N/A"),
("ok", "OK"),
("err", "Error"),
],
default="-",
max_length=16,
verbose_name="Connectivity",
),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 4.1.13 on 2024-10-24 08:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0007_account_date_change_secret_account_date_discovery_and_more"),
]
operations = [
migrations.AddField(
model_name="account",
name="access_by",
field=models.CharField(
blank=True, max_length=128, null=True, verbose_name="Access by"
),
),
]

View File

@ -1,27 +0,0 @@
# Generated by Django 4.1.13 on 2024-10-24 08:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0008_account_access_by"),
]
operations = [
migrations.RemoveField(
model_name="account",
name="date_discovery",
),
migrations.AddField(
model_name="account",
name="change_secret_status",
field=models.CharField(
blank=True,
max_length=16,
null=True,
verbose_name="Change secret status",
),
),
]

View File

@ -1,37 +0,0 @@
# Generated by Django 4.1.13 on 2024-10-28 08:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0009_remove_account_date_discovery_and_more"),
]
operations = [
migrations.AlterModelOptions(
name="accountrisk",
options={"verbose_name": "Account risk"},
),
migrations.RenameField(
model_name="account",
old_name="date_last_access",
new_name="date_last_login",
),
migrations.RenameField(
model_name="account",
old_name="access_by",
new_name="login_by",
),
migrations.AddField(
model_name="gatheredaccount",
name="status",
field=models.CharField(
choices=[("confirmed", "Confirmed"), ("ignored", "Ignored")],
default="",
max_length=32,
verbose_name="Status",
),
),
]

View File

@ -1,64 +0,0 @@
# Generated by Django 4.1.13 on 2024-10-30 02:57
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("accounts", "0010_alter_accountrisk_options_and_more"),
]
operations = [
migrations.AddField(
model_name="gatheredaccount",
name="authorized_keys",
field=models.TextField(
blank=True, default="", verbose_name="Authorized keys"
),
),
migrations.AddField(
model_name="gatheredaccount",
name="groups",
field=models.TextField(blank=True, default="", verbose_name="Groups"),
),
migrations.AddField(
model_name="gatheredaccount",
name="sudo",
field=models.TextField(default=False, verbose_name="Sudo"),
),
migrations.CreateModel(
name="GatheredAccountDiff",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("diff", models.TextField(default="", verbose_name="Diff")),
(
"item",
models.CharField(default="", max_length=32, verbose_name="Item"),
),
(
"date_created",
models.DateTimeField(
auto_now_add=True, verbose_name="Date created"
),
),
(
"account",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="accounts.gatheredaccount",
verbose_name="Gathered account",
),
),
],
),
]

View File

@ -1,24 +0,0 @@
# Generated by Django 4.1.13 on 2024-10-31 08:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0011_remove_gatheredaccount_action_and_more"),
]
operations = [
migrations.AlterField(
model_name="gatheredaccount",
name="status",
field=models.CharField(
blank=True,
choices=[("confirmed", "Confirmed"), ("ignored", "Ignored")],
default="",
max_length=32,
verbose_name="Status",
),
),
]

View File

@ -1,22 +0,0 @@
# Generated by Django 4.1.13 on 2024-10-31 08:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("accounts", "0012_alter_gatheredaccount_status"),
]
operations = [
migrations.RemoveField(
model_name="gatheredaccount",
name="sudo",
),
migrations.AddField(
model_name="gatheredaccount",
name="sudoers",
field=models.TextField(default=False, verbose_name="Sudoers"),
),
]

View File

@ -20,7 +20,8 @@ class GatheredAccountDiff(models.Model):
class GatheredAccount(JMSOrgBaseModel):
present = models.BooleanField(default=True, verbose_name=_("Remote present")) # 资产上是否还存在
remote_present = models.BooleanField(default=True, verbose_name=_("Remote present")) # 远端资产上是否还存在
present = models.BooleanField(default=False, verbose_name=_("Present")) # 系统资产上是否还存在
date_last_login = models.DateTimeField(null=True, verbose_name=_("Date login"))
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_("Asset"))
username = models.CharField(max_length=32, blank=True, db_index=True, verbose_name=_('Username'))

View File

@ -22,9 +22,10 @@ class GatheredAccountSerializer(BulkOrgResourceModelSerializer):
class Meta(BaseAccountSerializer.Meta):
model = GatheredAccount
fields = [
'id', 'present', 'asset', 'username',
'id', 'asset', 'username',
'date_updated', 'address_last_login',
'groups', 'sudoers', 'authorized_keys',
'remote_present', 'present',
'date_last_login', 'status'
]
read_only_fields = fields

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from accounts.const import AutomationTypes
from accounts.models import AccountCheckAutomation, AccountRisk
@ -11,11 +11,12 @@ logger = get_logger(__file__)
__all__ = [
'CheckAccountsAutomationSerializer',
'AccountRiskSerializer'
'AccountRiskSerializer',
'AccountCheckEngineSerializer'
]
class AccountRiskSerializer(ModelSerializer):
class AccountRiskSerializer(serializers.ModelSerializer):
class Meta:
model = AccountRisk
fields = '__all__'
@ -32,3 +33,10 @@ class CheckAccountsAutomationSerializer(BaseAutomationSerializer):
@property
def model_type(self):
return AutomationTypes.check_account
class AccountCheckEngineSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False)
name = serializers.CharField(max_length=128, required=True)
display_name = serializers.CharField(max_length=128, required=False)
description = serializers.CharField(required=False)

View File

@ -24,6 +24,7 @@ router.register(r'gather-account-executions', api.GatherAccountsExecutionViewSet
router.register(r'push-account-automations', api.PushAccountAutomationViewSet, 'push-account-automation')
router.register(r'push-account-executions', api.PushAccountExecutionViewSet, 'push-account-execution')
router.register(r'push-account-records', api.PushAccountRecordViewSet, 'push-account-record')
router.register(r'account-check-engines', api.AccountCheckEngineViewSet, 'account-check-engine')
urlpatterns = [
path('accounts/bulk/', api.AssetAccountBulkCreateApi.as_view(), name='account-bulk-create'),

View File

@ -52,7 +52,7 @@ class RBACPermission(permissions.DjangoModelPermissions):
return cls.format_perms(perm_tmpl, model_cls)
def get_default_action_perms(self, model_cls):
if model_cls is None:
if model_cls is None or not hasattr(model_cls, '_meta'):
return {}
perms = {}