cloud-mu 3.6.10 → 3.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/Berksfile +2 -3
  3. data/Berksfile.lock +11 -14
  4. data/bin/mu-aws-setup +16 -4
  5. data/bin/mu-configure +2 -1
  6. data/cloud-mu.gemspec +2 -2
  7. data/cookbooks/mu-firewall/Berksfile +1 -1
  8. data/cookbooks/mu-firewall/attributes/default.rb +2 -2
  9. data/cookbooks/mu-firewall/metadata.rb +3 -3
  10. data/cookbooks/mu-firewall/recipes/default.rb +11 -2
  11. data/cookbooks/mu-master/Berksfile +1 -1
  12. data/cookbooks/mu-master/attributes/default.rb +14 -1
  13. data/cookbooks/mu-master/files/default/389ds-perl/ASDialogs.pm +173 -0
  14. data/cookbooks/mu-master/files/default/389ds-perl/AdminMigration.pm +569 -0
  15. data/cookbooks/mu-master/files/default/389ds-perl/AdminServer.pm +952 -0
  16. data/cookbooks/mu-master/files/default/389ds-perl/AdminUtil.pm +983 -0
  17. data/cookbooks/mu-master/files/default/389ds-perl/ConfigDSDialogs.pm +449 -0
  18. data/cookbooks/mu-master/files/default/389ds-perl/DSCreate.pm +1551 -0
  19. data/cookbooks/mu-master/files/default/389ds-perl/DSDialogs.pm +233 -0
  20. data/cookbooks/mu-master/files/default/389ds-perl/DSMigration.pm +1175 -0
  21. data/cookbooks/mu-master/files/default/389ds-perl/DSUpdate.pm +534 -0
  22. data/cookbooks/mu-master/files/default/389ds-perl/DSUpdateDialogs.pm +152 -0
  23. data/cookbooks/mu-master/files/default/389ds-perl/DSUtil.pm +1710 -0
  24. data/cookbooks/mu-master/files/default/389ds-perl/Dialog.pm +249 -0
  25. data/cookbooks/mu-master/files/default/389ds-perl/DialogManager.pm +212 -0
  26. data/cookbooks/mu-master/files/default/389ds-perl/FileConn.pm +461 -0
  27. data/cookbooks/mu-master/files/default/389ds-perl/Inf.pm +268 -0
  28. data/cookbooks/mu-master/files/default/389ds-perl/Migration.pm +327 -0
  29. data/cookbooks/mu-master/files/default/389ds-perl/RegDSDialogs.pm +94 -0
  30. data/cookbooks/mu-master/files/default/389ds-perl/Resource.pm +137 -0
  31. data/cookbooks/mu-master/files/default/389ds-perl/Setup.pm +240 -0
  32. data/cookbooks/mu-master/files/default/389ds-perl/SetupDialogs.pm +243 -0
  33. data/cookbooks/mu-master/files/default/389ds-perl/SetupLog.pm +82 -0
  34. data/cookbooks/mu-master/files/default/setCertName.ldif +4 -0
  35. data/cookbooks/mu-master/libraries/mu.rb +2 -2
  36. data/cookbooks/mu-master/metadata.rb +1 -1
  37. data/cookbooks/mu-master/recipes/389ds.rb +71 -32
  38. data/cookbooks/mu-master/recipes/basepackages.rb +5 -0
  39. data/cookbooks/mu-master/recipes/default.rb +16 -5
  40. data/cookbooks/mu-master/recipes/init.rb +36 -3
  41. data/cookbooks/mu-master/recipes/ssl-certs.rb +6 -0
  42. data/cookbooks/mu-master/recipes/sssd.rb +85 -62
  43. data/cookbooks/mu-master/recipes/update_nagios_only.rb +7 -1
  44. data/cookbooks/mu-master/templates/default/389-directory-setup.inf.erb +11 -26
  45. data/cookbooks/mu-master/templates/default/sssd.conf.erb +18 -8
  46. data/cookbooks/mu-tools/files/default/Mu_CA.pem +33 -0
  47. data/cookbooks/mu-tools/metadata.rb +0 -1
  48. data/cookbooks/mu-tools/recipes/set_local_fw.rb +7 -1
  49. data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +5 -1
  50. data/cookbooks/nagios/CHANGELOG.md +679 -0
  51. data/cookbooks/nagios/LICENSE +201 -0
  52. data/cookbooks/nagios/README.md +340 -0
  53. data/cookbooks/nagios/attributes/config.rb +163 -0
  54. data/cookbooks/nagios/attributes/default.rb +204 -0
  55. data/cookbooks/nagios/libraries/base.rb +311 -0
  56. data/cookbooks/nagios/libraries/command.rb +68 -0
  57. data/cookbooks/nagios/libraries/contact.rb +229 -0
  58. data/cookbooks/nagios/libraries/contactgroup.rb +111 -0
  59. data/cookbooks/{firewall/recipes/disable_firewall.rb → nagios/libraries/custom_option.rb} +20 -7
  60. data/cookbooks/nagios/libraries/data_bag_helper.rb +23 -0
  61. data/cookbooks/nagios/libraries/default.rb +90 -0
  62. data/cookbooks/nagios/libraries/helpers.rb +229 -0
  63. data/cookbooks/nagios/libraries/host.rb +410 -0
  64. data/cookbooks/nagios/libraries/hostdependency.rb +178 -0
  65. data/cookbooks/nagios/libraries/hostescalation.rb +170 -0
  66. data/cookbooks/nagios/libraries/hostgroup.rb +117 -0
  67. data/cookbooks/nagios/libraries/nagios.rb +277 -0
  68. data/cookbooks/nagios/libraries/resource.rb +59 -0
  69. data/cookbooks/nagios/libraries/service.rb +449 -0
  70. data/cookbooks/nagios/libraries/servicedependency.rb +213 -0
  71. data/cookbooks/nagios/libraries/serviceescalation.rb +193 -0
  72. data/cookbooks/nagios/libraries/servicegroup.rb +142 -0
  73. data/cookbooks/nagios/libraries/timeperiod.rb +159 -0
  74. data/cookbooks/nagios/libraries/users_helper.rb +54 -0
  75. data/cookbooks/nagios/metadata.json +44 -0
  76. data/cookbooks/nagios/metadata.rb +22 -0
  77. data/cookbooks/nagios/recipes/_load_databag_config.rb +153 -0
  78. data/cookbooks/nagios/recipes/_load_default_config.rb +241 -0
  79. data/cookbooks/nagios/recipes/apache.rb +114 -0
  80. data/cookbooks/nagios/recipes/default.rb +41 -0
  81. data/cookbooks/nagios/recipes/nginx.rb +114 -0
  82. data/cookbooks/nagios/recipes/pagerduty.rb +95 -0
  83. data/cookbooks/nagios/recipes/server.rb +182 -0
  84. data/cookbooks/nagios/recipes/server_package.rb +85 -0
  85. data/cookbooks/nagios/recipes/server_source.rb +137 -0
  86. data/cookbooks/nagios/resources/command.rb +34 -0
  87. data/cookbooks/nagios/resources/conf.rb +52 -0
  88. data/cookbooks/nagios/resources/contact.rb +34 -0
  89. data/cookbooks/nagios/resources/contactgroup.rb +35 -0
  90. data/cookbooks/nagios/resources/host.rb +35 -0
  91. data/cookbooks/nagios/resources/hostdependency.rb +35 -0
  92. data/cookbooks/nagios/resources/hostescalation.rb +36 -0
  93. data/cookbooks/nagios/resources/hostgroup.rb +35 -0
  94. data/cookbooks/nagios/resources/resource.rb +34 -0
  95. data/cookbooks/nagios/resources/service.rb +35 -0
  96. data/cookbooks/nagios/resources/servicedependency.rb +35 -0
  97. data/cookbooks/nagios/resources/serviceescalation.rb +35 -0
  98. data/cookbooks/nagios/resources/servicegroup.rb +35 -0
  99. data/cookbooks/nagios/resources/timeperiod.rb +35 -0
  100. data/cookbooks/nagios/templates/apache2.conf.erb +102 -0
  101. data/cookbooks/nagios/templates/cgi.cfg.erb +266 -0
  102. data/cookbooks/nagios/templates/commands.cfg.erb +13 -0
  103. data/cookbooks/nagios/templates/contacts.cfg.erb +37 -0
  104. data/cookbooks/nagios/templates/hostgroups.cfg.erb +25 -0
  105. data/cookbooks/nagios/templates/hosts.cfg.erb +15 -0
  106. data/cookbooks/nagios/templates/htpasswd.users.erb +6 -0
  107. data/cookbooks/nagios/templates/nagios.cfg.erb +22 -0
  108. data/cookbooks/nagios/templates/nginx.conf.erb +80 -0
  109. data/cookbooks/nagios/templates/pagerduty.cgi.erb +185 -0
  110. data/cookbooks/nagios/templates/resource.cfg.erb +27 -0
  111. data/cookbooks/nagios/templates/servicedependencies.cfg.erb +15 -0
  112. data/cookbooks/nagios/templates/servicegroups.cfg.erb +14 -0
  113. data/cookbooks/nagios/templates/services.cfg.erb +14 -0
  114. data/cookbooks/nagios/templates/spawn-fcgi.erb +10 -0
  115. data/cookbooks/nagios/templates/templates.cfg.erb +31 -0
  116. data/cookbooks/nagios/templates/timeperiods.cfg.erb +13 -0
  117. data/extras/platform_berksfile_base +3 -3
  118. data/extras/python_rpm/build.sh +4 -4
  119. data/extras/python_rpm/muthon.spec +2 -4
  120. data/extras/vault_tools/export_vaults.sh +11 -1
  121. data/install/installer +1 -1
  122. data/modules/mu/kittens.rb +27523 -0
  123. data/modules/mu/master/ldap.rb +48 -31
  124. data/modules/mu/master.rb +69 -0
  125. data/modules/mu/mu.yaml.rb +351 -0
  126. data/modules/mu/providers/aws/firewall_rule.rb +3 -1
  127. data/modules/mu/providers/aws.rb +11 -5
  128. data/modules/mu.rb +5 -4
  129. metadata +99 -48
  130. data/cookbooks/firewall/CHANGELOG.md +0 -488
  131. data/cookbooks/firewall/LICENSE +0 -202
  132. data/cookbooks/firewall/README.md +0 -366
  133. data/cookbooks/firewall/TODO.md +0 -6
  134. data/cookbooks/firewall/attributes/default.rb +0 -5
  135. data/cookbooks/firewall/attributes/firewalld.rb +0 -8
  136. data/cookbooks/firewall/attributes/iptables.rb +0 -17
  137. data/cookbooks/firewall/attributes/ufw.rb +0 -12
  138. data/cookbooks/firewall/attributes/windows.rb +0 -8
  139. data/cookbooks/firewall/libraries/helpers.rb +0 -105
  140. data/cookbooks/firewall/libraries/helpers_firewalld.rb +0 -116
  141. data/cookbooks/firewall/libraries/helpers_firewalld_dbus.rb +0 -72
  142. data/cookbooks/firewall/libraries/helpers_iptables.rb +0 -112
  143. data/cookbooks/firewall/libraries/helpers_nftables.rb +0 -170
  144. data/cookbooks/firewall/libraries/helpers_ufw.rb +0 -142
  145. data/cookbooks/firewall/libraries/helpers_windows.rb +0 -129
  146. data/cookbooks/firewall/libraries/provider_firewall_firewalld.rb +0 -179
  147. data/cookbooks/firewall/libraries/provider_firewall_iptables.rb +0 -171
  148. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb +0 -200
  149. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb +0 -200
  150. data/cookbooks/firewall/libraries/provider_firewall_rule.rb +0 -34
  151. data/cookbooks/firewall/libraries/provider_firewall_ufw.rb +0 -138
  152. data/cookbooks/firewall/libraries/provider_firewall_windows.rb +0 -126
  153. data/cookbooks/firewall/libraries/resource_firewall.rb +0 -26
  154. data/cookbooks/firewall/libraries/resource_firewall_rule.rb +0 -52
  155. data/cookbooks/firewall/metadata.json +0 -40
  156. data/cookbooks/firewall/metadata.rb +0 -15
  157. data/cookbooks/firewall/recipes/default.rb +0 -76
  158. data/cookbooks/firewall/recipes/firewalld.rb +0 -87
  159. data/cookbooks/firewall/resources/firewalld.rb +0 -28
  160. data/cookbooks/firewall/resources/firewalld_config.rb +0 -39
  161. data/cookbooks/firewall/resources/firewalld_helpers.rb +0 -106
  162. data/cookbooks/firewall/resources/firewalld_icmptype.rb +0 -88
  163. data/cookbooks/firewall/resources/firewalld_ipset.rb +0 -104
  164. data/cookbooks/firewall/resources/firewalld_policy.rb +0 -115
  165. data/cookbooks/firewall/resources/firewalld_service.rb +0 -98
  166. data/cookbooks/firewall/resources/firewalld_zone.rb +0 -118
  167. data/cookbooks/firewall/resources/nftables.rb +0 -71
  168. data/cookbooks/firewall/resources/nftables_rule.rb +0 -113
  169. data/cookbooks/firewall/templates/default/ufw/default.erb +0 -13
  170. /data/cookbooks/{firewall → nagios}/chefignore +0 -0
  171. /data/cookbooks/{firewall → nagios}/renovate.json +0 -0
@@ -100,7 +100,7 @@ module MU
100
100
  raise MuLDAPError, "When supply credentials to getLDAPConnection, both username and password must be specified"
101
101
  end
102
102
  if !username and !password
103
- bind_creds = MU::Groomer::Chef.getSecret(vault: $MU_CFG["ldap"]["bind_creds"]["vault"], item: $MU_CFG["ldap"]["bind_creds"]["item"])
103
+ bind_creds = MU::Groomer::Chef.getSecret(vault: $MU_CFG["ldap"]["bind_creds"]["vault"], item: "cfg_directory_adm")#$MU_CFG["ldap"]["bind_creds"]["item"])
104
104
  username = bind_creds[$MU_CFG["ldap"]["bind_creds"]["username_field"]]
105
105
  password = bind_creds[$MU_CFG["ldap"]["bind_creds"]["password_field"]]
106
106
  end
@@ -210,6 +210,7 @@ module MU
210
210
  :gidNumber => gid,
211
211
  :objectclass => ["top", "posixGroup"]
212
212
  }
213
+
213
214
  if !@ldap_conn.add(
214
215
  :dn => dn,
215
216
  :attributes => attr
@@ -217,7 +218,7 @@ module MU
217
218
  MU.log "Error creating #{dn}: "+getLDAPErr, MU::ERR, details: attr
218
219
  return false
219
220
  elsif @ldap_conn.get_operation_result.code != 68
220
- MU.log "Created group #{dn} with gid #{gid}", MU::NOTICE
221
+ MU.log "Created group #{dn} with gid #{gid} (#{@ldap_conn.get_operation_result.message})", MU::NOTICE
221
222
  end
222
223
  return gid
223
224
  end
@@ -235,7 +236,7 @@ module MU
235
236
  MU.log "Custom directory service configured, not initializing bundled schema", MU::NOTICE
236
237
  return
237
238
  end
238
- root_creds = MU::Groomer::Chef.getSecret(vault: "mu_ldap", item: "root_dn_user")
239
+ root_creds = MU::Groomer::Chef.getSecret(vault: "mu_ldap", item: "cfg_directory_adm")
239
240
  @ldap_conn = Net::LDAP.new(
240
241
  :host => "127.0.0.1",
241
242
  :encryption => {
@@ -252,7 +253,7 @@ module MU
252
253
  )
253
254
 
254
255
  # Manufacture our OU tree and groups
255
- [$MU_CFG["ldap"]["base_dn"],
256
+ [ $MU_CFG["ldap"]["base_dn"],
256
257
  "OU=Mu-System,#{$MU_CFG["ldap"]["base_dn"]}",
257
258
  $MU_CFG["ldap"]["user_ou"],
258
259
  $MU_CFG["ldap"]["group_ou"],
@@ -397,14 +398,14 @@ module MU
397
398
 
398
399
  @can_write = true
399
400
  if !conn.add(:dn => dn, :attributes => attr)
400
- MU.log "Couldn't create write-test user #{dn}, operating in read-only LDAP mode (#{getLDAPErr})", MU::NOTICE, details: attr
401
+ MU.log "Couldn't create write-test user #{dn}, wll operate in read-only LDAP mode (#{getLDAPErr})", MU::NOTICE, details: attr
401
402
  return false
402
403
  end
403
404
 
404
405
  # Make sure we can write various fields that we might need to touch
405
406
  [:displayName, :mail, :givenName, :sn].each { |field|
406
407
  if !conn.replace_attribute(dn, field, "foo@bar.com")
407
- MU.log "Couldn't modify write-test user #{dn} field #{field.to_s}, operating in read-only LDAP mode (#{getLDAPErr})", MU::NOTICE
408
+ MU.log "Couldn't modify write-test user #{dn} field #{field.to_s}, will operate in read-only LDAP mode (#{getLDAPErr})", MU::NOTICE
408
409
  @can_write = false
409
410
 
410
411
  end
@@ -431,11 +432,12 @@ module MU
431
432
  # @param search [Array<String>]: Strings to search for.
432
433
  # @param exact [Boolean]: Return only exact matches for whole fields.
433
434
  # @param searchbase [String]: The DN under which to search.
435
+ # @param whole_desc [Boolean]: Return whole descriptors instead of just the DNs
434
436
  # @return [Array<String>]
435
- def self.findGroups(search = [], exact: false, searchbase: $MU_CFG['ldap']['base_dn'])
436
- if search.nil? or search.size == 0
437
- raise MuLDAPError, "Need something to search for in MU::Master::LDAP.findGroups"
438
- end
437
+ def self.findGroups(search = [], exact: false, searchbase: "OU=Groups,"+$MU_CFG['ldap']['base_dn'], whole_desc: false)
438
+ # if search.nil? or search.size == 0
439
+ # raise MuLDAPError, "Need something to search for in MU::Master::LDAP.findGroups"
440
+ # end
439
441
  conn = getLDAPConnection
440
442
  filter = nil
441
443
  search.each { |term|
@@ -450,14 +452,19 @@ module MU
450
452
  filter = filter | curfilter
451
453
  end
452
454
  }
453
- filter = Net::LDAP::Filter.ne("objectclass", "computer") & (filter)
455
+ filter = if filter
456
+ Net::LDAP::Filter.ne("objectclass", "computer") & (filter)
457
+ else
458
+ Net::LDAP::Filter.ne("objectclass", "computer")
459
+ end
454
460
  groups = []
455
461
  conn.search(
456
462
  :filter => filter,
457
463
  :base => searchbase,
458
- :attributes => ["objectclass"]
464
+ :attributes => ["objectclass"] + (whole_desc ? ["description", @gidnum_attr, @member_attr] : [])
459
465
  ) do |group|
460
- groups << group.dn
466
+ next if group.dn == searchbase
467
+ groups << (whole_desc ? group : group.dn)
461
468
  end
462
469
  groups
463
470
  end
@@ -671,7 +678,7 @@ module MU
671
678
  username_filter = Net::LDAP::Filter.eq("cn", cn)
672
679
  end
673
680
  user_filter = Net::LDAP::Filter.ne("objectclass", "computer") & Net::LDAP::Filter.ne("objectclass", "group")
674
- fetchattrs = ["cn", @uid_attr, "displayName", "mail"]
681
+ fetchattrs = ["cn", @uid_attr, "displayName", "mail", "departmentNumber"]
675
682
  fetchattrs << "employeeNumber" if $MU_CFG["ldap"]["type"] == "389 Directory Services"
676
683
  conn.search(
677
684
  :filter => username_filter & user_filter,
@@ -695,6 +702,9 @@ module MU
695
702
  begin
696
703
  users[acct[@uid_attr].first]['uid'] = acct.employeenumber.first
697
704
  end rescue NoMethodError
705
+ begin
706
+ users[acct[@uid_attr].first]['gid'] = acct.departmentNumber.first
707
+ end rescue NoMethodError
698
708
  end
699
709
  }
700
710
  }
@@ -898,22 +908,25 @@ module MU
898
908
  manageGroup(group, add_users: [user])
899
909
  }
900
910
 
901
- wait = 10
902
- begin
903
- %x{/usr/bin/getent passwd ; /usr/bin/getent group} # winbind is slow sometimes
904
- Etc.getpwnam(user)
905
- rescue ArgumentError
906
- if wait >= 30
907
- MU.log "User #{user} has been created in LDAP, but local system can't see it. Are PAM/LDAP configured correctly?", MU::ERR
908
- return false
909
- end
910
- MU.log "User #{user} has been created in LDAP, but not yet visible to local system, waiting #{wait}s and checking again.", MU::WARN
911
- sleep wait
912
- wait = wait + 5
913
- retry
914
- end if user != "mu"
911
+ # XXX SSSD is completely broken on Amazon 2023 for now. None of the below works.
912
+ # We're currently relying on MU::Master.manageUser to set up a unix-side
913
+ # user, old-school /etc/passwd style, in parallel to these LDAP entries.
914
+ # wait = 10
915
+ # begin
916
+ # %x{/usr/bin/getent passwd ; /usr/bin/getent group} # winbind is slow sometimes
917
+ # Etc.getpwnam(user)
918
+ # rescue ArgumentError
919
+ # if wait >= 30
920
+ # MU.log "User #{user} has been created in LDAP, but local system can't see it. Are PAM/LDAP configured correctly?", MU::ERR
921
+ # return false
922
+ # end
923
+ # MU.log "User #{user} has been created in LDAP, but not yet visible to local system, waiting #{wait}s and checking again.", MU::WARN
924
+ # sleep wait
925
+ # wait = wait + 5
926
+ # retry
927
+ # end if user != "mu"
915
928
  %x{/sbin/restorecon -r /home} # SELinux stupidity that oddjob misses
916
- MU::Master.setLocalDataPerms(user) if Etc.getpwuid(Process.uid).name == "root" and mu_acct
929
+ # MU::Master.setLocalDataPerms(user) if Etc.getpwuid(Process.uid).name == "root" and mu_acct
917
930
  else
918
931
  MU.log "We are in read-only LDAP mode. You must first create #{user} in your directory and add it to #{$MU_CFG["ldap"]["user_group_dn"]}. If the user is intended to be an admin, also add it to #{$MU_CFG["ldap"]["admin_group_dn"]}.", MU::WARN
919
932
  return true
@@ -985,9 +998,13 @@ module MU
985
998
 
986
999
  cur_users = listUsers
987
1000
  if cur_users.has_key?(user)
1001
+ stubdir = File.join($MU_CFG['datadir'], "users", user)
1002
+ if !Dir.exist?(stubdir)
1003
+ Dir.mkdir(stubdir)
1004
+ end
988
1005
  ["realname", "email", "monitoring_email"].each { |field|
989
1006
  next if !cur_users[user].has_key?(field)
990
- File.open($MU_CFG['datadir']+"/users/#{user}/#{field}", File::CREAT|File::RDWR, 0640) { |f|
1007
+ File.open("#{stubdir}/#{field}", File::CREAT|File::RDWR, 0640) { |f|
991
1008
  f.puts cur_users[user][field]
992
1009
  }
993
1010
  }
@@ -995,7 +1012,7 @@ module MU
995
1012
  MU.log "Load of current user list didn't include #{user}, even though we just created them!", MU::WARN
996
1013
  end
997
1014
 
998
- MU::Master.setLocalDataPerms(user) if Etc.getpwuid(Process.uid).name == "root" and mu_acct
1015
+ # MU::Master.setLocalDataPerms(user) if Etc.getpwuid(Process.uid).name == "root" and mu_acct
999
1016
  ok
1000
1017
  end
1001
1018
 
data/modules/mu/master.rb CHANGED
@@ -72,6 +72,46 @@ module MU
72
72
  end
73
73
  end
74
74
 
75
+ # Ensure that the existing list of LDAP groups has counterparts in
76
+ # /etc/group, and that all LDAP members also exist there.
77
+ # @return [Hash<String>]: A mapping of group names to gids
78
+ def self.syncGroups
79
+ groups = MU::Master::LDAP.findGroups(whole_desc: true)
80
+ ldapusers = MU::Master::LDAP.listUsers
81
+ groups.each { |g|
82
+ group_name = g.dn.split(/,/)[0].sub(/^cn=/i, '')
83
+ attempts = 0
84
+ group = begin
85
+ Etc.getgrnam(group_name)
86
+ rescue ArgumentError => e
87
+ MU.log "Creating unix group #{group_name} with gid #{g.gidnumber.first}", MU::NOTICE
88
+ attempts += 1
89
+ puts %x{/usr/sbin/groupadd --gid #{g.gidnumber.first} #{group_name}}
90
+ if attempts < 3
91
+ retry
92
+ else
93
+ raise MuError, "Failed to create group #{group_name}"
94
+ end
95
+ end
96
+ if group.gid != g.gidnumber.first.to_i
97
+ raise MuError, "GID #{group.gid.to_s} for group #{group_name} doesn't agree with LDAP, which says #{g.gidnumber.first}"
98
+ end
99
+
100
+ g.memberuid.each { |user|
101
+ begin
102
+ Etc.getpwnam(user)
103
+ rescue ArgumentError
104
+ next
105
+ end
106
+
107
+ if ldapusers[user] and !group.mem.include?(user)
108
+ MU.log "Adding #{user} to group #{group_name}", MU::NOTICE
109
+ puts %x{/usr/sbin/groupmod --append #{group_name} --users #{user}}
110
+ end
111
+ }
112
+ }
113
+ end
114
+
75
115
  # Create and/or update a user as appropriate (Chef, LDAP, et al).
76
116
  # @param username [String]: The canonical username to modify.
77
117
  # @param chef_username [String]: The Chef username, if different
@@ -99,12 +139,39 @@ module MU
99
139
  deleteUser(username) if create
100
140
  return false
101
141
  end
142
+ ldapusers = MU::Master::LDAP.listUsers
143
+ if !ldapusers[username]
144
+ MU.log "#{username} wasn't in LDAP after I added it, I don't know what to do", MU::ERR
145
+ deleteUser(username) if create
146
+ return false
147
+ end
148
+
149
+ # XXX the following insecure jank is a workaround for the fact that SSSD
150
+ # is flat broken on Amazon Linux 2023. We're managing unix passwd and
151
+ # group entries like cavemen.
152
+ ldap_desc = ldapusers[username]
153
+ begin
154
+ Etc.getpwnam(username)
155
+ rescue
156
+ syncGroups
157
+ MU.log "Creating unix user #{username}", MU::NOTICE, ldap_desc
158
+ # XXX plain-text password visible in ps! horrible!
159
+ puts %x{/usr/sbin/adduser "#{username}" --uid #{ldap_desc['uid']} --gid #{ldap_desc['gid']} --no-user-group --comment '#{ldap_desc['realname']},#{ldap_desc['email']},,,' --password '#{password}'}
160
+ end
161
+ syncGroups
102
162
  %x{sh -x /etc/init.d/oddjobd start 2>&1 > /dev/null} # oddjobd dies, like a lot
103
163
  begin
104
164
  Etc.getpwnam(username)
165
+ if password # setting a new password for an existing user
166
+ MU.log "Updating unix password for #{username}", MU::NOTICE
167
+ # XXX plain-text password visible in ps! horrible!
168
+ %x{echo '#{username}:#{password}' | /usr/sbin/chpasswd}
169
+ end
105
170
  rescue ArgumentError
106
171
  return false
107
172
  end
173
+
174
+
108
175
  chef_username ||= username.dup
109
176
  %x{/bin/su - #{username} -c "ls > /dev/null"}
110
177
  if !MU::Master::Chef.manageUser(chef_username, ldap_user: username, name: name, email: email, admin: admin, orgs: orgs, remove_orgs: remove_orgs) and create
@@ -157,6 +224,8 @@ module MU
157
224
  end
158
225
  MU::Master::Chef.deleteUser(user)
159
226
  MU::Master::LDAP.deleteUser(user)
227
+ puts %x{/usr/sbin/userdel "#{user}"}
228
+ puts %x{/usr/sbin/groupdel "#{user}.mu-user"}
160
229
  FileUtils.rm_rf(deletia)
161
230
  end
162
231
 
@@ -0,0 +1,351 @@
1
+ # Configuration schema for mu.yaml. See also {https://github.com/cloudamatic/mu/wiki/Configuration the Mu wiki}.
2
+ #
3
+ # Example:
4
+ #
5
+ # <pre>
6
+ # ---
7
+ # public_address: 1.2.3.4
8
+ # mu_admin_email: egtlabs@eglobaltech.com
9
+ # mu_admin_name: Joe Schmoe
10
+ # mommacat_port: 2260
11
+ # banner: My Example Mu Master
12
+ # mu_repository: git://github.com/cloudamatic/mu.git
13
+ # repos:
14
+ # - https://github.com/cloudamatic/mu_demo_platform
15
+ # allow_invade_foreign_vpcs: true
16
+ # ansible_dir:
17
+ # aws:
18
+ # egtdev:
19
+ # region: us-east-1
20
+ # log_bucket_name: egt-mu-log-bucket
21
+ # default: true
22
+ # name: egtdev
23
+ # personal:
24
+ # region: us-east-2
25
+ # log_bucket_name: my-mu-log-bucket
26
+ # name: personal
27
+ # google:
28
+ # egtlabs:
29
+ # project: egt-labs-admin
30
+ # credentials_file: /opt/mu/etc/google.json
31
+ # region: us-east4
32
+ # log_bucket_name: hexabucket-761234
33
+ # default: true
34
+ # </pre>
35
+ module MuYAML
36
+ # The configuration file format for Mu's main config file.
37
+ # Adoption Change Notifications
38
+ class adopt_change_notify
39
+ # @!group Optional parameters
40
+
41
+ # Report modifications to adopted resources, detected by mu-adopt --diff, to the Slack webhook and channel configured under Slack Configuration.
42
+ #
43
+ # @return [Boolean]
44
+ attr_accessor :slack
45
+
46
+ # If a list of details about a modified resources is longer than this number of lines (in JSON), it will be sent as an "attachment," which in Slack means a blockquote that displays a few lines with a "Show more" button. The internal default is 5 lines.
47
+ #
48
+ # @return [String]
49
+ attr_accessor :slack_snippet_threshold
50
+ # @!endgroup
51
+ end
52
+ # Amazon Web Services
53
+ class aws
54
+ # @!group Required parameters
55
+
56
+ # **REQUIRED** -
57
+ # S3 bucket into which we'll synchronize deploy secrets, and if we're hosted in AWS, collected system logs
58
+ #
59
+ # @return [String]
60
+ attr_accessor :log_bucket_name
61
+ # @!endgroup
62
+ # @!group Optional parameters
63
+
64
+ # **Must match pattern `(?i-mx:^[a-z0-9]+$)`** -
65
+ # Credentials used for accessing the AWS API (looks like: AKIAINWLOOAA24PBRBZA)
66
+ #
67
+ # @return [String]
68
+ attr_accessor :access_key
69
+
70
+ # Credentials used for accessing the AWS API (looks like: +Z16iRP9QAq7EcjHINyEMs3oR7A76QpfaSgCBogp).
71
+ #
72
+ # @return [String]
73
+ attr_accessor :access_secret
74
+
75
+ # **Must match pattern `(?-mix:^\d+$)`** -
76
+ # Default target account for resources managed using these credentials. This is an AWS account number, e.g. 918972669773. If not specified, we will use the account number which owns these API keys.
77
+ #
78
+ # @return [String]
79
+ attr_accessor :account_number
80
+
81
+ # A secure Chef vault and item from which to retrieve an AWS access key and secret. The vault item should have 'access_key' and 'access_secret' elements.
82
+ #
83
+ # @return [String]
84
+ attr_accessor :credentials
85
+
86
+ # An INI-formatted AWS credentials file, of the type used by the AWS command-line tools. This is less secure than using 'credentials' to store these in a Chef vault. See: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html
87
+ #
88
+ # @return [String]
89
+ attr_accessor :credentials_file
90
+
91
+ # **Default: `false`** -
92
+ # If set to true, Mu will default to these AWS credentials when targeting AWS resources
93
+ #
94
+ # @return [Boolean]
95
+ attr_accessor :default
96
+
97
+ # Default Amazon Web Services region in which these credentials should operate
98
+ #
99
+ # @return [String]
100
+ attr_accessor :region
101
+ # @!endgroup
102
+ end
103
+ # Microsoft Azure Cloud Computing Platform & Services
104
+ class azure
105
+ # @!group Optional parameters
106
+
107
+ # App client id used to authenticate to our subscription. From https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview
108
+ #
109
+ # @return [String]
110
+ attr_accessor :client_id
111
+
112
+ # App client secret used to authenticate to our subscription. From https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview under the 'Certificates & secrets' tab, 'Client secrets.' This can only be retrieved upon initial secret creation.
113
+ #
114
+ # @return [String]
115
+ attr_accessor :client_secret
116
+
117
+ # JSON file which contains a hash of directory_id, client_id, client_secret, and subscription values. If found, these will be override values entered directly in mu-configure.
118
+ #
119
+ # @return [String]
120
+ attr_accessor :credentials_file
121
+
122
+ # **Default: `false`** -
123
+ # If set to true, Mu will use this set of Azure credentials when targeting Azure without a specific account having been requested
124
+ #
125
+ # @return [Boolean]
126
+ attr_accessor :default
127
+
128
+ # AKA Tenant ID; the default Microsoft Azure Directory project in which we operate and deploy, from https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview
129
+ #
130
+ # @return [String]
131
+ attr_accessor :directory_id
132
+
133
+ # **Default: `eastus`** -
134
+ # Default Microsoft Azure region in which we operate and deploy
135
+ #
136
+ # @return [String]
137
+ attr_accessor :region
138
+
139
+ # Default Microsoft Azure Subscription we will use to deploy, from https://portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade
140
+ #
141
+ # @return [String]
142
+ attr_accessor :subscription
143
+ # @!endgroup
144
+ end
145
+ # Google Cloud Platform
146
+ class google
147
+ # @!group Required parameters
148
+
149
+ # **REQUIRED** -
150
+ # Cloud Storage bucket into which we'll synchronize deploy secrets, and if we're hosted in GCP, collected system logs
151
+ #
152
+ # @return [String]
153
+ attr_accessor :log_bucket_name
154
+
155
+ # **REQUIRED** -
156
+ # Default Google Cloud Platform project in which we operate and deploy. Generate a service account at: https://console.cloud.google.com/iam-admin/serviceaccounts/project, making sure the account has sufficient privileges to manage cloud resources. Download the private key as JSON, and import that key to the vault specified here. Import example: knife vault create secrets google -J my-google-service-account.json
157
+ #
158
+ # @return [String]
159
+ attr_accessor :project
160
+ # @!endgroup
161
+ # @!group Optional parameters
162
+
163
+ # A secure Chef vault and item from which to retrieve the JSON-formatted Service Account credentials for our GCP account, in the format vault:itemname (e.g. 'secrets:google'). Generate a service account at: https://console.cloud.google.com/iam-admin/serviceaccounts/project, making sure the account has sufficient privileges to manage cloud resources. Download the private key as JSON, and import that key to the vault specified here. Import example: knife vault create secrets google -J my-google-service-account.json
164
+ #
165
+ # @return [String]
166
+ attr_accessor :credentials
167
+
168
+ # JSON-formatted Service Account credentials for our GCP account, b64-encoded and dropped directly into mu.yaml. Generate a service account at: https://console.cloud.google.com/iam-admin/serviceaccounts/project, making sure the account has sufficient privileges to manage cloud resources. Download the private key as JSON and point this argument to the file. This is less secure than using 'credentials' to store in a vault.
169
+ #
170
+ # @return [String]
171
+ attr_accessor :credentials_encoded
172
+
173
+ # JSON-formatted Service Account credentials for our GCP account, stored in plain text in a file. Generate a service account at: https://console.cloud.google.com/iam-admin/serviceaccounts/project, making sure the account has sufficient privileges to manage cloud resources. Download the private key as JSON and point this argument to the file. This is less secure than using 'credentials' to store in a vault.
174
+ #
175
+ # @return [String]
176
+ attr_accessor :credentials_file
177
+
178
+ # For Google Cloud projects which are attached to a GSuite domain. Some API calls (groups, users, etc) require this identifier. From admin.google.com, choose Security, the Single Sign On, and look for the Entity ID field. The value after idpid= in the URL there should be the customer ID.
179
+ #
180
+ # @return [String]
181
+ attr_accessor :customer_id
182
+
183
+ # **Default: `false`** -
184
+ # If set to true, Mu will use this set of GCP credentials when targeting the Google Cloud without a specific account having been requested
185
+ #
186
+ # @return [Boolean]
187
+ attr_accessor :default
188
+
189
+ # Optional list of projects to ignore, for credentials which have visibility into multiple projects
190
+ #
191
+ # @return [Array<String>]
192
+ attr_accessor :ignore_habitats
193
+
194
+ # For Google Cloud projects which are attached to a GSuite domain. GCP service accounts cannot view or manage GSuite resources (groups, users, etc) directly, but must instead masquerade as a GSuite user which has delegated authority to the service account. See also: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
195
+ #
196
+ # @return [String]
197
+ attr_accessor :masequerade_as
198
+
199
+ # For credential sets which have access to multiple GSuite or Cloud Identity orgs, you must specify a default organization (e.g. my.domain.com).
200
+ #
201
+ # @return [String]
202
+ attr_accessor :org
203
+
204
+ # **Default: `us-east4`** -
205
+ # Default Google Cloud Platform region in which we operate and deploy
206
+ #
207
+ # @return [String]
208
+ attr_accessor :region
209
+
210
+ # Optional list of projects to which we'll restrict all of our activities.
211
+ #
212
+ # @return [Array<String>]
213
+ attr_accessor :restrict_to_habitats
214
+ # @!endgroup
215
+ end
216
+ # Slack Configuration
217
+ class slack
218
+ # @!group Optional parameters
219
+
220
+ # The channel name (without leading #) to which alerts should be sent.
221
+ #
222
+ # @return [String]
223
+ attr_accessor :channel
224
+
225
+ # The hooks.slack.com URL for the webook to which we'll send deploy notifications
226
+ #
227
+ # @return [String]
228
+ attr_accessor :webhook
229
+ # @!endgroup
230
+ end
231
+ # @!group Required parameters
232
+
233
+ # **REQUIRED**,
234
+ # **Must match pattern `(?i-mx:^[a-z0-9\-_]+$)`** -
235
+ # The local system's value for HOSTNAME
236
+ #
237
+ # @return [String]
238
+ attr_accessor :hostname
239
+
240
+ # **REQUIRED**,
241
+ # **Must match pattern `(?i-mx:\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z)`** -
242
+ # Administative contact email
243
+ #
244
+ # @return [String]
245
+ attr_accessor :mu_admin_email
246
+
247
+ # **REQUIRED**,
248
+ # **Must match pattern `(?-mix:^(127\.0\.0\.1|localhost)$)`** -
249
+ # IP address or hostname
250
+ #
251
+ # @return [String]
252
+ attr_accessor :public_address
253
+ # @!endgroup
254
+ # @!group Optional parameters
255
+
256
+ # Adoption Change Notifications
257
+ #
258
+ # @return [adopt_change_notify]
259
+ # @see adopt_change_notify
260
+ attr_accessor :adopt_change_notify
261
+
262
+ # **Default: `false`** -
263
+ # Ordinarily, Mu will automatically name, tag and generate auxiliary resources in a standard Mu-ish fashion that allows for deployment of multiple clones of a given stack. Toggling this flag will change the default behavior of mu-adopt, when it creates stack descriptors from found resources, to enable or disable this behavior (see also mu-adopt's --scrub option).
264
+ #
265
+ # @return [Boolean]
266
+ attr_accessor :adopt_scrub_mu_isms
267
+
268
+ # If set to true, Mu will be allowed to modify routing and peering behavior of VPCs which it did not create, but for which it has permissions.
269
+ #
270
+ # @return [Boolean]
271
+ attr_accessor :allow_invade_foreign_vpcs
272
+
273
+ # Intended for use with minimal installs which use Ansible as a groomer and which do not store Ansible artifacts in a dedicated git repository. This allows simply pointing to a local directory.
274
+ #
275
+ # @return [String]
276
+ attr_accessor :ansible_dir
277
+
278
+ # Amazon Web Services
279
+ #
280
+ # @return [aws]
281
+ # @see aws
282
+ attr_accessor :aws
283
+
284
+ # Microsoft Azure Cloud Computing Platform & Services
285
+ #
286
+ # @return [azure]
287
+ # @see azure
288
+ attr_accessor :azure
289
+
290
+ # Login banner, displayed in various locations
291
+ #
292
+ # @return [String]
293
+ attr_accessor :banner
294
+
295
+ # **Default: `false`** -
296
+ # Disable the Momma Cat grooming daemon. Nodes which require asynchronous Ansible/Chef bootstraps will not function. This option is only honored in gem-based installations.
297
+ #
298
+ # @return [Boolean]
299
+ attr_accessor :disable_mommacat
300
+
301
+ # **Default: `false`** -
302
+ # Disable Nagios monitoring
303
+ #
304
+ # @return [Boolean]
305
+ attr_accessor :disable_nagios
306
+
307
+ # Google Cloud Platform
308
+ #
309
+ # @return [google]
310
+ # @see google
311
+ attr_accessor :google
312
+
313
+ # Optional extra Chef roles or recipes to invoke when running chef-client on this Master (ex: recipe[mycookbook::mumaster])
314
+ #
315
+ # @return [Array<String>]
316
+ attr_accessor :master_runlist_extras
317
+
318
+ # **Default: `2260`**,
319
+ # **Must match pattern `(?i-mx:^[0-9]+$)`** -
320
+ # Listen port for the Momma Cat grooming daemon
321
+ #
322
+ # @return [String]
323
+ attr_accessor :mommacat_port
324
+
325
+ # **Default: `Mu Administrator`** -
326
+ # Administative contact's full name
327
+ #
328
+ # @return [String]
329
+ attr_accessor :mu_admin_name
330
+
331
+ # **Default: `git://github.com/cloudamatic/mu.git`**,
332
+ # **Must match pattern `(?-mix:(((git|ssh|http(s)?)|(git@[\w\.]+))(:(\/\/)?))?([\w\.@\:\/\-~]+)(\.git)?(\/)?)`** -
333
+ # Source repository for Mu tools
334
+ #
335
+ # @return [String]
336
+ attr_accessor :mu_repository
337
+
338
+ # **Default: `["https://github.com/cloudamatic/mu_demo_platform"]`**,
339
+ # **Must match pattern `(?-mix:(((git|ssh|http(s)?)|(git@[\w\.]+))(:(\/\/)?))?([\w\.@\:\/\-~]+)(\.git)?(\/)?)`** -
340
+ # Optional platform repositories, as a Git URL or Github repo name (ex: eGT-Labs/fema_platform.git)
341
+ #
342
+ # @return [Array<String>]
343
+ attr_accessor :repos
344
+
345
+ # Slack Configuration
346
+ #
347
+ # @return [slack]
348
+ # @see slack
349
+ attr_accessor :slack
350
+ # @!endgroup
351
+ end
@@ -757,6 +757,8 @@ MU.log ".update_security_group_rule_descriptions_ingress", MU::NOTICE, details:
757
757
  end
758
758
 
759
759
  def rules_match(rule_a, rule_b)
760
+ a_ranges = rule_a[:ip_ranges].to_a.map { |r| MU.structToHash(r) }.sort
761
+ b_ranges = rule_b[:ip_ranges].to_a.map { |r| MU.structToHash(r) }.sort
760
762
  (
761
763
  rule_a[:from_port] == rule_b[:from_port] and
762
764
  rule_a[:to_port] == rule_b[:to_port] and
@@ -768,7 +770,7 @@ MU.log ".update_security_group_rule_descriptions_ingress", MU::NOTICE, details:
768
770
  ) or
769
771
  (
770
772
  !rule_a[:ip_ranges].nil? and !rule_b[:ip_ranges].nil? and
771
- rule_a[:ip_ranges].sort == rule_b[:ip_ranges].sort
773
+ a_ranges == b_ranges
772
774
  )
773
775
  ) and
774
776
  (