diff --git a/apps/ops/models.py b/apps/ops/models.py index 8ea121d64..3f0f0205d 100644 --- a/apps/ops/models.py +++ b/apps/ops/models.py @@ -4,7 +4,9 @@ from __future__ import unicode_literals, absolute_import import logging import json +from jinja2 import Template from django.db import models +from assets.models import Asset from django.utils.translation import ugettext_lazy as _ @@ -220,47 +222,195 @@ class HostAlia(models.Model): class UserAlia(models.Model): - name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Host_Alias')) - host_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) + name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('User_Alias')) + user_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) def __unicode__(self): return self.name class CmdAlia(models.Model): - name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Host_Alias')) - host_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) + name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Command_Alias')) + cmd_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) def __unicode__(self): return self.name class RunasAlia(models.Model): - name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Host_Alias')) - host_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) + name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Runas_Alias')) + runas_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) def __unicode__(self): return self.name class Privilege(models.Model): - name = models.CharField(max_length=128, blank=True, null=True, unique=True, verbose_name=_('Host_Alias')) - host_items = models.TextField(blank=True, null=True, verbose_name=_('Host_Items')) + user = models.ForeignKey(UserAlia, blank=True, null=True, related_name='privileges') + host = models.ForeignKey(HostAlia, blank=True, null=True, related_name='privileges') + runas = models.ForeignKey(RunasAlia, blank=True, null=True, related_name='privileges') + command = models.ForeignKey(CmdAlia, blank=True, null=True, related_name='privileges') + nopassword = models.BooleanField(default=True, verbose_name=_('Is_NoPassword')) def __unicode__(self): - return self.name + return "[%s %s %s %s %s]" % (self.user.name, + self.host.name, + self.runas.name, + self.command.name, + self.nopassword) + + def to_tuple(self): + return self.user.name, self.host.name, self.runas.name, self.command.name, self.nopassword + + +class Extra_conf(models.Model): + line = models.TextField(blank=True, null=True, verbose_name=_('Extra_Item')) + + def __unicode__(self): + return self.line class Sudo(models.Model): - host_alias = models.ManyToManyField(HostAlia, related_name='sudos', blank=True, null=True) - user_alias = models.ManyToManyField(UserAlia, related_name='sudos', blank=True, null=True) - cmd_alias = models.ManyToManyField(CmdAlia, related_name='sudos', blank=True, null=True) - runas_alias = models.ManyToManyField(RunasAlia, related_name='sudos', blank=True, null=True) - privileges = models.ManyToManyField(Privilege, related_name='sudos', blank=True, null=True) + """ + Sudo配置文件对象, 用于配置sudo的配置文件 + + :param user_alias: {: } + :param cmnd_alias: {: } + :param host_alias: {: } + :param runas_alias: {: } + :param extra_lines: [, ,...] + :param privileges: [(user, host, runas, command, nopassword),] + """ + + asset = models.ForeignKey(Asset, null=True, blank=True, related_name='sudos') + host_alias = models.ManyToManyField(HostAlia, related_name='sudos', blank=True) + user_alias = models.ManyToManyField(UserAlia, related_name='sudos', blank=True) + cmnd_alias = models.ManyToManyField(CmdAlia, related_name='sudos', blank=True) + runas_alias = models.ManyToManyField(RunasAlia, related_name='sudos', blank=True) + extra_lines = models.ManyToManyField(Extra_conf, related_name='sudos', blank=True) + privilege_items = models.ManyToManyField(Privilege, related_name='sudos', blank=True) + + @property + def users(self): + ret = {} + for user in self.user_alias.all(): + ret[user.name] = user.user_items.split(',') + return ret + + @property + def commands(self): + ret = {} + for cmd in self.cmnd_alias.all(): + ret[cmd.name] = cmd.cmd_items.split(',') + return ret + + @property + def hosts(self): + ret = {} + for host in self.host_alias.all(): + ret[host.name] = host.host_items.split(',') + return ret + + @property + def runas(self): + ret = {} + for runas in self.runas_alias.all(): + ret[runas.name] = runas.runas_items.split(',') + return ret + + @property + def extras(self): + return [extra.line for extra in self.extra_lines.all()] + + @property + def privileges(self): + return [privilege.to_tuple() for privilege in self.privilege_items.all()] @property def content(self): - pass + template = Template(self.__sudoers_jinja2_tmp__) + context = {"User_Alias": self.users, + "Cmnd_Alias": self.commands, + "Host_Alias": self.hosts, + "Runas_Alias": self.runas, + "Extra_Lines": self.extras, + "privileges": self.privileges} + return template.render(context) + + @property + def __sudoers_jinja2_tmp__(self): + return """# management by JumpServer +# This file MUST be edited with the 'visudo' command as root. +# +# Please consider adding local content in /etc/sudoers.d/ instead of +# directly modifying this file. +# +# See the man page for details on how to write a sudoers file. +# +Defaults env_reset +Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +# JumpServer Generate Other Configure is here +{% if Extra_Lines -%} +{% for line in Extra_Lines -%} +{{ line }} +{% endfor %} +{%- endif %} + +# Host alias specification +{% if Host_Alias -%} +{% for flag, items in Host_Alias.iteritems() -%} +Host_Alias {{ flag }} = {{ items|join(', ') }} +{% endfor %} +{%- endif %} + +# User alias specification +{% if User_Alias -%} +{% for flag, items in User_Alias.iteritems() -%} +User_Alias {{ flag }} = {{ items|join(', ') }} +{% endfor %} +{%- endif %} + + +# Cmnd alias specification +{% if Cmnd_Alias -%} +{% for flag, items in Cmnd_Alias.iteritems() -%} +Cmnd_Alias {{ flag }} = {{ items|join(', ') }} +{% endfor %} +{%- endif %} + +# Run as alias specification +{% if Runas_Alias -%} +{% for flag, items in Runas_Alias.iteritems() -%} +Runas_Alias {{ flag }} = {{ items|join(', ') }} +{% endfor %} +{%- endif %} + +# User privilege specification +root ALL=(ALL:ALL) ALL + +# JumpServer Generate User privilege is here. +# Note privileges is a tuple list like [(user, host, runas, command, nopassword),] +{% if privileges -%} +{% for User_Flag, Host_Flag, Runas_Flag, Command_Flag, NopassWord in privileges -%} +{% if NopassWord -%} +{{ User_Flag }} {{ Host_Flag }}=({{ Runas_Flag }}) NOPASSWD: {{ Command_Flag }} +{%- else -%} +{{ User_Flag }} {{ Host_Flag }}=({{ Runas_Flag }}) {{ Command_Flag }} +{%- endif %} +{% endfor %} +{%- endif %} + +# Members of the admin group may gain root privileges +%admin ALL=(ALL) ALL + +# Allow members of group sudo to execute any command +%sudo ALL=(ALL:ALL) ALL + +# See sudoers(5) for more information on "#include" directives: + +#includedir /etc/sudoers.d +""" diff --git a/apps/ops/sudo_api.py b/apps/ops/sudo_api.py deleted file mode 100644 index 331371d10..000000000 --- a/apps/ops/sudo_api.py +++ /dev/null @@ -1,147 +0,0 @@ -# ~*~ coding: utf-8 ~*~ -from __future__ import unicode_literals - -""" -该模块主要用于提供一个统一的api来管理sudo的配置文件, -支持管理的系统包括: ubuntu(/etc/sudoers) - -因为sudoers配置文件很危险,所以采用生成临时文件, 验证ok后, 进行替换来变更 -""" - - -from jinja2 import Template - - -__sudoers_tmp__ = """# management by JumpServer -# This file MUST be edited with the 'visudo' command as root. -# -# Please consider adding local content in /etc/sudoers.d/ instead of -# directly modifying this file. -# -# See the man page for details on how to write a sudoers file. -# -Defaults env_reset -Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -# JumpServer Generate Other Configure is here -{% if Extra_Lines -%} -{% for line in Extra_Lines -%} -{{ line }} -{% endfor %} -{%- endif %} - -# Host alias specification -{% if Host_Alias -%} -{% for flag, items in Host_Alias.iteritems() -%} -Host_Alias {{ flag }} = {{ items|join(', ') }} -{% endfor %} -{%- endif %} - -# User alias specification -{% if User_Alias -%} -{% for flag, items in User_Alias.iteritems() -%} -User_Alias {{ flag }} = {{ items|join(', ') }} -{% endfor %} -{%- endif %} - - -# Cmnd alias specification -{% if Cmnd_Alias -%} -{% for flag, items in Cmnd_Alias.iteritems() -%} -Cmnd_Alias {{ flag }} = {{ items|join(', ') }} -{% endfor %} -{%- endif %} - -# Run as alias specification -{% if Runas_Alias -%} -{% for flag, items in Runas_Alias.iteritems() -%} -Runas_Alias {{ flag }} = {{ items|join(', ') }} -{% endfor %} -{%- endif %} - -# User privilege specification -root ALL=(ALL:ALL) ALL - -# JumpServer Generate User privilege is here. -# Note privileges is a tuple list like [(user, host, runas, command, nopassword),] -{% if privileges -%} -{% for User_Flag, Host_Flag, Runas_Flag, Command_Flag, NopassWord in privileges -%} -{% if NopassWord -%} -{{ User_Flag }} {{ Host_Flag }}=({{ Runas_Flag }}) NOPASSWD: {{ Command_Flag }} -{%- else -%} -{{ User_Flag }} {{ Host_Flag }}=({{ Runas_Flag }}) {{ Command_Flag }} -{%- endif %} -{% endfor %} -{%- endif %} - -# Members of the admin group may gain root privileges -%admin ALL=(ALL) ALL - -# Allow members of group sudo to execute any command -%sudo ALL=(ALL:ALL) ALL - -# See sudoers(5) for more information on "#include" directives: - -#includedir /etc/sudoers.d -""" - - -class Sudo(object): - """ - Sudo配置文件API, 用于配置sudo的配置文件 - - :param user_alias: {: } - :param cmnd_alias: {: } - :param host_alias: {: } - :param runas_alias: {: } - :param extra_lines: [, ,...] - :param privileges: [(user, host, runas, command, nopassword),] - """ - - def __init__(self, user_alias, cmnd_alias, privileges, host_alias=None, runas_alias=None, extra_lines=None): - self.extras = extra_lines - self.users = user_alias - self.commands = cmnd_alias - self.hosts = host_alias - self.runas = runas_alias - self.privileges = privileges - - def get_tmp(self): - template = Template(__sudoers_tmp__) - context = {"User_Alias": self.users, - "Cmnd_Alias": self.commands, - "Host_Alias": self.hosts, - "Runas_Alias": self.runas, - "Extra_Lines": self.extras, - "privileges": self.privileges} - return template.render(context) - - def gen_privileges(self): - pass - - def get_sudo_from_db(self): - pass - - def check_users(self): - pass - - def check_commands(self): - pass - - def check_hosts(self): - pass - - def check_runas(self): - pass - - def check_privileges(self): - pass - - -if __name__ == "__main__": - users = {"a": ['host1, host2'], "b": ["host3", "host4"]} - commands = {"dba": ["bin/bash"], "dev": ["bin/bash"]} - privileges = [("a", "ALL", "root", "dba", True), ("a", "ALL", "root", "dba", False)] - sudo = Sudo(users, commands, privileges, extra_lines=['aaaaaasf sdfasdf', 'bbbbb sfdsdf']) - print sudo.get_tmp() -