# # Cookbook Name:: mu-activedirectory # Provider:: domain_node # # Copyright 2015, eGlobalTech, # # All rights reserved - Do Not Redistribute # require 'chef/mixin/shell_out' include Chef::Mixin::ShellOut include Chef::Mixin::PowershellOut def whyrun_supported? true end action :add do case node['platform'] when "windows" set_client_dns elevate_remote_access join_domain_windows # set_computer_name(join_domain_creds) when platform_family?('rhel') install_ad_client_packages join_domain_linux else Chef::Log.info("Unsupported platform #{node['platform']}") end end action :remove do case node['platform'] when "windows" unjoin_domain_windows when platform_family?('rhel') unjoin_domain_linux else Chef::Log.info("Unsupported platform #{node['platform']}") end end # def load_current_resource # @current_resource = @new_resource.dup # end def join_domain_creds "(New-Object System.Management.Automation.PSCredential('#{new_resource.netbios_name}\\#{new_resource.join_user}', (ConvertTo-SecureString '#{new_resource.join_password}' -AsPlainText -Force)))" end def join_domain_windows unless in_domain? # This will allow us to add a new computer account to the correct OU so the right group policy is applied new_name = nil new_name = "-NewName #{new_resource.computer_name}" if node['hostname'].downcase != new_resource.computer_name.downcase if new_resource.computer_ou code = "Add-Computer -DomainName #{new_resource.dns_name} -Credential#{join_domain_creds} #{new_name} -OUPath '#{new_resource.computer_ou}' -PassThru -Verbose -Force" else code = "Add-Computer -DomainName #{new_resource.dns_name} -Credential#{join_domain_creds} #{new_name} -PassThru -Verbose -Force" end Chef::Log.info("Joining #{new_resource.computer_name} node to #{new_resource.dns_name} domain") cmd = powershell_out(code) if cmd.stdout.include?("HasSucceeded") && cmd.stdout.include?("True") Chef::Log.info("Domain Join was successful") execute "kill ssh for reboot" do command "Taskkill /im sshd.exe /f /t" returns [0, 128] action :nothing end reboot "Successfully joined #{new_resource.computer_name} to #{new_resource.dns_name} domain" do action :reboot_now reason "Successfully joined #{new_resource.computer_name} to #{new_resource.dns_name} domain" notifies :run, "execute[kill ssh for reboot]", :immediately end kill_ssh elsif cmd.stdout.include?("HasSucceeded") && cmd.stdout.include?("False") Chef::Log.fatal("Domain Join was NOT successful") Chef::Log.fatal("Domain join stderr #{cmd.stderr}") Chef::Application.fatal!("Failed to join #{new_resource.computer_name} to #{new_resource.dns_name} domain") else Chef::Log.fatal("Something went wrong during domain join. Command to join domain was: #{code}") Chef::Log.fatal("Domain join stderr #{cmd.stderr}") Chef::Application.fatal!("Failed to join #{new_resource.computer_name} to #{new_resource.dns_name} domain") end end end def set_client_dns cmd = powershell_out("Get-NetAdapter | Set-DnsClientServerAddress -ServerAddresses #{new_resource.dc_ips.join(", ")}") Chef::Log.info("Set DNS addresses to #{new_resource.dc_ips.join(", ")}") end def unjoin_domain_windows if in_domain? Chef::Log.info("Removing #{new_resource.computer_name} node from #{new_resource.dns_name} domain") cmd = powershell_out("Remove-Computer -UnjoinDomaincredential #{join_domain_creds} -Passthru -Verbose -Restart -Force") Chef::Application.fatal!("Failed to remove #{new_resource.computer_name} from #{new_resource.dns_name} domain") unless cmd.exitstatus == 0 reboot "Removed #{new_resource.computer_name} from #{new_resource.dns_name} domain" do action :reboot_now reason "Removed #{new_resource.computer_name} from #{new_resource.dns_name} domain" end kill_ssh end end def join_domain_linux set_selinux_policies config_ssh_ntp_dns create_pam_winbind_directories pam_winbind_lib configure_winbind_kerberos_authentication directory "#{node['ad']['samba_conf_dir']}/includes" do mode 0755 end template "#{node['ad']['samba_conf_dir']}/smb.conf" do source "smb.conf.erb" owner "root" group "root" mode 0644 notifies :restart, "service[smb]", :delayed notifies :restart, "service[winbind]", :delayed variables( :domain_name => new_resource.dns_name, :dcs => new_resource.dc_names, :computer_name => new_resource.computer_name, :netbios_name => new_resource.netbios_name, :include_file => "#{node['ad']['samba_conf_dir']}/includes/#{node['ad']['samba_include_file']}" ) end # We no longer user Winbind to integrate with AD, but Samba relies on it, so # we run it on top of adcli's Kerberos creds so that you can still use SMB. execute "Join Winbind to domain #{new_resource.dns_name}" do command "( echo '#{new_resource.join_password}' | kinit #{new_resource.join_user} ) ; net ads join #{new_resource.dns_name.downcase} -k -d 4" sensitive true not_if "net ads testjoin -k | grep OK" notifies :restart, "service[winbind]", :delayed end end def install_ad_client_packages %w{samba4-winbind authconfig krb5-workstation pam_krb5 samba4-common oddjob-mkhomedir samba4-winbind-clients samba4-winbind-krb5-locator krb5-devel}.each { |pkg| package pkg } if %w{centos redhat}.include?(node['platform']) && node['platform_version'].to_i == 7 # execute "systemctl enable smb.service " package "samba" service "smb" do action :enable end end end def set_selinux_policies # Disable SELinux. Need to test if existing policies below work without having to disabling SELinux. execute "setenforce 0" # Add Policies to SELinux to allow winbind and ssh to work correctly. TO DO - TEST THIS %w{winbindpol sshd_pol}.each { |policy_file| %w{te pp}.each { |ext| cookbook_file "#{Chef::Config[:file_cache_path]}/#{policy_file}.#{ext}" do source "#{policy_file}.#{ext}" end } execute "semodule -i #{policy_file}.pp" do cwd Chef::Config[:file_cache_path] not_if "semodule -l | grep #{policy_file}" notifies :restart, "service[winbind]", :immediately notifies :restart, "service[sshd]", :immediately end } execute "setsebool -P ssh_chroot_rw_homedirs 1" do not_if "grep ssh_chroot_rw_homedirs=1 /etc/selinux/targeted/modules/active/booleans.local" end end def config_ssh_ntp_dns template "mu-activedirectory /etc/ntp.conf" do path "/etc/ntp.conf" source "ntp.conf.erb" owner "root" group "root" mode 0644 variables( :dcs => new_resource.dc_names ) end template "mu-activedirectory /etc/ssh/sshd_config" do path "/etc/ssh/sshd_config" source "sshd_config.erb" owner "root" group "root" cookbook "mu-tools" mode 0600 notifies :restart, "service[sshd]", :immediately # variables( # :allow_password_auth => new_resource.allow_password_auth, # :allow_groups => new_resource.allow_groups, # :sftp_only_group => new_resource.sftp_only_group, # :sftp_chroot => new_resource.sftp_chroot # ) end end def create_pam_winbind_directories directory "/home/#{new_resource.dns_name}" do owner "root" group "root" mode 0755 not_if { ::File.exists?("/home/#{new_resource.dns_name}") or ::File.symlink?("/home/#{new_resource.dns_name}")} end %w[/run /run/samba /run/samba/winbindd].each { |path| directory path do owner "root" group "root" mode 0755 end } directory "/etc/skel" do owner "root" group "root" mode 0700 end %w{.bashrc .bash_profile .bash_logout}.each { |file| file "/etc/skel/#{file}" do owner "root" group "root" mode 0600 end } end def pam_winbind_lib link "/lib64/security/pam_winbind.so" do to "/usr/lib64/security/pam_winbind.so" end execute "echo 'session optional pam_umask.so umask=0077' >> /etc/pam.d/sshd" do not_if "grep pam_umask.so /etc/pam.d/sshd" end end def configure_winbind_kerberos_authentication # Because authconfig doesn't always update those # %w{password-auth system-auth}.each { |file| # cookbook_file "/etc/pam.d/#{file}" do # source file # manage_symlink_source true # end # } end def unjoin_domain_linux execute "Unjoin domain #{new_resource.dns_name}" do command "net ads leave -U #{new_resource.join_user}%#{new_resource.join_password}" sensitive true only_if "net ads testjoin | grep OK" end end