diff --git a/connect.py b/connect.py index 15f4c19b4..05d84dd8f 100644 --- a/connect.py +++ b/connect.py @@ -19,8 +19,9 @@ import struct, fcntl, signal, socket, select os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings' if django.get_version() != '1.6': django.setup() -from jumpserver.api import ServerError, User, Asset, AssetGroup, get_object, mkdir -from jumpserver.api import logger, Log, TtyLog +from jumpserver.api import ServerError, User, Asset, AssetGroup, get_object, mkdir, get_asset_info, get_role +from jumpserver.api import logger, Log, TtyLog, get_role_key +from jperm.perm_api import gen_resource, get_group_asset_perm, get_group_user_perm from jumpserver.settings import LOG_DIR from jperm.ansible_api import Command @@ -73,15 +74,15 @@ class Tty(object): A virtual tty class 一个虚拟终端类,实现连接ssh和记录日志,基类 """ - def __init__(self, username, asset_name): - self.username = username - self.asset_name = asset_name + def __init__(self, user, asset, role): + self.username = user.username + self.asset_name = asset.hostname self.ip = None self.port = 22 self.channel = None - #self.asset = get_object(Asset, name=asset_name) - #self.user = get_object(User, username=username) - self.role = None + self.asset = asset + self.user = user + self.role = role self.ssh = None self.connect_info = None self.login_type = 'ssh' @@ -287,7 +288,10 @@ class Tty(object): # 2. get 映射用户 # 3. get 映射用户的账号,密码或者key # self.connect_info = {'user': '', 'asset': '', 'ip': '', 'port': 0, 'role_name': '', 'role_pass': '', 'role_key': ''} - self.connect_info = {'user': 'a', 'asset': 'b', 'ip': '127.0.0.1', 'port': 22, 'role_name': 'root', 'role_pass': 'redhat', 'role_key': ''} + asset_info = get_asset_info(self.asset) + self.connect_info = {'user': self.user, 'asset': self.asset, 'ip': asset_info.get('ip'), + 'port': int(asset_info.get('port')), 'role_name': self.role.name, + 'role_pass': self.role.password, 'role_key': self.role.key_path} return self.connect_info def get_connection(self): @@ -301,7 +305,7 @@ class Tty(object): ssh.load_system_host_keys() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: - role_key = connect_info.get('role_key') + role_key = get_role_key(self.user, self.role) if role_key and os.path.isfile(role_key): try: ssh.connect(connect_info.get('ip'), @@ -469,6 +473,7 @@ class Nav(object): def __init__(self, user): self.user = user self.search_result = {} + self.user_perm = {} @staticmethod def print_nav(): @@ -499,7 +504,9 @@ class Nav(object): def search(self, str_r=''): gid_pattern = re.compile(r'^g\d+$') - user_asset_all = list(Asset.objects.all()) + if not self.user_perm: + self.user_perm = get_group_user_perm(self.user) + user_asset_all = self.user_perm.get('asset').keys() user_asset_search = [] if str_r: if gid_pattern.match(str_r): @@ -512,13 +519,15 @@ class Nav(object): user_asset_search = user_asset_all self.search_result = dict(zip(range(len(user_asset_search)), user_asset_search)) - - print '\033[32m[%-3s] %-15s %-15s %-5s %-5s %s \033[0m' % ('ID', 'AssetName', 'IP', 'Port', 'Role', 'Comment') + print '\033[32m[%-3s] %-15s %-15s %-5s %-10s %s \033[0m' % ('ID', 'AssetName', 'IP', 'Port', 'Role', 'Comment') for index, asset in self.search_result.items(): + asset_info = get_asset_info(asset) + role = [str(role.name) for role in self.user_perm.get('asset').get(asset).get('role')] if asset.comment: - print '[%-3s] %-15s %-15s %-5s %-5s %s' % (index, 'asset_name'+str(index), asset.ip, asset.port, 'role', asset.comment) + print '[%-3s] %-15s %-15s %-5s %-10s %s' % (index, asset.hostname, asset.ip, asset_info.get('port'), + role, asset.comment) else: - print '[%-3s] %-15s %-15s %-5s %-5s' % (index, 'asset_name'+str(index), asset.ip, asset.port, 'role') + print '[%-3s] %-15s %-15s %-5s %-10s' % (index, asset.hostname, asset.ip, asset_info.get('port'), role) print @staticmethod @@ -542,13 +551,11 @@ class Nav(object): if pattern == 'q': break else: - res = { - "group1": { - "hosts": [{"hostname": "127.0.0.1", "port": "22", "username": "lastimac", "password": "redhat"}, {"hostname": "192.168.244.129", "port": "22", "username": "root", "password": "redhat"}, {"hostname": "j", "port": "22", "username": "root", "password": "redhat"}], - "vars": {"var1": 'a', "var2": 'a'} - } - } + if not self.user_perm: + self.user_perm = get_group_user_perm(self.user) + res = gen_resource(self.user, perm=self.user_perm) cmd = Command(res) + logger.debug(res) for inv in cmd.inventory.get_hosts(pattern=pattern): print inv.name confirm_host = raw_input("\033[1;32mIs that [y/n]>:\033[0m ").strip() @@ -617,7 +624,28 @@ def main(): else: try: asset = nav.search_result[int(option)] - ssh_tty = SshTty('a', 'b') + roles = get_role(login_user, asset) + if len(roles) > 1: + role_check = dict(zip(range(len(roles)), roles)) + print role_check + for index, role in role_check.items(): + print "[%s] %s" % (index, role.name) + print "输入角色ID, q退出" + try: + role_index = raw_input("\033[1;32mID>:\033[0m ").strip() + if role_index == 'q': + continue + else: + role = role_check[int(role_index)] + except IndexError: + color_print('请输入正确ID', 'red') + continue + elif len(roles) == 1: + role = roles[0] + else: + color_print('没有映射用户', 'red') + continue + ssh_tty = SshTty(login_user, asset, role) ssh_tty.connect() except (KeyError, ValueError): color_print('请输入正确ID', 'red') diff --git a/jperm/ansible_api.py b/jperm/ansible_api.py index 2bf6973c1..1b0e5ce38 100644 --- a/jperm/ansible_api.py +++ b/jperm/ansible_api.py @@ -404,7 +404,7 @@ class Tasks(Command): result[key] = { "all_ip": setup.get("ansible_all_ipv4_addresses"), - "hostname" : setup.get("ansible_hostname" ), + "hostname" : setup.get("ansible_hostname"), "default_ip": setup.get("ansible_default_ipv4").get("address"), "default_mac": setup.get("ansible_default_ipv4").get("macaddress"), "product_name": setup.get("ansible_product_name"), diff --git a/jperm/perm_api.py b/jperm/perm_api.py index cc078db8b..856c13005 100644 --- a/jperm/perm_api.py +++ b/jperm/perm_api.py @@ -132,37 +132,30 @@ def get_group_asset_perm(ob): return perm -def gen_resource(ob): +def gen_resource(ob, perm=None): """ ob为用户或资产列表或资产queryset 生成MyInventory需要的 resource文件 """ res = [] if isinstance(ob, User): - perm = get_group_user_perm(ob) + if not perm: + perm = get_group_user_perm(ob) + for asset, asset_info in perm.get('asset').items(): - info = {'hostname': asset.hostname, 'ip': asset.ip, 'port': asset.port} + asset_info = get_asset_info(asset) + info = {'hostname': asset.hostname, 'ip': asset.ip, 'port': asset_info.get('port', 22)} try: - role = sorted(list(asset_info.get('role')))[0] + role = sorted(list(perm.get('asset').get(asset).get('role')))[0] except IndexError: continue info['username'] = role.name info['password'] = role.password - info['key_path'] = role.key_path + info['ssh_key'] = get_role_key(ob, role) res.append(info) elif isinstance(ob, (list, QuerySet)): - default = get_object(Setting, name='default') for asset in ob: - info = {'hostname': asset.hostname, 'ip': asset.ip} - if asset.use_default_auth: - if default: - info['port'] = default.default_port - info['username'] = default.default_user - info['password'] = default.default_password - info['ssh_key'] = default.default_pri_key_path - else: - info['port'] = asset.port - info['username'] = asset.username + info = get_asset_info(asset) res.append(info) return res diff --git a/jperm/utils.py b/jperm/utils.py index c8acff371..a6b3608ee 100644 --- a/jperm/utils.py +++ b/jperm/utils.py @@ -51,6 +51,7 @@ def gen_keys(): private_key = os.path.join(key_path_dir, 'id_rsa') public_key = os.path.join(key_path_dir, 'id_rsa.pub') key.write_private_key_file(private_key) + os.chmod(private_key, 0644) with open(public_key, 'w') as content_file: for data in [key.get_name(), diff --git a/jumpserver/api.py b/jumpserver/api.py index 198b11bf5..e787ad97b 100644 --- a/jumpserver/api.py +++ b/jumpserver/api.py @@ -9,19 +9,21 @@ import hashlib import datetime import random import subprocess -from settings import * +import json +import logging +from settings import * from django.core.paginator import Paginator, EmptyPage, InvalidPage from django.http import HttpResponse, Http404 from django.template import RequestContext from juser.models import User, UserGroup from jlog.models import Log, TtyLog from jasset.models import Asset, AssetGroup +from jperm.models import PermRule, PermRole +from jumpserver.models import Setting from django.http import HttpResponseRedirect from django.shortcuts import render_to_response from django.core.mail import send_mail -import json -import logging def set_log(level): @@ -45,11 +47,57 @@ def set_log(level): return logger_f -def chown(path, user, group='', ): +def get_asset_info(asset): + default = get_object(Setting, name='default') + info = {'hostname': asset.hostname, 'ip': asset.ip} + if asset.use_default_auth: + if default: + info['port'] = default.default_port + info['username'] = default.default_user + info['password'] = CRYPTOR.decrypt(default.default_password) + info['ssh_key'] = default.default_pri_key_path + else: + info['port'] = asset.port + info['username'] = asset.username + info['password'] = asset.password + + return info + + +def get_role(user, asset): + roles = [] + rules = PermRule.objects.filter(user=user, asset=asset) + for rule in rules: + roles.extend(list(rule.role.all())) + return roles + + +def get_role_key(user, role): + """ + 由于role的key的权限是所有人可以读的, ansible要求为600,所以拷贝一份到特殊目录 + :param user: + :param role: + :return: self key path + """ + user_role_key_dir = os.path.join(KEY_DIR, 'user') + user_role_key_path = os.path.join(user_role_key_dir, '%s_%s.pem' % (user.username, role.name)) + mkdir(user_role_key_dir, mode=777) + if not os.path.isfile(user_role_key_path): + with open(os.path.join(role.key_path, 'id_rsa')) as fk: + with open(user_role_key_path, 'w') as fu: + fu.write(fk.read()) + + print user_role_key_path, user.username + chown(user_role_key_path, user.username) + os.chmod(user_role_key_path, 0600) + return user_role_key_path + + +def chown(path, user, group=''): if not group: group = user - uid = pwd.getpwnam(user).pwd_uid - gid = pwd.getpwnam(group).gr_gid + uid = pwd.getpwnam(user).pw_uid + gid = pwd.getpwnam(group).pwd_gid os.chown(path, uid, gid) @@ -170,8 +218,7 @@ class PyCrypt(object): try: plain_text = cryptor.decrypt(a2b_hex(text)) except TypeError: - # raise ServerError('Decrypt password error, TYpe error.') - pass + raise ServerError('Decrypt password error, TYpe error.') return plain_text.rstrip('\0') @@ -406,7 +453,7 @@ def mkdir(dir_name, username='', mode=0755): """ if not os.path.isdir(dir_name): os.makedirs(dir_name) - os.chmod(dir_name, mode) + os.chmod(dir_name, mode) if username: chown(dir_name, username) diff --git a/juser/user_api.py b/juser/user_api.py index 13dfb7273..0248e5c6d 100644 --- a/juser/user_api.py +++ b/juser/user_api.py @@ -130,7 +130,7 @@ def gen_ssh_key(username, password='', """ logger.debug('生成ssh key, 并设置authorized_keys') private_key_file = os.path.join(key_dir, username) - mkdir(key_dir) + mkdir(key_dir, mode=777) if os.path.isfile(private_key_file): os.unlink(private_key_file) ret = bash('echo -e "y\n"|ssh-keygen -t rsa -f %s -b %s -P "%s"' % (private_key_file, length, password))