Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

新增选择本地文件上传密钥,上传后将密钥信息保存到数据库,连接时从数据库读取 #1303

Merged
merged 27 commits into from
Jan 13, 2022
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6d0bab6
# 新增 pkey 目录挂载
issacmark Dec 28, 2021
31e00e6
# 修改显示名称,引导用户填写 pkey 文件的名称
issacmark Dec 28, 2021
cce914c
# 新增 ssh tunnel keys 默认存放文件夹
issacmark Dec 28, 2021
0902cfb
# 将数据库的 pkey 名字与 pkey 目录拼接
issacmark Dec 28, 2021
5b71dd7
# 后台 django q 菜单改为中文
issacmark Dec 29, 2021
88821c4
# 对应增加 pkey 文本框
issacmark Dec 30, 2021
beb2112
# 通过 form 读取秘钥信息
issacmark Dec 30, 2021
32e2422
# 新增 pkey 字段存储密钥信息
issacmark Dec 31, 2021
c33d6c1
Merge remote-tracking branch 'origin/new_pr' into new_pr
issacmark Dec 31, 2021
a34d3e1
# 改为使用 pkey 文件对象进行登录
issacmark Dec 31, 2021
166ac3b
# 新增 pkey 字段存储密钥信息
issacmark Dec 31, 2021
a2cdf04
#
issacmark Dec 31, 2021
a24f90c
# 改为传入 pkey
issacmark Dec 31, 2021
0ce4f40
# 新增本地保存 pkey 的路径
issacmark Dec 31, 2021
aa420a7
Update models.py
issacmark Dec 31, 2021
a4d66a8
Merge branch 'master' into new_pr
issacmark Dec 31, 2021
2b59a0f
# 设置为相对路径
issacmark Jan 4, 2022
d9f2ddf
Merge remote-tracking branch 'origin/new_pr' into new_pr
issacmark Jan 4, 2022
e88478c
#
issacmark Jan 4, 2022
5e31b8c
Merge branch 'master' into new_pr
issacmark Jan 4, 2022
99e262d
#
issacmark Jan 6, 2022
7eee255
Merge branch 'master' into new_pr
hhyo Jan 11, 2022
fd128c0
# 修复当填写了秘钥路径,秘钥文件不存在时的异常
issacmark Jan 12, 2022
ca9f519
# pkey 字段改为 EncryptedTextField
issacmark Jan 12, 2022
3b78bea
# ssh 隧道功能修改
issacmark Jan 12, 2022
6793607
Merge remote-tracking branch 'origin/new_pr' into new_pr
issacmark Jan 12, 2022
fe7fe9c
Merge branch 'master' into new_pr
hhyo Jan 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions archery/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,3 +257,11 @@
# },
}
}

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
if not os.path.exists(MEDIA_ROOT):
os.mkdir(MEDIA_ROOT)

PKEY_ROOT = os.path.join(MEDIA_ROOT, 'keys')
if not os.path.exists(PKEY_ROOT):
os.mkdir(PKEY_ROOT)
7 changes: 5 additions & 2 deletions sql/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
WorkflowAudit, WorkflowLog, ParamTemplate, ParamHistory, InstanceTag, \
Tunnel, AuditEntry

from sql.form import TunnelForm


# 用户管理
@admin.register(Users)
Expand Down Expand Up @@ -87,13 +89,14 @@ class TunnelAdmin(admin.ModelAdmin):
search_fields = ('id', 'tunnel_name')
fieldsets = (
None,
{'fields': ('tunnel_name', 'host', 'port', 'user', 'password', 'pkey_path', 'pkey_password',), }),
{'fields': ('tunnel_name', 'host', 'port', 'user', 'password', 'pkey_path', 'pkey_password', 'pkey'), }),
ordering = ('id',)
# 添加页显示内容
add_fieldsets = (
('隧道信息', {'fields': ('tunnel_name', 'host', 'port')}),
('连接信息', {'fields': ('user', 'password', 'pkey_path', 'pkey_password')}),
('连接信息', {'fields': ('user', 'password', 'pkey_path', 'pkey_password', 'pkey')}),
)
form = TunnelForm

def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name in ['password', 'pkey_password']:
Expand Down
4 changes: 2 additions & 2 deletions sql/engines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(self, instance=None):
instance.tunnel.port,
instance.tunnel.user,
instance.tunnel.password,
instance.tunnel.pkey_path,
instance.tunnel.pkey,
instance.tunnel.pkey_password,
)
self.host,self.port = self.ssh.get_ssh()
Expand All @@ -48,7 +48,7 @@ def remote_instance_conn(self, instance=None):
instance.tunnel.port,
instance.tunnel.user,
instance.tunnel.password,
instance.tunnel.pkey_path,
instance.tunnel.pkey,
instance.tunnel.pkey_password,
)
self.remote_host, self.remote_port = self.remotessh.get_ssh()
Expand Down
27 changes: 27 additions & 0 deletions sql/form.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/python
# -*- coding:utf-8 -*-
"""
---------------------------------------------------------
@project: issacmarkArchery
@file: form
@date: 2021/12/30 17:43
@author: mayp
---------------------------------------------------------
"""
from django.forms import ModelForm, Textarea
from sql.models import Tunnel


class TunnelForm(ModelForm):
class Meta:
model = Tunnel
fields = "__all__"
widgets = {
'PKey': Textarea(attrs={'cols': 40, 'rows': 8}),
}

def clean(self):
cleaned_data = super().clean()
pkey_path = cleaned_data.get('pkey_path').read()
if pkey_path:
cleaned_data['pkey'] = str(pkey_path, 'utf-8').replace(r'\r', '').replace(r'\n', '')
38 changes: 12 additions & 26 deletions sql/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

from django.utils.translation import gettext as _
from mirage.crypto import Crypto
from django.conf import settings

pkey_root = settings.PKEY_ROOT


class ResourceGroup(models.Model):
"""
Expand Down Expand Up @@ -99,14 +103,21 @@ class Tunnel(models.Model):
port = models.IntegerField('端口', default=0)
user = fields.EncryptedCharField(verbose_name='用户名', max_length=200, default='', blank=True, null=True)
password = fields.EncryptedCharField(verbose_name='密码', max_length=300, default='', blank=True, null=True)
pkey_path = fields.EncryptedCharField(verbose_name='密钥地址', max_length=300, default='', blank=True, null=True)
pkey = models.TextField(verbose_name="密钥", blank=True, null=True)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是否也采取加密存储的形式

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

密钥长度太长了,所以用了这个

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

加密组件也支持text,可以调整下

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嗯嗯 改成 EncryptedTextField 了

pkey_path = models.FileField(verbose_name="密钥地址", blank=True, null=True, upload_to='keys/')
pkey_password = fields.EncryptedCharField(verbose_name='密钥密码', max_length=300, default='', blank=True, null=True)
create_time = models.DateTimeField('创建时间', auto_now_add=True)
update_time = models.DateTimeField('更新时间', auto_now=True)

def __str__(self):
return self.tunnel_name

def short_pkey(self):
if len(str(self.pkey)) > 20:
return '{}...'.format(str(self.pkey)[0:19])
else:
return str(self.pkey)

class Meta:
managed = True
db_table = 'ssh_tunnel'
Expand Down Expand Up @@ -853,28 +864,3 @@ class Meta:
index_together = ('hostname_max', 'ts_min')
verbose_name = u'慢日志明细'
verbose_name_plural = u'慢日志明细'


class AuditEntry(models.Model):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这块应该是其他pr合并到主干的,注意冲突处理

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

原来的方式:将密钥上传至 archery 部署的服务器目录,如果是docker部署的还需要传到容器卷挂载的目录下,如 downloads logs这种目录里,然后在后台天上这个目录的绝对路径,当部署多实例的时候就无法使用了,而且使用起来也不是特别便捷
修改后:由后台页面的上传按钮直接上传到keys目录,然后读取pkey的内容写入数据库的pkey字段,实际上每次连接都是从数据库获取pkey来连接

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前使用这个功能的用户应该都是把密钥上传到了部署 archery 服务的服务器上,升级时需要把密钥下载到本地,更新版本后编辑对应条目,重新选择文件上传即可。
变更sql:
ALTER TABLE archery.ssh_tunnel
ADD COLUMN pkey longtext NULL AFTER password;

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前使用这个功能的用户应该都是把密钥上传到了部署 archery 服务的服务器上,升级时需要把密钥下载到本地,更新版本后编辑对应条目,重新选择文件上传即可。 变更sql: ALTER TABLE archery.ssh_tunnel ADD COLUMN pkey longtext NULL AFTER password;

辛苦增加到1.8.3的sql文件中

"""
登录审计日志
"""
user_id = models.IntegerField('用户ID')
user_name = models.CharField('用户名称', max_length=255, null=True)
action = models.CharField('动作', max_length=255)
ip = models.GenericIPAddressField('IP', null=True)
action_time = models.DateTimeField('操作时间', auto_now_add=True)

class Meta:
managed = True
db_table = 'audit_log'
verbose_name = u'审计日志'
verbose_name_plural = u'审计日志'

def __unicode__(self):
return '{0} - {1} - {2} - {3} - {4}'.format(self.user_id, self.user_name, self.ip
, self.action, self.action_time)

def __str__(self):
return '{0} - {1} - {2} - {3} - {4}'.format(self.user_id, self.user_name, self.ip
, self.action, self.action_time)
11 changes: 8 additions & 3 deletions sql/utils/ssh_tunnel.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,26 @@
"""
from sshtunnel import SSHTunnelForwarder
from paramiko import RSAKey
import io


class SSHConnection(object):
"""
ssh隧道连接类,用于映射ssh隧道端口到本地,连接结束时需要清理
"""
def __init__(self, host, port, tun_host, tun_port, tun_user, tun_password, pkey_path, pkey_password):
def __init__(self, host, port, tun_host, tun_port, tun_user, tun_password, pkey, pkey_password):
self.host = host
self.port = int(port)
self.tun_host = tun_host
self.tun_port = int(tun_port)
self.tun_user = tun_user
self.tun_password = tun_password

if pkey_path:
self.private_key = RSAKey.from_private_key_file(pkey_path, password=pkey_password)
if pkey:
private_key_file_obj = io.StringIO()
private_key_file_obj.write(pkey)
private_key_file_obj.seek(0)
self.private_key = RSAKey.from_private_key(private_key_file_obj, password=pkey_password)
self.server = SSHTunnelForwarder(
ssh_address_or_host=(self.tun_host, self.tun_port),
ssh_username=self.tun_user,
Expand Down
1 change: 1 addition & 0 deletions src/docker-compose/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ services:
- "./archery/downloads:/opt/archery/downloads"
- "./archery/sql/migrations:/opt/archery/sql/migrations"
- "./archery/logs:/opt/archery/logs"
- "./archery/keys:/opt/archery/keys"
entrypoint: "dockerize -wait tcp://mysql:3306 -wait tcp://redis:6379 -timeout 60s /opt/archery/src/docker/startup.sh"
environment:
NGINX_PORT: 9123