mirror of https://github.com/jumpserver/jumpserver
perf: Change secret
parent
0adb9e0d5e
commit
e062b5820c
|
@ -11,8 +11,8 @@ from accounts.models import Account
|
|||
from assets.models import Asset, Node
|
||||
from authentication.permissions import UserConfirmation, ConfirmType
|
||||
from common.api.mixin import ExtraFilterFieldsMixin
|
||||
from common.permissions import IsValidUser
|
||||
from common.drf.filters import AttrRulesFilterBackend
|
||||
from common.permissions import IsValidUser
|
||||
from orgs.mixins.api import OrgBulkModelViewSet
|
||||
from rbac.permissions import RBACPermission
|
||||
|
||||
|
|
|
@ -75,24 +75,24 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
|||
return accounts
|
||||
|
||||
def gen_new_secret(self, account, path_dir):
|
||||
private_key_path = None
|
||||
if self.secret_type is None:
|
||||
new_secret = account.secret
|
||||
return new_secret, private_key_path
|
||||
|
||||
if self.secret_strategy == SecretStrategy.custom:
|
||||
new_secret = self.execution.snapshot['secret']
|
||||
else:
|
||||
generator = SecretGenerator(
|
||||
self.secret_strategy, self.secret_type,
|
||||
self.execution.snapshot.get('password_rules')
|
||||
)
|
||||
new_secret = generator.get_secret()
|
||||
if self.secret_strategy == SecretStrategy.custom:
|
||||
new_secret = self.execution.snapshot['secret']
|
||||
else:
|
||||
generator = SecretGenerator(
|
||||
self.secret_strategy, self.secret_type,
|
||||
self.execution.snapshot.get('password_rules')
|
||||
)
|
||||
new_secret = generator.get_secret()
|
||||
|
||||
recorder_secret = new_secret
|
||||
private_key_path = None
|
||||
if account.secret_type == SecretType.SSH_KEY:
|
||||
private_key_path = self.generate_private_key_path(new_secret, path_dir)
|
||||
new_secret = self.generate_public_key(new_secret)
|
||||
return new_secret, private_key_path
|
||||
return new_secret, private_key_path, recorder_secret
|
||||
|
||||
def get_or_create_record(self, asset, account, new_secret, name):
|
||||
asset_account_id = f'{asset.id}-{account.id}'
|
||||
|
@ -158,9 +158,9 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
|||
return inventory_hosts
|
||||
|
||||
for account in accounts:
|
||||
new_secret, private_key_path = self.gen_new_secret(account, path_dir)
|
||||
new_secret, private_key_path, recorder_secret = self.gen_new_secret(account, path_dir)
|
||||
h = self.gen_change_secret_inventory(host, account, new_secret, private_key_path, asset)
|
||||
self.get_or_create_record(asset, account, new_secret, h['name'])
|
||||
self.get_or_create_record(asset, account, recorder_secret, h['name'])
|
||||
inventory_hosts.append(h)
|
||||
|
||||
return inventory_hosts
|
||||
|
@ -182,7 +182,8 @@ class ChangeSecretManager(AccountBasePlaybookManager):
|
|||
|
||||
with safe_db_connection():
|
||||
recorder.save(update_fields=['status', 'date_finished'])
|
||||
account.save(update_fields=['secret', 'version', 'date_updated'])
|
||||
account.save(update_fields=['secret', 'date_updated'])
|
||||
|
||||
self.summary['ok_accounts'] += 1
|
||||
self.result['ok_accounts'].append(
|
||||
{
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 4.1.13 on 2024-12-05 08:39
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0020_alter_automationexecution_options'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='pushaccountautomation',
|
||||
name='action',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='pushaccountautomation',
|
||||
name='triggers',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='pushaccountautomation',
|
||||
name='username',
|
||||
),
|
||||
]
|
|
@ -14,6 +14,7 @@ __all__ = ['Account', 'AccountHistoricalRecords']
|
|||
|
||||
class AccountHistoricalRecords(HistoricalRecords):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.updated_version = None
|
||||
self.included_fields = kwargs.pop('included_fields', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
@ -22,18 +23,29 @@ class AccountHistoricalRecords(HistoricalRecords):
|
|||
return super().post_save(instance, created, using=using, **kwargs)
|
||||
|
||||
check_fields = set(self.included_fields) - {'version'}
|
||||
history_attrs = instance.history.all().values(*check_fields).first()
|
||||
if history_attrs is None:
|
||||
|
||||
history_account = instance.history.first()
|
||||
if history_account is None:
|
||||
self.updated_version = 1
|
||||
return super().post_save(instance, created, using=using, **kwargs)
|
||||
|
||||
history_attrs = {field: getattr(history_account, field) for field in check_fields}
|
||||
|
||||
attrs = {field: getattr(instance, field) for field in check_fields}
|
||||
history_attrs = set(history_attrs.items())
|
||||
attrs = set(attrs.items())
|
||||
diff = attrs - history_attrs
|
||||
if not diff:
|
||||
return
|
||||
self.updated_version = history_account.version + 1
|
||||
return super().post_save(instance, created, using=using, **kwargs)
|
||||
|
||||
def create_historical_record(self, instance, history_type, using=None):
|
||||
super().create_historical_record(instance, history_type, using=using)
|
||||
if self.updated_version is not None:
|
||||
instance.version = self.updated_version
|
||||
instance.save(update_fields=['version'])
|
||||
|
||||
def create_history_model(self, model, inherited):
|
||||
if self.included_fields and not self.excluded_fields:
|
||||
self.excluded_fields = [
|
||||
|
@ -60,7 +72,8 @@ class Account(AbsConnectivity, LabeledMixin, BaseAccount):
|
|||
date_last_login = models.DateTimeField(null=True, blank=True, verbose_name=_('Date last access'))
|
||||
login_by = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Access by'))
|
||||
date_change_secret = models.DateTimeField(null=True, blank=True, verbose_name=_('Date change secret'))
|
||||
change_secret_status = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Change secret status'))
|
||||
change_secret_status = models.CharField(max_length=16, null=True, blank=True,
|
||||
verbose_name=_('Change secret status'))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Account')
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from accounts.const import AutomationTypes
|
||||
|
@ -11,9 +10,6 @@ __all__ = ['PushAccountAutomation']
|
|||
|
||||
|
||||
class PushAccountAutomation(ChangeSecretMixin, AccountBaseAutomation):
|
||||
triggers = models.JSONField(max_length=16, default=list, verbose_name=_('Triggers'))
|
||||
username = models.CharField(max_length=128, verbose_name=_('Username'))
|
||||
action = models.CharField(max_length=16, verbose_name=_('Action'))
|
||||
|
||||
def create_nonlocal_accounts(self, usernames, asset):
|
||||
secret_type = self.secret_type
|
||||
|
@ -30,28 +26,11 @@ class PushAccountAutomation(ChangeSecretMixin, AccountBaseAutomation):
|
|||
]
|
||||
Account.objects.bulk_create(create_account_objs)
|
||||
|
||||
@property
|
||||
def dynamic_username(self):
|
||||
return self.username == '@USER'
|
||||
|
||||
@dynamic_username.setter
|
||||
def dynamic_username(self, value):
|
||||
if value:
|
||||
self.username = '@USER'
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.type = AutomationTypes.push_account
|
||||
if not settings.XPACK_LICENSE_IS_VALID:
|
||||
self.is_periodic = False
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def to_attr_json(self):
|
||||
attr_json = super().to_attr_json()
|
||||
attr_json.update({
|
||||
'username': self.username,
|
||||
'params': self.params,
|
||||
})
|
||||
return attr_json
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Push asset account")
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from collections import defaultdict
|
||||
|
||||
from django.db.models.signals import post_delete
|
||||
from django.db.models.signals import pre_save, post_save
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext_noop
|
||||
|
||||
|
@ -17,15 +17,6 @@ from .tasks.push_account import push_accounts_to_assets_task
|
|||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
@receiver(pre_save, sender=Account)
|
||||
def on_account_pre_save(sender, instance, **kwargs):
|
||||
if instance.version == 0:
|
||||
instance.version = 1
|
||||
else:
|
||||
history_account = instance.history.first()
|
||||
instance.version = history_account.version + 1 if history_account else 0
|
||||
|
||||
|
||||
@merge_delay_run(ttl=5)
|
||||
def push_accounts_if_need(accounts=()):
|
||||
from .models import AccountTemplate
|
||||
|
|
|
@ -74,6 +74,7 @@ class BaseAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
|
|||
"type": self.type,
|
||||
"comment": self.comment,
|
||||
"accounts": self.accounts,
|
||||
"params": self.params,
|
||||
"org_id": str(self.org_id),
|
||||
"nodes": self.get_many_to_many_ids("nodes"),
|
||||
"assets": self.get_many_to_many_ids("assets"),
|
||||
|
|
Loading…
Reference in New Issue