cookbooks/mu-master/recipes/default.rb
#
# Cookbook Name:: mu-master
# Recipe:: default
#
# Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
#
# Licensed under the BSD-3 license (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License in the root of the project or at
#
# http://egt-labs.com/mu/LICENSE.html
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# XXX this is nonsense if we're not in AWS
instance_id = node.name
search_domains = ["platform-mu"]
if node['ec2']
response = Net::HTTP.get_response(URI("http://169.254.169.254/latest/meta-data/instance-id"))
instance_id = response.body
search_domains = ["ec2.internal", "server.#{instance_id}.platform-mu", "platform-mu"]
elsif node['gce']
instance_id = node['gce']['instance']['name']
domains = node['gce']['instance']['hostname'].split(/\./)
domains.shift
search_domains = []
begin
search_domains << domains.join(".")+"."
domains.shift
end while domains.size > 1
search_domains << "google.internal."
end
if ::File.exist?("/etc/sudoers.d/waagent")
sshgroup = if node['platform'] == "centos"
"centos"
elsif node['platform'] == "ubuntu"
"ubuntu"
elsif node['platform'] == "windows"
"windows"
else
"root"
end
File.readlines("/etc/sudoers.d/waagent").each { |l|
l.chomp!
user = l.sub(/ .*/, '')
group sshgroup do
members user
append true
end
}
end
include_recipe 'mu-master::init'
include_recipe 'mu-master::basepackages'
include_recipe 'mu-master::firewall-holes'
include_recipe 'mu-master::ssl-certs'
include_recipe 'mu-master::vault'
include_recipe 'mu-tools::gcloud'
#include_recipe 'mu-master::kubectl'
master_ips = get_mu_master_ips
master_ips << "127.0.0.1"
master_ips.uniq!
master_ips.each { |host|
firewall_rule "Mu Master ports for self (#{host})" do
source "#{host}/32"
end
if host.match(/^(?:10\.|172\.(1[6789]|2[0-9]|3[01])\.|192\.168\.)/)
hostsfile_entry host do
hostname $MU_CFG['hostname']
aliases [node.name, "MU-MASTER"]
action :append
end
end
}
["#{$MU_CFG['installdir']}/etc/mu.yaml", "#{$MU_CFG['installdir']}/lib/Berksfile.lock"].each { |f|
file f do
mode 0644
end
}
if !node['update_nagios_only']
include_recipe 'chef-vault'
if $MU_CFG.has_key?('ldap')
if $MU_CFG['ldap']['type'] == "389 Directory Services" and Dir.exist?("/etc/dirsrv/slapd-#{$MU_CFG['hostname']}")
include_recipe 'mu-master::sssd'
elsif $MU_CFG['ldap']['type'] == "Active Directory"
node.normal['ad'] = {}
node.normal['ad']['computer_name'] = "MU-MASTER"
node.normal['ad']['node_class'] = "mumaster"
node.normal['ad']['node_type'] = "domain_node"
node.normal['ad']['domain_operation'] = "join"
node.normal['ad']['domain_name'] = $MU_CFG['ldap']['domain_name']
search_domains << node.normal['ad']['domain_name']
node.normal['ad']['netbios_name'] = $MU_CFG['ldap']['domain_netbios_name']
node.normal['ad']['dcs'] = $MU_CFG['ldap']['dcs']
node.normal['ad']['domain_join_vault'] = $MU_CFG['ldap']['join_creds']['vault']
node.normal['ad']['domain_join_item'] = $MU_CFG['ldap']['join_creds']['item']
node.normal['ad']['domain_join_username_field'] = $MU_CFG['ldap']['join_creds']['username_field']
node.normal['ad']['domain_join_password_field'] = $MU_CFG['ldap']['join_creds']['password_field']
if !node['application_attributes']['sshd_allow_groups'].match(/(^|\s)#{$MU_CFG['ldap']['user_group_name']}(\s|$)/i)
node.normal['application_attributes']['sshd_allow_groups'] = node['application_attributes']['sshd_allow_groups']+" "+$MU_CFG['ldap']['user_group_name'].downcase
end
node.save
include_recipe "mu-activedirectory::domain-node"
end
end
execute "set Mu Master's hostname" do
command "PATH=/bin:/usr/bin hostname #{$MU_CFG['hostname']}"
not_if "PATH=/bin:/usr/bin hostname | grep '^#{$MU_CFG['hostname']}$'"
end
file "/etc/hostname" do
content "#{$MU_CFG['hostname']}\n"
end
execute "updating hostname in /etc/sysconfig/network" do
command "sed -i 's/^HOSTNAME=.*/HOSTNAME=#{$MU_CFG['hostname']}.platform-mu/' /etc/sysconfig/network"
not_if "grep '^HOSTNAME=#{$MU_CFG['hostname']}.platform-mu'"
end
sudoer_line = "%#{$MU_CFG['ldap']['admin_group_name']} ALL=(ALL) NOPASSWD: ALL"
execute "echo '#{sudoer_line}' >> /etc/sudoers" do
not_if "grep '^#{sudoer_line}$' /etc/sudoers"
end
cookbook_file "/root/.vimrc" do
source "vimrc"
action :create_if_missing
end
file "/etc/profile.d/usr_local_bin.sh" do
content "export PATH=\"${PATH}:/usr/local/bin\"\n"
mode 0644
end
cookbook_file "/var/www/html/cloudamatic.png" do
source "cloudamatic.png"
mode 0644
end
package "nagios" do
action :remove
end
# The Nagios cookbook will only rebuild if the main executable is missing, so
# remove it if we've got a version bump coming down the pike.
execute "remove old Nagios binary" do
command "rm -f /usr/sbin/nagios"
not_if "/usr/sbin/nagios -V | grep 'Nagios Core #{node['nagios']['server']['version']}'"
end
end
include_recipe "mu-master::update_nagios_only"
if !node['update_nagios_only']
package %w(nagios-plugins-breeze nagios-plugins-by_ssh nagios-plugins-cluster nagios-plugins-dhcp nagios-plugins-dig nagios-plugins-disk nagios-plugins-disk_smb nagios-plugins-dns nagios-plugins-dummy nagios-plugins-file_age nagios-plugins-flexlm nagios-plugins-fping nagios-plugins-game nagios-plugins-hpjd nagios-plugins-http nagios-plugins-icmp nagios-plugins-ide_smart nagios-plugins-ircd nagios-plugins-ldap nagios-plugins-load nagios-plugins-log nagios-plugins-mailq nagios-plugins-mrtg nagios-plugins-mrtgtraf nagios-plugins-nagios nagios-plugins-nt nagios-plugins-ntp nagios-plugins-ntp-perl nagios-plugins-nwstat nagios-plugins-oracle nagios-plugins-overcr nagios-plugins-pgsql nagios-plugins-ping nagios-plugins-procs nagios-plugins-real nagios-plugins-rpc nagios-plugins-sensors nagios-plugins-smtp nagios-plugins-snmp nagios-plugins-ssh nagios-plugins-swap nagios-plugins-tcp nagios-plugins-time nagios-plugins-ups nagios-plugins-users nagios-plugins-wave) do
action :install
end
package %w(nagios-plugins-mysql) do
action :install
not_if { node['platform'] == 'amazon' }
end
directory "/home/nagios" do
owner "nagios"
mode 0711
end
directory "/home/nagios/.ssh" do
owner "nagios"
mode 0711
end
file "/home/nagios/.ssh/config" do
owner "nagios"
mode 0600
end
execute "dhclient-script" do
command "/sbin/dhclient-script"
action :nothing
end
service "network" do
action :nothing
end
if !$MU_CFG['public_address'].match(/^\d+\.\d+\.\d+\.\d+$/)
my_name = $MU_CFG['public_address'].dup
begin
search_domains << my_name.dup
my_name.sub!(/^[^\.]+?\./, "")
end while my_name.match(/\./)
end
template "/etc/dhcp/dhclient-eth0.conf" do
source "dhclient-eth0.conf.erb"
mode 0644
notifies :restart, "service[network]", :immediately unless %w{redhat centos}.include?(node['platform']) && node['platform_version'].to_i == 7
variables(
:search_domains => search_domains
)
end
svrname = node['hostname']
if !$MU_CFG['public_address'].match(/^\d+\.\d+\.\d+\.\d+$/)
svrname = $MU_CFG['public_address']
end
apache2_install "" do
docroot_dir "/var/www/html"
modules %w{status alias auth_basic authn_core authn_file authz_core authz_groupfile authz_host authz_user autoindex deflate dir env mime negotiation setenvif log_config logio unixd systemd headers proxy proxy_http rewrite ssl ldap authnz_ldap slotmem_shm}
end
package "mod_ldap"
# add stock .conf files to the mix where applicable
apache2_mod_proxy ""
apache2_mod_ldap ""
apache2_mod_cgid ""
apache2_mod_ssl ""
apache2_mod "php"
apache2_default_site "" do
action :enable
notifies :start, "service[apache2]", :delayed
end
# nagios keeps disabling the default vhost, so let's make another one
execute "Allow net connect to local for apache" do
command "/usr/sbin/setsebool -P httpd_can_network_connect on"
not_if "/usr/sbin/getsebool httpd_can_network_connect | grep -cim1 ^.*on$"
not_if "/sbin/getenforce | grep -cim1 disabled"
notifies :reload, "service[apache2]", :delayed
end
aliases = [node['fqdn'], node['hostname'], node['local_hostname'], node['local_ipv4'], node['public_hostname'], node['public_ipv4']]
if node['ec2']
aliases << node['ec2']['local_ipv4']
aliases << node['ec2']['local_hostname']
aliases << node['ec2']['public_ipv4']
aliases << node['ec2']['public_hostname']
end
aliases.uniq!
aliases.reject! { |a| a.nil? or a.empty? }
service 'apache2' do
extend Apache2::Cookbook::Helpers
service_name lazy { apache_platform_service_name }
supports restart: true, status: true, reload: true
action :enable
end
template '/etc/httpd/sites-available/mu_docs.conf' do
variables(
server_name: svrname,
server_port: "80",
server_aliases: aliases,
docroot: "/var/www/html"
)
cookbook 'mu-master'
source 'web_app.conf.erb'
notifies :reload, "service[apache2]", :delayed
end
apache2_site "mu_docs"
template '/etc/httpd/sites-available/https_proxy.conf' do
variables(
server_name: svrname,
server_port: "443",
server_aliases: aliases,
docroot: "/var/www/html"
)
cookbook 'mu-master'
source 'web_app.conf.erb'
notifies :reload, "service[apache2]", :delayed
end
apache2_site "https_proxy"
# configure the appropriate authentication method for the web server
case node['nagios']['server_auth_method']
when 'openid'
apache2_mod 'auth_openid'
when 'cas'
apache2_mod 'auth_cas'
end
# apache2_conf "nagios" do
# server_name svrname
# server_aliases aliases
# template 'nagios.conf.erb'
# cookbook "mu-master"
# notifies :reload, "service[apache2]", :delayed
# action :enable
# end
template '/etc/httpd/sites-available/nagios.conf' do
variables(
server_name: svrname,
server_port: "443",
server_aliases: aliases,
docroot: "/var/www/html"
)
cookbook 'mu-master'
source 'nagios.conf.erb'
notifies :reload, "service[apache2]", :delayed
end
apache2_site "nagios"
link "/etc/nagios3" do
to "/etc/nagios"
notifies :reload, "service[apache2]", :delayed
end
directory "/usr/lib64/nagios"
link "/usr/lib64/nagios/cgi-bin" do
to "/usr/lib/cgi-bin"
notifies :reload, "service[apache2]", :delayed
end
directory "/var/www/html/docs" do
owner "apache"
group "apache"
end
include_recipe "postfix"
# Use a real hostname for mail if we happen to have one assigned
if !MU.mu_public_addr.match(/^\d+\.\d+\.\d+\.\d+$/)
node.normal['postfix']['main']['myhostname'] = MU.mu_public_addr
node.normal['postfix']['main']['mydomain'] = MU.mu_public_addr.sub(/^.*?([^\.]+\.[^\.]+)$/, '\1')
node.normal['postfix']['main']['myorigin'] = MU.mu_public_addr.sub(/^.*?([^\.]+\.[^\.]+)$/, '\1')
else
node.normal['postfix']['main']['myhostname'] = $MU_CFG['hostname']
node.normal['postfix']['main']['mydomain'] = "platform-mu"
node.normal['postfix']['main']['myorigin'] = "platform-mu"
end
node.normal['postfix']['main']['inet_interfaces'] = "all"
node.save
mubranch=`cd #{MU_BASE}/lib && git rev-parse --abbrev-ref HEAD` # ~FC048
file "/var/www/html/index.html" do
owner "apache"
group "apache"
content "
<h1>This is a Mu Master server</h2>
<p>
<a href='https://#{MU.mu_public_addr}/nagios/'>Nagios monitoring GUI</a>
</p>
<p>
<a href='#{(mubranch.nil? or mubranch == "master" or mubranch.match(/detached from/)) ? "https://cloudamatic.gitlab.io/mu/" : "http://"+MU.mu_public_addr+"/docs"}'>Mu API documentation</a>
</p>
"
end
execute "echo 'devnull: /dev/null' >> /etc/aliases" do
not_if "grep '^devnull: /dev/null$' /etc/aliases"
end
directory "/Mu_Logs"
include_recipe "mu-tools::rsyslog"
cookbook_file "0-mu-log-server.conf" do
path "/etc/rsyslog.d/0-mu-log-server.conf"
notifies :restart, "service[rsyslog]", :delayed
end
file "0-mu-log-client.conf" do
path "/etc/rsyslog.d/0-mu-log-client.conf"
action :delete
notifies :restart, "service[rsyslog]", :delayed
end
execute "echo '/sbin/restorecon -r /home' >> /etc/rc.d/rc.local" do
not_if "grep '^/sbin/restorecon -r /home' /etc/rc.d/rc.local"
end
execute "echo '/opt/chef/bin/chef-client' >> /etc/rc.d/rc.local" do
not_if "grep ^/opt/chef/bin/chef-client /etc/rc.d/rc.local"
end
directory "/etc/pki/rsyslog"
["Mu_CA.pem", "rsyslog.crt", "rsyslog.key"].each { |file|
execute "install rsyslog SSL cert file #{file}" do
command "cp -f #{MU.mainDataDir}/ssl/#{file} /etc/pki/rsyslog/#{file} && chmod 400 /etc/pki/rsyslog/#{file}"
not_if "diff #{MU.mainDataDir}/ssl/#{file} /etc/pki/rsyslog/#{file}"
end
}
package "logrotate"
file "/etc/logrotate.d/Mu_audit_logs" do
content "/Mu_Logs/master.log
/Mu_Logs/nodes.log
{
sharedscripts
daily
delaycompress
postrotate
#{MU.myRoot}/bin/mu-aws-setup -u
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}
"
end
# XXX this will catch the occasional 4am groom. Need a way to graceful-restart momma.
file "/etc/logrotate.d/Mu_momma_cat" do
content "/var/log/mu-momma-cat.log
{
sharedscripts
size 100M
delaycompress
postrotate
/etc/init.d/mu-momma-cat restart
endscript
}
"
end
template "#{MU.etcDir}/mu.rc" do
source "mu.rc.erb"
mode 0644
owner "root"
variables(
:installdir => MU.installDir,
:repos => MU.muCfg['repos']
)
not_if { ::File.size?("#{MU.etcDir}/mu.rc") }
end
execute "source #{MU.etcDir}/mu.rc from root dotfiles" do
command "echo 'source #{MU.etcDir}/mu.rc' >> #{Etc.getpwnam("root").dir}/.bashrc"
not_if "test -f #{Etc.getpwnam("root").dir}/.bashrc && grep '^source #{MU.etcDir}/mu.rc$' #{Etc.getpwnam("root").dir}/.bashrc"
end
begin
resources('service[sshd]')
rescue Chef::Exceptions::ResourceNotFound
service "sshd" do
action [:enable, :start]
end
end
template "Mu Master /etc/ssh/sshd_config" do
path "/etc/ssh/sshd_config"
source "sshd_config.erb"
mode 0600
owner "root"
group "root"
notifies :reload, "service[sshd]", :delayed
cookbook "mu-tools"
end
cron "Sync client firewall allow rules" do
action :create
minute "10"
user "root"
command "#{MU.installDir}/bin/mu-firewall-allow-clients"
end
# XXX bug in Chef vault is current purging basically all clients
cron "Rotate vault keys and purge MIA clients" do
action :delete
minute "10"
hour "6"
user "root"
command "/opt/mu/bin/knife vault rotate all keys --clean-unknown-clients"
end
# TODO fine if we're SysV-compatible, but cover the other guys
template "/etc/init.d/mu-momma-cat" do
source "mu-momma-cat.erb"
variables(
:installdir => MU.installDir,
:ssl_key => $MU_CFG['ssl']['key'],
:ssl_cert => $MU_CFG['ssl']['cert'],
)
mode 0755
end
link "/opt/mu/bin/mu-momma-cat" do
to "/etc/init.d/mu-momma-cat"
end
service "mu-momma-cat" do
action [:enable, :start]
end
# This is stuff that can break for no damn reason at all
include_recipe "mu-tools::cloudinit"
begin
node.normal['mu']['user_map'] = MU::Master.listUsers
node.normal['mu']['user_list'] = []
node['mu']['user_map'].each_pair { |user, data|
node.normal['mu']['user_list'] << "#{user} (#{data['email']})"
}
node.save
file "/root/.gitconfig" do
content "[user]
name = #{node['mu']['user_map']['mu']['realname']}
email = #{node['mu']['user_map']['mu']['email']}
[push]
default = current
"
end
# XXX placeholder- we should have a "federal" flag which invokes
# mu-tools::apply_security, which has its own gov-compliant /etc/issue.net
# The one that ships on CentOS images seems incorrect, so nuking it for now
file "/etc/issue.net" do
action :delete
end
node['mu']['user_map'].each_pair { |mu_user, data|
execute "echo '#{mu_user}: #{data['email']}' >> /etc/aliases" do
not_if "grep '^#{mu_user}: #{data['email']}$' /etc/aliases"
end
}
file "/etc/motd" do
content "
*******************************************************************************
This is a Mu Master server. Mu is installed in #{MU.myRoot}.
Nagios monitoring GUI: https://#{MU.mu_public_addr}/nagios/
Mu API documentation: #{(mubranch.nil? or mubranch == "master" or mubranch.match(/detached from/)) ? "https://cloudamatic.gitlab.io/mu/" : "http://"+MU.mu_public_addr+"/docs"}
Mu metadata are stored in #{MU.mainDataDir}
Users: #{node['mu']['user_list'].join(", ")}
*******************************************************************************
"
end
rescue Exception
log "Can't list users" do
message "Doesn't seem like I can list available users. Hopefully this is initial setup."
level :warn
end
end
end