Source code for windows.configure_domain_plugin

from dns.dns_objects import DNSServer
from windows.base_objects import WindowsHost

from firewheel.control.experiment_graph import AbstractPlugin


[docs] class ConfigureDomain(AbstractPlugin): """ This plugin configures and schedules joining a domain and creating a domain controller. """ join_rel_time = -50
[docs] def run(self): """ Executes the domain configuration process. The logic is as follows: - Find all the domain controllers in the graph. - Schedule the DC and then find its experiment IP address. - Find all vertices (hosts) that belong to that domain and schedule them. """ dc_ip = {} for v in self.g.get_vertices(): if not v.is_decorated_by(WindowsHost): continue if ( getattr(v, "windows_domain", None) is not None and "controller" in v.windows_domain and v.windows_domain["controller"] ): self.set_dc_schedule(v) if getattr(v, "interfaces", None) is None: continue # If the address is not 0.0.0.0 or starts with 172 we assume it # is the experiment address. for interface in v.interfaces.interfaces: if not str(interface["address"]) == "0.0.0.0": # noqa: S104 dc_ip[v.windows_domain["id"]] = { "ip": interface["address"], "dns_name": v.windows_domain["name"], } # Needs a separate loop so we know all of the domain controllers. for host in self.g.get_vertices(): if not host.is_decorated_by(WindowsHost): continue if getattr(host, "windows_domain", None) is None: continue # Find each host that should join v's domain if ( "id" in host.windows_domain and host.windows_domain["id"] is not None and ( "controller" not in host.windows_domain or host.windows_domain["controller"] is None ) ): if host.windows_domain["id"] in dc_ip: self.set_host_schedule( host, dc_ip[host.windows_domain["id"]]["dns_name"], dc_ip[host.windows_domain["id"]]["ip"], ) else: print( 'Error: Domain controller not found for "%s"' % host.windows_domain["name"] )
[docs] def get_dns_address(self): """ Gets the IP address of the DNS Server in the experiment. Returns: str: The IP address of the DNS server, or None if not found. """ for v in self.g.get_vertices(): if v.is_decorated_by(DNSServer): dns = str(v.dns_data.get("dns_address")) if not dns: continue return dns
[docs] def set_dc_schedule(self, v): """ Adds to the domain controller's schedule. .. warning:: This method assumes that the Administrator password is originally set to: ``changeme&1`` and then changed to ``ChangeThisPassword#1``. Users should update this as needed. Args: v (Vertex): The vertex describing the domain controller. """ # Set up the default NETBIOS name if there isn't already one present. if "netbios" not in v.windows_domain or not v.windows_domain["netbios"]: v.windows_domain["netbios"] = v.windows_domain["name"].split(".")[0].upper() if v.windows_domain.get("upstream_dns"): upstream_dns = v.windows_domain["upstream_dns"] else: upstream_dns = self.get_dns_address() # We assume that the ``safe_mode_admin_password`` is ``changeme&1`` initially # Default usernames/passwords for in-experiment images are safe to hard-code admin_password = "changeme&1" # noqa: S105 domain_name = v.windows_domain["name"] arguments = "-domain %s -netBiosName %s -safe_mode_admin_password %s" % ( domain_name, v.windows_domain["netbios"], admin_password, ) if upstream_dns: arguments += " -upstream_dns %s" % upstream_dns # If we are using a snapshot version of the DC where things are already set up, we do not # need to configure it. try: if not v.snapshot: v.run_powershell( self.join_rel_time, "install_domain_controller.ps1", arguments ) except AttributeError: v.run_powershell( self.join_rel_time, "install_domain_controller.ps1", arguments ) arguments = "-username administrator -password ChangeThisPassword#1" v.run_powershell(self.join_rel_time + 1, "change_password.ps1", arguments) self.add_users(v)
[docs] def add_users(self, v): """ Adds users to the domain controller. Args: v (Vertex): The vertex describing the domain controller. """ if "users" not in v.windows_domain or not v.windows_domain["users"]: return users = "" for user in v.windows_domain["users"]: users += "%s %s\n" % (user["username"], user["password"]) if users: vm_resource = v.run_powershell( self.join_rel_time + 2, "add_activedirectory_users.ps1" ) vm_resource.add_dynamic_content("users.txt", users, "-Users")
[docs] def set_host_schedule(self, host, domain_dns_name, dc_ip): """ Adds to the hosts' schedule if it is part of a domain. .. warning:: This method assumes that the Administrator password is set to: ``ChangeThisPassword#1`` and will need to be updated by users. Args: host (Vertex): The vertex describing the host. domain_dns_name (str): The DNS name used to join the domain. dc_ip (str): The experiment IP address of the domain controller. """ arguments = ( "-domain_name %s -admin_user Administrator " "-admin_password ChangeThisPassword#1 -domain_controller_ip %s" % (domain_dns_name, dc_ip) ) if host.windows_domain.get("dns"): arguments += " -dns_ip {}".format(host.windows_domain["dns"]) host.run_powershell(self.join_rel_time, "join_windows_domain.ps1", arguments)
[docs] def fix_hostname(self, host): """ Ensures the hostname is set before joining the domain regardless of whether anyone else has tried to set the hostname. Args: host (Vertex): The vertex describing the host. """ host.add_vm_resource( self.join_rel_time - 1, "set_hostname.py", host.name.split(".")[0], None )