perf: change secret (#9014)

Co-authored-by: feng <1304903146@qq.com>
pull/9019/head
fit2bot 2022-11-03 22:39:48 +08:00 committed by GitHub
parent 7560a5cd1f
commit ebfc3b7b38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 150 additions and 6 deletions

View File

@ -1,17 +1,28 @@
import os
import time
import random
import string
from copy import deepcopy
from openpyxl import Workbook
from collections import defaultdict
from django.utils import timezone
from django.conf import settings
from common.utils import lazyproperty, gen_key_pair
from common.utils.timezone import local_now_display
from common.utils.file import encrypt_and_compress_zip_file
from common.utils import get_logger, lazyproperty, gen_key_pair
from users.models import User
from assets.models import ChangeSecretRecord
from assets.notifications import ChangeSecretExecutionTaskMsg
from assets.serializers import ChangeSecretRecordBackUpSerializer
from assets.const import (
AutomationTypes, SecretType, SecretStrategy, SSHKeyStrategy, DEFAULT_PASSWORD_RULES
)
from ..base.manager import BasePlaybookManager
logger = get_logger(__name__)
class ChangeSecretManager(BasePlaybookManager):
def __init__(self, *args, **kwargs):
@ -125,7 +136,7 @@ class ChangeSecretManager(BasePlaybookManager):
new_secret = self.get_secret()
recorder = ChangeSecretRecord(
account=account, execution=self.execution,
asset=asset, account=account, execution=self.execution,
old_secret=account.secret, new_secret=new_secret,
)
records.append(recorder)
@ -172,4 +183,51 @@ class ChangeSecretManager(BasePlaybookManager):
recorder.save()
def on_runner_failed(self, runner, e):
pass
logger.error("Change secret error: ", e)
def run(self, *args, **kwargs):
super().run(*args, **kwargs)
recorders = self.name_recorder_mapper.values()
recorders = list(recorders)
self.send_recorder_mail(recorders)
def send_recorder_mail(self, recorders):
if not recorders:
return
recipients = self.execution.recipients
if not recipients:
return
recipients = User.objects.filter(id__in=list(recipients))
name = self.execution.snapshot['name']
path = os.path.join(os.path.dirname(settings.BASE_DIR), 'tmp')
filename = os.path.join(path, f'{name}-{local_now_display()}-{time.time()}.xlsx')
if not self.create_file(recorders, filename):
return
for user in recipients:
attachments = []
if user.secret_key:
password = user.secret_key.encode('utf8')
attachment = os.path.join(path, f'{name}-{local_now_display()}-{time.time()}.zip')
encrypt_and_compress_zip_file(attachment, password, [filename])
attachments = [attachment]
ChangeSecretExecutionTaskMsg(name, user).publish(attachments)
os.remove(filename)
@staticmethod
def create_file(recorders, filename):
serializer_cls = ChangeSecretRecordBackUpSerializer
serializer = serializer_cls(recorders, many=True)
header = [v.label for v in serializer.child.fields.values()]
rows = [list(row.values()) for row in serializer.data]
if not rows:
return False
rows.insert(0, header)
wb = Workbook(filename)
ws = wb.create_sheet('Sheet1')
for row in rows:
ws.append(row)
wb.save(filename)
return True

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.14 on 2022-11-03 13:57
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('assets', '0109_rename_categories_to_types'),
]
operations = [
migrations.AddField(
model_name='changesecretrecord',
name='asset',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.asset'),
),
]

View File

@ -111,6 +111,13 @@ class AutomationExecution(OrgModelMixin):
def manager_type(self):
return self.snapshot['type']
@property
def recipients(self):
recipients = self.snapshot.get('recipients')
if not recipients:
return []
return recipients.values()
def start(self):
from assets.automations.endpoint import ExecutionManager
manager = ExecutionManager(execution=self)

View File

@ -51,6 +51,7 @@ class ChangeSecretAutomation(BaseAutomation):
class ChangeSecretRecord(JMSBaseModel):
execution = models.ForeignKey('assets.AutomationExecution', on_delete=models.CASCADE)
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, null=True)
account = models.ForeignKey('assets.Account', on_delete=models.CASCADE, null=True)
old_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Old secret'))
new_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Secret'))

View File

@ -158,7 +158,6 @@ class BaseAccount(OrgModelMixin):
return {
'name': self.name,
'username': self.username,
'password': self.password,
'public_key': self.public_key,
}

View File

@ -15,11 +15,35 @@ class AccountBackupExecutionTaskMsg(object):
def message(self):
name = self.name
if self.user.secret_key:
return _('{} - The account backup passage task has been completed. See the attachment for details').format(name)
return _('{} - The account backup passage task has been completed. See the attachment for details').format(
name)
return _("{} - The account backup passage task has been completed: the encryption password has not been set - "
"please go to personal information -> file encryption password to set the encryption password").format(name)
"please go to personal information -> file encryption password to set the encryption password").format(
name)
def publish(self, attachment_list=None):
send_mail_attachment_async.delay(
self.subject, self.message, [self.user.email], attachment_list
)
class ChangeSecretExecutionTaskMsg(object):
subject = _('Notification of implementation result of encryption change plan')
def __init__(self, name: str, user: User):
self.name = name
self.user = user
@property
def message(self):
name = self.name
if self.user.secret_key:
return _('{} - The encryption change task has been completed. See the attachment for details').format(name)
return _("{} - The encryption change task has been completed: the encryption password has not been set - "
"please go to personal information -> file encryption password to set the encryption password").format(
name)
def publish(self, attachments=None):
send_mail_attachment_async.delay(
self.subject, self.message, [self.user.email], attachments
)

View File

@ -11,3 +11,4 @@ from .account import *
from assets.serializers.account.backup import *
from .platform import *
from .cagegory import *
from .automation import *

View File

@ -0,0 +1,35 @@
from django.utils.translation import ugettext as _
from rest_framework import serializers
from common.utils import get_logger
from assets.models import ChangeSecretRecord
logger = get_logger(__file__)
class ChangeSecretRecordBackUpSerializer(serializers.ModelSerializer):
asset = serializers.SerializerMethodField(label=_('Asset'))
account = serializers.SerializerMethodField(label=_('Account'))
is_success = serializers.SerializerMethodField(label=_('Is success'))
class Meta:
model = ChangeSecretRecord
fields = [
'id', 'asset', 'account', 'old_secret', 'new_secret',
'status', 'error', 'is_success'
]
@staticmethod
def get_asset(instance):
return str(instance.asset)
@staticmethod
def get_account(instance):
return str(instance.account)
@staticmethod
def get_is_success(obj):
if obj.status == 'success':
return _("Success")
return _("Failed")