cloud-mu 2.1.0beta → 3.0.0beta

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 (291) hide show
  1. checksums.yaml +5 -5
  2. data/Berksfile +4 -5
  3. data/Berksfile.lock +179 -0
  4. data/README.md +1 -6
  5. data/ansible/roles/geerlingguy.firewall/templates/firewall.bash.j2 +0 -0
  6. data/ansible/roles/mu-installer/README.md +33 -0
  7. data/ansible/roles/mu-installer/defaults/main.yml +2 -0
  8. data/ansible/roles/mu-installer/handlers/main.yml +2 -0
  9. data/ansible/roles/mu-installer/meta/main.yml +60 -0
  10. data/ansible/roles/mu-installer/tasks/main.yml +13 -0
  11. data/ansible/roles/mu-installer/tests/inventory +2 -0
  12. data/ansible/roles/mu-installer/tests/test.yml +5 -0
  13. data/ansible/roles/mu-installer/vars/main.yml +2 -0
  14. data/bin/mu-adopt +125 -0
  15. data/bin/mu-aws-setup +4 -4
  16. data/bin/mu-azure-setup +265 -0
  17. data/bin/mu-azure-tests +43 -0
  18. data/bin/mu-cleanup +20 -8
  19. data/bin/mu-configure +224 -98
  20. data/bin/mu-deploy +8 -3
  21. data/bin/mu-gcp-setup +16 -8
  22. data/bin/mu-gen-docs +92 -8
  23. data/bin/mu-load-config.rb +52 -12
  24. data/bin/mu-momma-cat +36 -0
  25. data/bin/mu-node-manage +34 -27
  26. data/bin/mu-self-update +2 -2
  27. data/bin/mu-ssh +12 -8
  28. data/bin/mu-upload-chef-artifacts +11 -4
  29. data/bin/mu-user-manage +3 -0
  30. data/cloud-mu.gemspec +8 -11
  31. data/cookbooks/firewall/libraries/helpers_iptables.rb +2 -2
  32. data/cookbooks/firewall/metadata.json +1 -1
  33. data/cookbooks/firewall/recipes/default.rb +5 -9
  34. data/cookbooks/mu-firewall/attributes/default.rb +2 -0
  35. data/cookbooks/mu-firewall/metadata.rb +1 -1
  36. data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +0 -0
  37. data/cookbooks/mu-master/Berksfile +2 -2
  38. data/cookbooks/mu-master/files/default/check_mem.pl +0 -0
  39. data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
  40. data/cookbooks/mu-master/metadata.rb +5 -4
  41. data/cookbooks/mu-master/recipes/389ds.rb +1 -1
  42. data/cookbooks/mu-master/recipes/basepackages.rb +30 -10
  43. data/cookbooks/mu-master/recipes/default.rb +59 -7
  44. data/cookbooks/mu-master/recipes/firewall-holes.rb +1 -1
  45. data/cookbooks/mu-master/recipes/init.rb +65 -47
  46. data/cookbooks/mu-master/recipes/{eks-kubectl.rb → kubectl.rb} +4 -10
  47. data/cookbooks/mu-master/recipes/sssd.rb +2 -1
  48. data/cookbooks/mu-master/recipes/update_nagios_only.rb +6 -6
  49. data/cookbooks/mu-master/templates/default/web_app.conf.erb +2 -2
  50. data/cookbooks/mu-master/templates/mods/ldap.conf.erb +4 -0
  51. data/cookbooks/mu-php54/Berksfile +1 -2
  52. data/cookbooks/mu-php54/metadata.rb +4 -5
  53. data/cookbooks/mu-php54/recipes/default.rb +1 -1
  54. data/cookbooks/mu-splunk/templates/default/splunk-init.erb +0 -0
  55. data/cookbooks/mu-tools/Berksfile +3 -2
  56. data/cookbooks/mu-tools/files/default/Mu_CA.pem +33 -0
  57. data/cookbooks/mu-tools/libraries/helper.rb +20 -8
  58. data/cookbooks/mu-tools/metadata.rb +5 -2
  59. data/cookbooks/mu-tools/recipes/apply_security.rb +2 -3
  60. data/cookbooks/mu-tools/recipes/eks.rb +1 -1
  61. data/cookbooks/mu-tools/recipes/gcloud.rb +5 -30
  62. data/cookbooks/mu-tools/recipes/nagios.rb +1 -1
  63. data/cookbooks/mu-tools/recipes/rsyslog.rb +1 -0
  64. data/cookbooks/mu-tools/recipes/selinux.rb +19 -0
  65. data/cookbooks/mu-tools/recipes/split_var_partitions.rb +0 -1
  66. data/cookbooks/mu-tools/recipes/windows-client.rb +256 -122
  67. data/cookbooks/mu-tools/resources/disk.rb +3 -1
  68. data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +1 -1
  69. data/cookbooks/mu-tools/templates/default/etc_hosts.erb +1 -1
  70. data/cookbooks/mu-tools/templates/default/{kubeconfig.erb → kubeconfig-eks.erb} +0 -0
  71. data/cookbooks/mu-tools/templates/default/kubeconfig-gke.erb +27 -0
  72. data/cookbooks/mu-tools/templates/windows-10/sshd_config.erb +137 -0
  73. data/cookbooks/mu-utility/recipes/nat.rb +4 -0
  74. data/extras/alpha.png +0 -0
  75. data/extras/beta.png +0 -0
  76. data/extras/clean-stock-amis +2 -2
  77. data/extras/generate-stock-images +131 -0
  78. data/extras/git-fix-permissions-hook +0 -0
  79. data/extras/image-generators/AWS/centos6.yaml +17 -0
  80. data/extras/image-generators/{aws → AWS}/centos7-govcloud.yaml +0 -0
  81. data/extras/image-generators/{aws → AWS}/centos7.yaml +0 -0
  82. data/extras/image-generators/{aws → AWS}/rhel7.yaml +0 -0
  83. data/extras/image-generators/{aws → AWS}/win2k12.yaml +0 -0
  84. data/extras/image-generators/{aws → AWS}/win2k16.yaml +0 -0
  85. data/extras/image-generators/{aws → AWS}/windows.yaml +0 -0
  86. data/extras/image-generators/{gcp → Google}/centos6.yaml +1 -0
  87. data/extras/image-generators/Google/centos7.yaml +18 -0
  88. data/extras/python_rpm/build.sh +0 -0
  89. data/extras/release.png +0 -0
  90. data/extras/ruby_rpm/build.sh +0 -0
  91. data/extras/ruby_rpm/muby.spec +1 -1
  92. data/install/README.md +43 -5
  93. data/install/deprecated-bash-library.sh +0 -0
  94. data/install/installer +1 -1
  95. data/install/jenkinskeys.rb +0 -0
  96. data/install/mu-master.yaml +55 -0
  97. data/modules/mommacat.ru +41 -7
  98. data/modules/mu.rb +444 -149
  99. data/modules/mu/adoption.rb +500 -0
  100. data/modules/mu/cleanup.rb +235 -158
  101. data/modules/mu/cloud.rb +675 -138
  102. data/modules/mu/clouds/aws.rb +156 -24
  103. data/modules/mu/clouds/aws/alarm.rb +4 -14
  104. data/modules/mu/clouds/aws/bucket.rb +60 -18
  105. data/modules/mu/clouds/aws/cache_cluster.rb +8 -20
  106. data/modules/mu/clouds/aws/collection.rb +12 -22
  107. data/modules/mu/clouds/aws/container_cluster.rb +209 -118
  108. data/modules/mu/clouds/aws/database.rb +120 -45
  109. data/modules/mu/clouds/aws/dnszone.rb +7 -18
  110. data/modules/mu/clouds/aws/endpoint.rb +5 -15
  111. data/modules/mu/clouds/aws/firewall_rule.rb +144 -72
  112. data/modules/mu/clouds/aws/folder.rb +4 -11
  113. data/modules/mu/clouds/aws/function.rb +6 -16
  114. data/modules/mu/clouds/aws/group.rb +4 -12
  115. data/modules/mu/clouds/aws/habitat.rb +11 -13
  116. data/modules/mu/clouds/aws/loadbalancer.rb +40 -28
  117. data/modules/mu/clouds/aws/log.rb +5 -13
  118. data/modules/mu/clouds/aws/msg_queue.rb +9 -24
  119. data/modules/mu/clouds/aws/nosqldb.rb +4 -12
  120. data/modules/mu/clouds/aws/notifier.rb +6 -13
  121. data/modules/mu/clouds/aws/role.rb +69 -40
  122. data/modules/mu/clouds/aws/search_domain.rb +17 -20
  123. data/modules/mu/clouds/aws/server.rb +184 -94
  124. data/modules/mu/clouds/aws/server_pool.rb +33 -38
  125. data/modules/mu/clouds/aws/storage_pool.rb +5 -12
  126. data/modules/mu/clouds/aws/user.rb +59 -33
  127. data/modules/mu/clouds/aws/userdata/linux.erb +18 -30
  128. data/modules/mu/clouds/aws/userdata/windows.erb +9 -9
  129. data/modules/mu/clouds/aws/vpc.rb +214 -145
  130. data/modules/mu/clouds/azure.rb +978 -44
  131. data/modules/mu/clouds/azure/container_cluster.rb +413 -0
  132. data/modules/mu/clouds/azure/firewall_rule.rb +500 -0
  133. data/modules/mu/clouds/azure/habitat.rb +167 -0
  134. data/modules/mu/clouds/azure/loadbalancer.rb +205 -0
  135. data/modules/mu/clouds/azure/role.rb +211 -0
  136. data/modules/mu/clouds/azure/server.rb +810 -0
  137. data/modules/mu/clouds/azure/user.rb +257 -0
  138. data/modules/mu/clouds/azure/userdata/README.md +4 -0
  139. data/modules/mu/clouds/azure/userdata/linux.erb +137 -0
  140. data/modules/mu/clouds/azure/userdata/windows.erb +275 -0
  141. data/modules/mu/clouds/azure/vpc.rb +782 -0
  142. data/modules/mu/clouds/cloudformation.rb +12 -9
  143. data/modules/mu/clouds/cloudformation/firewall_rule.rb +5 -13
  144. data/modules/mu/clouds/cloudformation/server.rb +10 -1
  145. data/modules/mu/clouds/cloudformation/server_pool.rb +1 -0
  146. data/modules/mu/clouds/cloudformation/vpc.rb +0 -2
  147. data/modules/mu/clouds/google.rb +554 -117
  148. data/modules/mu/clouds/google/bucket.rb +173 -32
  149. data/modules/mu/clouds/google/container_cluster.rb +1112 -157
  150. data/modules/mu/clouds/google/database.rb +24 -47
  151. data/modules/mu/clouds/google/firewall_rule.rb +344 -89
  152. data/modules/mu/clouds/google/folder.rb +156 -79
  153. data/modules/mu/clouds/google/group.rb +272 -82
  154. data/modules/mu/clouds/google/habitat.rb +177 -52
  155. data/modules/mu/clouds/google/loadbalancer.rb +9 -34
  156. data/modules/mu/clouds/google/role.rb +1211 -0
  157. data/modules/mu/clouds/google/server.rb +491 -227
  158. data/modules/mu/clouds/google/server_pool.rb +233 -48
  159. data/modules/mu/clouds/google/user.rb +479 -125
  160. data/modules/mu/clouds/google/userdata/linux.erb +3 -3
  161. data/modules/mu/clouds/google/userdata/windows.erb +9 -9
  162. data/modules/mu/clouds/google/vpc.rb +381 -223
  163. data/modules/mu/config.rb +689 -214
  164. data/modules/mu/config/bucket.rb +1 -1
  165. data/modules/mu/config/cache_cluster.rb +1 -1
  166. data/modules/mu/config/cache_cluster.yml +0 -4
  167. data/modules/mu/config/container_cluster.rb +18 -9
  168. data/modules/mu/config/database.rb +6 -23
  169. data/modules/mu/config/firewall_rule.rb +9 -15
  170. data/modules/mu/config/folder.rb +22 -21
  171. data/modules/mu/config/habitat.rb +22 -21
  172. data/modules/mu/config/loadbalancer.rb +2 -2
  173. data/modules/mu/config/role.rb +9 -40
  174. data/modules/mu/config/server.rb +26 -5
  175. data/modules/mu/config/server_pool.rb +1 -1
  176. data/modules/mu/config/storage_pool.rb +2 -2
  177. data/modules/mu/config/user.rb +4 -0
  178. data/modules/mu/config/vpc.rb +350 -110
  179. data/modules/mu/defaults/{amazon_images.yaml → AWS.yaml} +37 -39
  180. data/modules/mu/defaults/Azure.yaml +17 -0
  181. data/modules/mu/defaults/Google.yaml +24 -0
  182. data/modules/mu/defaults/README.md +1 -1
  183. data/modules/mu/deploy.rb +168 -125
  184. data/modules/mu/groomer.rb +2 -1
  185. data/modules/mu/groomers/ansible.rb +104 -32
  186. data/modules/mu/groomers/chef.rb +96 -44
  187. data/modules/mu/kittens.rb +20602 -0
  188. data/modules/mu/logger.rb +38 -11
  189. data/modules/mu/master.rb +90 -8
  190. data/modules/mu/master/chef.rb +2 -3
  191. data/modules/mu/master/ldap.rb +0 -1
  192. data/modules/mu/master/ssl.rb +250 -0
  193. data/modules/mu/mommacat.rb +917 -513
  194. data/modules/scratchpad.erb +1 -1
  195. data/modules/tests/super_complex_bok.yml +0 -0
  196. data/modules/tests/super_simple_bok.yml +0 -0
  197. data/roles/mu-master.json +2 -1
  198. data/spec/azure_creds +5 -0
  199. data/spec/mu.yaml +56 -0
  200. data/spec/mu/clouds/azure_spec.rb +164 -27
  201. data/spec/spec_helper.rb +5 -0
  202. data/test/clean_up.py +0 -0
  203. data/test/exec_inspec.py +0 -0
  204. data/test/exec_mu_install.py +0 -0
  205. data/test/exec_retry.py +0 -0
  206. data/test/smoke_test.rb +0 -0
  207. metadata +90 -118
  208. data/cookbooks/mu-jenkins/Berksfile +0 -14
  209. data/cookbooks/mu-jenkins/CHANGELOG.md +0 -13
  210. data/cookbooks/mu-jenkins/LICENSE +0 -37
  211. data/cookbooks/mu-jenkins/README.md +0 -105
  212. data/cookbooks/mu-jenkins/attributes/default.rb +0 -42
  213. data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +0 -73
  214. data/cookbooks/mu-jenkins/files/default/deploy_config.xml +0 -44
  215. data/cookbooks/mu-jenkins/metadata.rb +0 -21
  216. data/cookbooks/mu-jenkins/recipes/default.rb +0 -195
  217. data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +0 -54
  218. data/cookbooks/mu-jenkins/recipes/public_key.rb +0 -24
  219. data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +0 -24
  220. data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +0 -14
  221. data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +0 -6
  222. data/cookbooks/nagios/Berksfile +0 -11
  223. data/cookbooks/nagios/CHANGELOG.md +0 -589
  224. data/cookbooks/nagios/CONTRIBUTING.md +0 -11
  225. data/cookbooks/nagios/LICENSE +0 -37
  226. data/cookbooks/nagios/README.md +0 -328
  227. data/cookbooks/nagios/TESTING.md +0 -2
  228. data/cookbooks/nagios/attributes/config.rb +0 -171
  229. data/cookbooks/nagios/attributes/default.rb +0 -228
  230. data/cookbooks/nagios/chefignore +0 -102
  231. data/cookbooks/nagios/definitions/command.rb +0 -33
  232. data/cookbooks/nagios/definitions/contact.rb +0 -33
  233. data/cookbooks/nagios/definitions/contactgroup.rb +0 -33
  234. data/cookbooks/nagios/definitions/host.rb +0 -33
  235. data/cookbooks/nagios/definitions/hostdependency.rb +0 -33
  236. data/cookbooks/nagios/definitions/hostescalation.rb +0 -34
  237. data/cookbooks/nagios/definitions/hostgroup.rb +0 -33
  238. data/cookbooks/nagios/definitions/nagios_conf.rb +0 -38
  239. data/cookbooks/nagios/definitions/resource.rb +0 -33
  240. data/cookbooks/nagios/definitions/service.rb +0 -33
  241. data/cookbooks/nagios/definitions/servicedependency.rb +0 -33
  242. data/cookbooks/nagios/definitions/serviceescalation.rb +0 -34
  243. data/cookbooks/nagios/definitions/servicegroup.rb +0 -33
  244. data/cookbooks/nagios/definitions/timeperiod.rb +0 -33
  245. data/cookbooks/nagios/libraries/base.rb +0 -314
  246. data/cookbooks/nagios/libraries/command.rb +0 -91
  247. data/cookbooks/nagios/libraries/contact.rb +0 -230
  248. data/cookbooks/nagios/libraries/contactgroup.rb +0 -112
  249. data/cookbooks/nagios/libraries/custom_option.rb +0 -36
  250. data/cookbooks/nagios/libraries/data_bag_helper.rb +0 -23
  251. data/cookbooks/nagios/libraries/default.rb +0 -90
  252. data/cookbooks/nagios/libraries/host.rb +0 -412
  253. data/cookbooks/nagios/libraries/hostdependency.rb +0 -181
  254. data/cookbooks/nagios/libraries/hostescalation.rb +0 -173
  255. data/cookbooks/nagios/libraries/hostgroup.rb +0 -119
  256. data/cookbooks/nagios/libraries/nagios.rb +0 -282
  257. data/cookbooks/nagios/libraries/resource.rb +0 -59
  258. data/cookbooks/nagios/libraries/service.rb +0 -455
  259. data/cookbooks/nagios/libraries/servicedependency.rb +0 -215
  260. data/cookbooks/nagios/libraries/serviceescalation.rb +0 -195
  261. data/cookbooks/nagios/libraries/servicegroup.rb +0 -144
  262. data/cookbooks/nagios/libraries/timeperiod.rb +0 -160
  263. data/cookbooks/nagios/libraries/users_helper.rb +0 -54
  264. data/cookbooks/nagios/metadata.rb +0 -25
  265. data/cookbooks/nagios/recipes/_load_databag_config.rb +0 -153
  266. data/cookbooks/nagios/recipes/_load_default_config.rb +0 -241
  267. data/cookbooks/nagios/recipes/apache.rb +0 -48
  268. data/cookbooks/nagios/recipes/default.rb +0 -204
  269. data/cookbooks/nagios/recipes/nginx.rb +0 -82
  270. data/cookbooks/nagios/recipes/pagerduty.rb +0 -143
  271. data/cookbooks/nagios/recipes/server_package.rb +0 -40
  272. data/cookbooks/nagios/recipes/server_source.rb +0 -164
  273. data/cookbooks/nagios/templates/default/apache2.conf.erb +0 -96
  274. data/cookbooks/nagios/templates/default/cgi.cfg.erb +0 -266
  275. data/cookbooks/nagios/templates/default/commands.cfg.erb +0 -13
  276. data/cookbooks/nagios/templates/default/contacts.cfg.erb +0 -37
  277. data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +0 -25
  278. data/cookbooks/nagios/templates/default/hosts.cfg.erb +0 -15
  279. data/cookbooks/nagios/templates/default/htpasswd.users.erb +0 -6
  280. data/cookbooks/nagios/templates/default/nagios.cfg.erb +0 -22
  281. data/cookbooks/nagios/templates/default/nginx.conf.erb +0 -62
  282. data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +0 -185
  283. data/cookbooks/nagios/templates/default/resource.cfg.erb +0 -27
  284. data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +0 -15
  285. data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +0 -14
  286. data/cookbooks/nagios/templates/default/services.cfg.erb +0 -14
  287. data/cookbooks/nagios/templates/default/templates.cfg.erb +0 -31
  288. data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +0 -13
  289. data/extras/image-generators/aws/centos6.yaml +0 -18
  290. data/modules/mu/defaults/google_images.yaml +0 -16
  291. data/roles/mu-master-jenkins.json +0 -24
@@ -0,0 +1,257 @@
1
+ # Copyright:: Copyright (c) 2018 eGlobalTech, Inc., all rights reserved
2
+ #
3
+ # Licensed under the BSD-3 license (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License in the root of the project or at
6
+ #
7
+ # http://egt-labs.com/mu/LICENSE.html
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module MU
16
+ class Cloud
17
+ class Azure
18
+ # A user as configured in {MU::Config::BasketofKittens::users}
19
+ class User < MU::Cloud::User
20
+
21
+ # Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like <tt>@vpc</tt>, for us.
22
+ # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
23
+ def initialize(**args)
24
+ super
25
+
26
+ if !mu_name.nil?
27
+ @mu_name = mu_name
28
+ @cloud_id = Id.new(cloud_desc.id) if @cloud_id
29
+ else
30
+ @mu_name ||= @deploy.getResourceName(@config["name"], max_length: 31)
31
+ end
32
+
33
+ end
34
+
35
+ # Called automatically by {MU::Deploy#createResources}
36
+ def create
37
+ @config['region'] ||= MU::Cloud::Azure.myRegion(@config['credentials'])
38
+ rgroup_name = @deploy.deploy_id+"-"+@config['region'].upcase
39
+
40
+ tags = {}
41
+ if !@config['scrub_mu_isms']
42
+ tags = MU::MommaCat.listStandardTags
43
+ end
44
+ if @config['tags']
45
+ @config['tags'].each { |tag|
46
+ tags[tag['key']] = tag['value']
47
+ }
48
+ end
49
+
50
+ if @config['type'] == "interactive"
51
+ raise Mu::MuError, "I don't know how to make interactive users in Azure yet"
52
+ else
53
+ ident_obj = MU::Cloud::Azure.serviceaccts(:Identity).new
54
+ # ident_obj.name = @mu_name
55
+ ident_obj.location = @config['region']
56
+ ident_obj.tags = tags
57
+ begin
58
+ MU.log "Creating service account #{@mu_name}"
59
+ resp = MU::Cloud::Azure.serviceaccts(credentials: @config['credentials']).user_assigned_identities.create_or_update(rgroup_name, @mu_name, ident_obj)
60
+ @cloud_id = Id.new(resp.id)
61
+ rescue ::MsRestAzure::AzureOperationError => e
62
+ MU::Cloud::Azure.handleError(e)
63
+ end
64
+
65
+ begin
66
+ sleep 1
67
+ end while cloud_desc(use_cache: false).nil? or cloud_desc.client_id.nil?
68
+
69
+ end
70
+ end
71
+
72
+ # If we're a managed service identity or otherwise have a URL for
73
+ # fetching our client secret, fetch it and return it.
74
+ # XXX this doesn't work, and may not be intended to
75
+ # @return [String]
76
+ def getSecret
77
+ if cloud_desc and cloud_desc.client_secret_url
78
+ cred_hash = MU::Cloud::Azure.getSDKOptions(@credentials)
79
+
80
+ token_provider = MsRestAzure::ApplicationTokenProvider.new(
81
+ cred_hash[:tenant_id],
82
+ cred_hash[:client_id],
83
+ cred_hash[:client_secret]
84
+ )
85
+ cred_obj = MsRest::TokenCredentials.new(token_provider)
86
+
87
+ client = ::MsRest::ServiceClient.new(cred_obj)
88
+ cloud_desc.client_secret_url.match(/^(http.*?\.azure\.net)(\/.*)/)
89
+ base = Regexp.last_match[1]
90
+ path = Regexp.last_match[2]
91
+ #MU.log "Calling into #{base} #{path}"
92
+ promise = client.make_request_async(
93
+ cloud_desc.client_secret_url,
94
+ :get,
95
+ path
96
+ )
97
+
98
+ # XXX this is async, need to stop and wait somehow
99
+ promise.then do | result|
100
+ resp = result.response
101
+ # MU.log "RESPONSE", MU::WARN, details: resp
102
+ end
103
+ end
104
+ nil
105
+ end
106
+
107
+ # Called automatically by {MU::Deploy#createResources}
108
+ def groom
109
+ rgroup_name = @deploy.deploy_id+"-"+@config['region'].upcase
110
+ if @config['roles']
111
+ @config['roles'].each { |role|
112
+ MU::Cloud::Azure::Role.assignTo(cloud_desc.principal_id, role_name: role, credentials: @config['credentials'])
113
+ }
114
+ end
115
+ end
116
+
117
+ # Return the metadata for this user configuration
118
+ # @return [Hash]
119
+ def notify
120
+ description = MU.structToHash(cloud_desc)
121
+ if description
122
+ description.delete(:etag)
123
+ return description
124
+ end
125
+ {
126
+ }
127
+ end
128
+
129
+ # Does this resource type exist as a global (cloud-wide) artifact, or
130
+ # is it localized to a region/zone?
131
+ # @return [Boolean]
132
+ def self.isGlobal?
133
+ false
134
+ end
135
+
136
+ # Denote whether this resource implementation is experiment, ready for
137
+ # testing, or ready for production use.
138
+ def self.quality
139
+ MU::Cloud::ALPHA
140
+ end
141
+
142
+ # Stub method. Azure resources are cleaned up by removing the parent
143
+ # resource group.
144
+ # @return [void]
145
+ def self.cleanup(**args)
146
+ end
147
+
148
+ # Locate and return cloud provider descriptors of this resource type
149
+ # which match the provided parameters, or all visible resources if no
150
+ # filters are specified. At minimum, implementations of +find+ must
151
+ # honor +credentials+ and +cloud_id+ arguments. We may optionally
152
+ # support other search methods, such as +tag_key+ and +tag_value+, or
153
+ # cloud-specific arguments like +project+. See also {MU::MommaCat.findStray}.
154
+ # @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
155
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching resources
156
+ def self.find(**args)
157
+ found = {}
158
+
159
+ # XXX Had to register Microsoft.ApiManagement at https://portal.azure.com/#@eglobaltechlabs.onmicrosoft.com/resource/subscriptions/3d20ddd8-4652-4074-adda-0d127ef1f0e0/resourceproviders
160
+ # ffs automate this process, it's just like API enabling in GCP
161
+
162
+ # Azure resources are namedspaced by resource group. If we weren't
163
+ # told one, we may have to search all the ones we can see.
164
+ resource_groups = if args[:resource_group]
165
+ [args[:resource_group]]
166
+ elsif args[:cloud_id] and args[:cloud_id].is_a?(MU::Cloud::Azure::Id)
167
+ [args[:cloud_id].resource_group]
168
+ else
169
+ MU::Cloud::Azure.resources(credentials: args[:credentials]).resource_groups.list.map { |rg| rg.name }
170
+ end
171
+
172
+ if args[:cloud_id]
173
+ id_str = args[:cloud_id].is_a?(MU::Cloud::Azure::Id) ? args[:cloud_id].name : args[:cloud_id]
174
+ resource_groups.each { |rg|
175
+ resp = MU::Cloud::Azure.serviceaccts(credentials: args[:credentials]).user_assigned_identities.get(rg, id_str)
176
+ found[Id.new(resp.id)] = resp if resp
177
+ }
178
+ else
179
+ if args[:resource_group]
180
+ MU::Cloud::Azure.serviceaccts(credentials: args[:credentials]).user_assigned_identities.list_by_resource_group.each { |ident|
181
+ found[Id.new(ident.id)] = ident
182
+ }
183
+ else
184
+ MU::Cloud::Azure.serviceaccts(credentials: args[:credentials]).user_assigned_identities.list_by_subscription.each { |ident|
185
+ found[Id.new(ident.id)] = ident
186
+ }
187
+ end
188
+ end
189
+
190
+ found
191
+ end
192
+
193
+ # Cloud-specific configuration properties.
194
+ # @param config [MU::Config]: The calling MU::Config object
195
+ # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
196
+ def self.schema(config)
197
+ toplevel_required = []
198
+ schema = {
199
+ "region" => MU::Config.region_primitive,
200
+ "name" => {
201
+ "type" => "string",
202
+ "description" => "The name of a account to create. Currently, +service+ is the only account type we support in Azure."
203
+ },
204
+ "type" => {
205
+ "type" => "string",
206
+ "description" => "'service' will create a service account (machine credentials) and generate API keys",
207
+ "enum" => ["service"]
208
+ },
209
+ "roles" => {
210
+ "type" => "array",
211
+ "description" => "One or more Azure Authorization roles to associate with this resource.",
212
+ "default" => ["Reader"],
213
+ "items" => {
214
+ "type" => "string",
215
+ "description" => "One or more Azure Authorization roles to associate with this resource. If no roles are specified, we default to +Reader+, which permits read-only access subscription-wide."
216
+ }
217
+ }
218
+ }
219
+ [toplevel_required, schema]
220
+ end
221
+
222
+ # Cloud-specific pre-processing of {MU::Config::BasketofKittens::users}, bare and unvalidated.
223
+ # @param user [Hash]: The resource to process and validate
224
+ # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
225
+ # @return [Boolean]: True if validation succeeded, False otherwise
226
+ def self.validateConfig(user, configurator)
227
+ ok = true
228
+ user['region'] ||= MU::Cloud::Azure.myRegion(user['credentials'])
229
+
230
+ # if user['groups'] and user['groups'].size > 0 and
231
+ # !MU::Cloud::Azure.credConfig(user['credentials'])['masquerade_as']
232
+ # MU.log "Cannot change Azure group memberships in non-GSuite environments.\nVisit https://groups.google.com to manage groups.", MU::ERR
233
+ # ok = false
234
+ # end
235
+
236
+ if user['type'] != "service" and user["create_api_key"]
237
+ MU.log "Only service accounts can have API keys in Azure", MU::ERR
238
+ ok = false
239
+ end
240
+
241
+ if user['type'] != "service"
242
+ MU.log "Human accounts not yet supported in Azure::User", MU::ERR
243
+ ok = false
244
+ end
245
+
246
+ ok
247
+ end
248
+
249
+ private
250
+
251
+ def bind_human_user
252
+ end
253
+
254
+ end
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,4 @@
1
+
2
+ Baseline CloudInit userdata scripts for MU nodes to self-configure.
3
+
4
+ See also: https://help.ubuntu.com/community/CloudInit
@@ -0,0 +1,137 @@
1
+ #!/bin/sh
2
+ # Copyright:: Copyright (c) 2019 eGlobalTech, Inc., all rights reserved
3
+ #
4
+ # Licensed under the BSD-3 license (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License in the root of the project or at
7
+ #
8
+ # http://egt-labs.com/mu/LICENSE.html
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ updates_run=0
17
+ need_reboot=0
18
+ instance_id="`curl http://metadata.google.internal/computeMetadata/v1/instance/name`"
19
+ if [ -f /etc/debian_version ];then
20
+ if ! grep '^/bin/sh /var/lib/cloud/instance/user-data.txt$' /etc/rc.local > /dev/null;then
21
+ echo "/bin/sh /var/lib/cloud/instance/user-data.txt" >> /etc/rc.local
22
+ fi
23
+ apt-get update -y
24
+ if [ ! -f /usr/bin/curl ] ;then /usr/bin/apt-get --fix-missing -y install curl;fi
25
+ <% if !$mu.skipApplyUpdates %>
26
+ if [ ! -f /.mu-installer-ran-updates ];then
27
+ service ssh stop
28
+ apt-get --fix-missing -y upgrade
29
+ if [ $? -eq 0 ]
30
+ then
31
+ echo "Successfully updated packages"
32
+ updates_run=1
33
+ else
34
+ echo "FAILED PACKAGE UPDATE" >&2
35
+ fi
36
+ # Proceed regardless
37
+ touch /.mu-installer-ran-updates
38
+
39
+ # XXX this logic works on Ubuntu, is it Debian-friendly?
40
+ latest_kernel="`ls -1 /boot/vmlinuz-* | sed -r 's/^\/boot\/vmlinuz-//' | tail -1`"
41
+ running_kernel="`uname -r`"
42
+ if [ "$running_kernel" != "$latest_kernel" -a "$latest_kernel" != "" ];then
43
+ need_reboot=1
44
+ else
45
+ service ssh start
46
+ fi
47
+ fi
48
+ <% end %>
49
+ elif [ -x /usr/bin/yum ];then
50
+ version=`/bin/rpm -qa \*-release | grep -Ei "redhat|centos" | cut -d"-" -f3`
51
+ if [ -z "$version" ];then
52
+ amazon_version=`/bin/rpm -qa \*-release | grep -Ei "system-release"| cut -d"-" -f3 | cut -d"." -f1`
53
+ if [ "$amazon_version" == "2014" ] || [ "$amazon_version" == "2015" ] || [ "$amazon_version" == "2016" ];then
54
+ version=6
55
+ fi
56
+ fi
57
+ if [ $version -eq 7 ];then
58
+ userdata_dir="/var/lib/cloud/instances/$instance_id"
59
+ else
60
+ userdata_dir="/var/lib/cloud/instance"
61
+ fi
62
+ if ! grep "^/bin/sh $userdata_dir/user-data.txt$" /etc/rc.d/rc.local > /dev/null;then
63
+ echo "/bin/sh $userdata_dir/user-data.txt" >> /etc/rc.d/rc.local
64
+ fi
65
+
66
+ sed -i 's/^Defaults.*requiretty$/Defaults !requiretty/' /etc/sudoers
67
+
68
+ if [ $version == 7 ];then
69
+ chmod 755 /etc/rc.d/rc.local
70
+ fi
71
+ if [ ! -f /usr/bin/curl ] ;then /usr/bin/yum -y install curl;fi
72
+ # Ugh, rando EPEL mirror
73
+ if [ ! -f /etc/yum.repos.d/epel.repo ];then
74
+ /bin/rpm -ivh http://mirror.metrocast.net/fedora/epel/epel-release-latest-$version.noarch.rpm
75
+ fi
76
+ <% if !$mu.skipApplyUpdates %>
77
+ if [ ! -f /.mu-installer-ran-updates ];then
78
+ service sshd stop
79
+ kernel_update=`yum list updates | grep kernel`
80
+ yum -y update
81
+ if [ $? -eq 0 ]
82
+ then
83
+ echo "Successfully updated packages"
84
+ updates_run=1
85
+ else
86
+ echo "FAILED PACKAGE UPDATE" >&2
87
+ fi
88
+ # Proceed regardless
89
+ touch /.mu-installer-ran-updates
90
+ if [ -n "$kernel_update" ]; then
91
+ need_reboot=1
92
+ else
93
+ service sshd start
94
+ fi
95
+ fi
96
+ <% end %>
97
+ fi
98
+
99
+ umask 0077
100
+
101
+ # Install Chef now, because why not?
102
+ if [ ! -f /opt/chef/embedded/bin/ruby ];then
103
+ curl https://www.chef.io/chef/install.sh > chef-install.sh
104
+ set +e
105
+ # We may run afoul of a synchronous bootstrap process doing the same thing. So
106
+ # wait until we've managed to run successfully.
107
+ while ! sh chef-install.sh -v <%= $mu.chefVersion %>;do
108
+ sleep 10
109
+ done
110
+ touch /opt/mu_installed_chef
111
+ set -e
112
+ fi
113
+
114
+ <% if !$mu.skipApplyUpdates %>
115
+ if [ "$need_reboot" == "1" ];then
116
+ shutdown -r now "Applying new kernel"
117
+ fi
118
+ <% end %>
119
+
120
+ gsutil cp gs://<%= $mu.adminBucketName %>/<%= $mu.muID %>-secret .
121
+
122
+ echo '
123
+ require "openssl"
124
+ require "base64"
125
+ key = OpenSSL::PKey::RSA.new(Base64.urlsafe_decode64("<%= $mu.deployKey %>"))
126
+ print Base64.urlsafe_encode64(key.public_encrypt(File.read("<%= $mu.muID %>-secret")))
127
+ ' > encrypt_deploy_secret.rb
128
+
129
+ deploykey="<%= $mu.deployKey %>"
130
+ instance_id="`curl http://metadata.google.internal/computeMetadata/v1/instance/name`"
131
+
132
+ # Make double-sure sshd is actually up
133
+ service sshd restart
134
+
135
+ /usr/bin/curl -k --data mu_id="<%= $mu.muID %>" --data mu_resource_name="<%= $mu.resourceName %>" --data mu_resource_type="<%= $mu.resourceType %>" --data mu_instance_id="$instance_id" --data mu_bootstrap="1" --data mu_user="<%= $mu.muUser %>" --data mu_deploy_secret="`/opt/chef/embedded/bin/ruby encrypt_deploy_secret.rb`" https://<%= $mu.publicIP %>:<%= $mu.mommaCatPort %>/
136
+ /bin/rm -f <%= $mu.muID %>-secret mu_deploy_key.pub chef-install.sh encrypt_deploy_secret.rb
137
+ touch /.mu_userdata_complete
@@ -0,0 +1,275 @@
1
+ <powershell>
2
+ Set-ExecutionPolicy Unrestricted -Force -Scope CurrentUser
3
+
4
+ $sshdUser = "sshd_service"
5
+ $tmp = "$env:Temp\mu-userdata"
6
+ mkdir $tmp
7
+ $logfile = "c:/Mu-Bootstrap-$([Environment]::UserName).log"
8
+ $basedir = 'c:/bin'
9
+ $cygwin_dir = "$basedir/cygwin"
10
+ $username = (whoami).Split('\')[1]
11
+ $WebClient = New-Object System.Net.WebClient
12
+ $awsmeta = "http://169.254.169.254/latest"
13
+ $pydir = 'c:\bin\python\python27'
14
+ $pyv = '2.7.14'
15
+ $env:Path += ";$pydir\Scripts;$pydir"
16
+
17
+ function log
18
+ {
19
+ Write-Host $args
20
+ Add-Content "c:/Mu-Bootstrap-$([Environment]::UserName).log" "$(Get-Date -f MM-dd-yyyy_HH:mm:ss) $args"
21
+ Add-Content "c:/Mu-Bootstrap-GLOBAL.log" "$(Get-Date -f MM-dd-yyyy_HH:mm:ss) $args"
22
+ }
23
+
24
+ function fetchSecret([string]$file){
25
+ log "Fetching s3://<%= $mu.adminBucketName %>/$file to $tmp/$file"
26
+ aws.cmd s3 cp s3://<%= $mu.adminBucketName %>/$file $tmp/$file
27
+ }
28
+
29
+ function importCert([string]$cert, [string]$store){
30
+ fetchSecret($cert)
31
+ if(!(Test-Path "$tmp/$cert")){
32
+ return $null
33
+ }
34
+ # XXX guard better (check thumbprint & CN)
35
+ if($store -ne "Root"){
36
+ Remove-Item -Path Cert:/LocalMachine/$store/* -Force -Recurse
37
+ }
38
+ if($cert -Match ".pfx$"){
39
+ return Import-PfxCertificate -FilePath $tmp/$cert -CertStoreLocation Cert:\LocalMachine\$store
40
+ } else {
41
+ return Import-Certificate -FilePath $tmp/$cert -CertStoreLocation Cert:\LocalMachine\$store
42
+ }
43
+ Remove-Item -Force "$tmp/$cert"
44
+ }
45
+
46
+ log "- Invoked as $([Environment]::UserName) (system started at $(Get-CimInstance -ClassName win32_operatingsystem | select lastbootuptime)) -"
47
+ <% if !$mu.skipApplyUpdates %>
48
+ If (!(Test-Path "c:/mu-installer-ran-updates")){
49
+ Stop-Service -ErrorAction SilentlyContinue sshd
50
+ }
51
+ <% end %>
52
+ <% if $mu.platform != "win2k16" %>
53
+ If ([Environment]::OSVersion.Version.Major -lt 10) {
54
+ If ("$($myInvocation.MyCommand.Path)" -ne "$tmp/realuserdata_stripped.ps1"){
55
+ $Error.Clear()
56
+ Invoke-WebRequest -Uri "$awsmeta/user-data" -OutFile $tmp/realuserdata.ps1
57
+ while($Error.count -gt 0){
58
+ $Error.Clear()
59
+ log "Failed to retrieve current userdata from $awsmeta/user-data, waiting 15s and retrying"
60
+ sleep 15
61
+ Invoke-WebRequest -Uri "$awsmeta/user-data" -OutFile $tmp/realuserdata.ps1
62
+ }
63
+ Get-Content $tmp/realuserdata.ps1 | Select-String -pattern '^#','^<' -notmatch | Set-Content $tmp/realuserdata_stripped.ps1
64
+ If (Compare-Object (Get-Content $myInvocation.MyCommand.Path) (Get-Content $tmp/realuserdata_stripped.ps1)){
65
+ log "Invoking $tmp/realuserdata.ps1 in lieu of $($myInvocation.MyCommand.Path)"
66
+ Invoke-Expression $tmp/realuserdata_stripped.ps1
67
+ exit
68
+ }
69
+ }
70
+ }
71
+ <% end %>
72
+ $admin_username = (Get-WmiObject -Query 'Select * from Win32_UserAccount Where (LocalAccount=True and SID like "%-500")').name
73
+ log "Local admin: $admin_username"
74
+
75
+ Add-Type -Assembly System.Web
76
+ $password = [Web.Security.Membership]::GeneratePassword(15,2)
77
+
78
+ If (!(Test-Path $basedir)){
79
+ mkdir $basedir
80
+ }
81
+
82
+ <% if $mu.platform != "win2k16" %>
83
+ If ([Environment]::OSVersion.Version.Major -lt 10) {
84
+ If (!(Get-ScheduledTask -TaskName 'run-userdata')){
85
+ log "Adding run-userdata scheduled task (user NT AUTHORITY\SYSTEM)"
86
+ Invoke-WebRequest -Uri "https://s3.amazonaws.com/cloudamatic/run-userdata_scheduledtask.xml" -OutFile $tmp/run-userdata_scheduledtask.xml
87
+ Register-ScheduledTask -Xml (Get-Content "$tmp/run-userdata_scheduledtask.xml" | out-string) -TaskName 'run-userdata' -Force -User ".\$admin_username"
88
+ }
89
+ }
90
+ <% end %>
91
+
92
+ If (!(Test-Path "$pydir\python.exe")){
93
+ If (!(Test-Path $tmp\python-$pyv.msi)){
94
+ log "Downloading Python installer"
95
+ $WebClient.DownloadFile("https://www.python.org/ftp/python/$pyv/python-$pyv.msi","$tmp/python-$pyv.msi")
96
+ }
97
+ log "Running Python installer"
98
+ (Start-Process -FilePath msiexec -ArgumentList "/i $tmp\python-$pyv.msi /qn ALLUSERS=1 TARGETDIR=$pydir" -Wait -Passthru).ExitCode
99
+ }
100
+
101
+ If (!(Test-Path "$pydir\Scripts\aws.cmd")){
102
+ If (!(Test-Path $tmp/get-pip.py)){
103
+ log "Downloading get-pip.py"
104
+ $WebClient.DownloadFile("https://bootstrap.pypa.io/get-pip.py","$tmp/get-pip.py")
105
+ }
106
+ python $tmp/get-pip.py
107
+ log "Running pip install awscli"
108
+ pip install awscli
109
+ }
110
+
111
+ function removeChef($location){
112
+ $install_chef = $false
113
+ $my_chef = (Get-ItemProperty $location | Where-Object {$_.DisplayName -like "chef client*"}).DisplayName
114
+ if ($my_chef) {
115
+ if ($my_chef -match '<%= $mu.chefVersion %>'.split('-')[0]) {
116
+ $install_chef = $false
117
+ } else{
118
+ log "Uninstalling Chef"
119
+ $uninstall_string = (Get-ItemProperty $location | Where-Object {$_.DisplayName -like "chef client*"}).UninstallString
120
+ $uninstall_string = ($uninstall_string -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X","").Trim()
121
+ $($uninstall_string -Replace '[\s\t]+', ' ').Split() | ForEach {
122
+ log "msiexec.exe /X $_ /gn"
123
+ start-process "msiexec.exe" -arg "/X $_ /qn" -Wait
124
+ }
125
+ $install_chef = $true
126
+ }
127
+ }
128
+
129
+ return $install_chef
130
+ }
131
+
132
+ If (!(Test-Path "c:\opscode\chef\embedded\bin\ruby.exe")){
133
+ $install_chef = $true
134
+ } else {
135
+ if (removeChef("HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*")){
136
+ $install_chef = $true
137
+ } elseif (removeChef("HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*")) {
138
+ $install_chef = $true
139
+ } else {
140
+ $install_chef = $false
141
+ }
142
+ }
143
+
144
+ If ($install_chef){
145
+ log "Installing Chef <%= $mu.chefVersion %>"
146
+ If (!(Test-Path $env:Temp/chef-installer-<%= $mu.chefVersion %>.msi)){
147
+ log "Downloading Chef installer"
148
+ $WebClient.DownloadFile("https://www.chef.io/chef/download?p=windows&pv=2012&m=x86_64&v=<%= $mu.chefVersion %>","$env:Temp/chef-installer-<%= $mu.chefVersion %>.msi")
149
+ }
150
+ log "Running Chef installer"
151
+ (Start-Process -FilePath msiexec -ArgumentList "/i $env:Temp\chef-installer-<%= $mu.chefVersion %>.msi ALLUSERS=1 /le $env:Temp\chef-client-install.log /qn" -Wait -Passthru).ExitCode
152
+ Set-Content "c:/mu_installed_chef" "yup"
153
+ }
154
+
155
+ fetchSecret("<%= $mu.muID %>-secret")
156
+ log "Encrypting Mu deploy secret"
157
+ $deploy_secret = & "c:\opscode\chef\embedded\bin\ruby" -ropenssl -rbase64 -e "key = OpenSSL::PKey::RSA.new(Base64.urlsafe_decode64('<%= $mu.deployKey %>'))" -e "print Base64.urlsafe_encode64(key.public_encrypt(File.read('$tmp\<%= $mu.muID %>-secret')))"
158
+
159
+ function callMomma([string]$act)
160
+ {
161
+ $params = @{mu_id='<%= $mu.muID %>';mu_resource_name='<%= $mu.resourceName %>';mu_resource_type='<%= $mu.resourceType %>';mu_instance_id="$awsid";mu_user='<%= $mu.muUser %>';mu_deploy_secret="$deploy_secret";$act="1"}
162
+ log "Calling Momma Cat at https://<%= $mu.publicIP %>:<%= $mu.mommaCatPort %> with $act"
163
+ [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} # XXX
164
+ $resp = Invoke-WebRequest -Uri https://<%= $mu.publicIP %>:<%= $mu.mommaCatPort %> -Method POST -Body $params
165
+ return $resp.Content
166
+ }
167
+
168
+ $awsid=(New-Object System.Net.WebClient).DownloadString("$awsmeta/meta-data/instance-id")
169
+
170
+ $credstr = callMomma "mu_windows_admin_creds"
171
+ $creds = $false
172
+ $real_admin_user = $admin_username
173
+ if($credstr){
174
+ $credparts = $credstr.Split(";", 2)
175
+ $creds = New-Object System.Management.Automation.PSCredential($credparts[0], (ConvertTo-SecureString $credparts[1] -AsPlainText -Force))
176
+ if($admin_username -ne $credparts[0]){
177
+ if ((Get-WmiObject win32_computersystem).partofdomain -ne $true){
178
+ (([adsi]("WinNT://./$admin_username, user")).psbase.invoke("SetPassword", $credparts[1]))
179
+ log "Changing local admin account from $admin_username to $($credparts[0])"
180
+ ([adsi]("WinNT://./$admin_username, user")).psbase.rename($credparts[0])
181
+ $need_reboot = $TRUE
182
+ $real_admin_user = $credparts[0]
183
+ } ElseIf(!$admin_username){
184
+ $admin_username = $credparts[0]
185
+ }
186
+ } ElseIf($creds){
187
+ log "Setting $admin_username password"
188
+ (([adsi]("WinNT://./$admin_username, user")).psbase.invoke("SetPassword", $credparts[1]))
189
+ }
190
+ } else {
191
+ log "Failed to get credentials from Momma Cat for some reason $($credstr)"
192
+ }
193
+
194
+ If (!(Test-Path $tmp/PSWindowsUpdate.zip)){
195
+ If (!(Test-Path c:/Users/$admin_username/Documents/WindowsPowerShell/Modules)){
196
+ mkdir c:/Users/$admin_username/Documents/WindowsPowerShell/Modules
197
+ }
198
+
199
+ $WebClient.DownloadFile("https://s3.amazonaws.com/cloudamatic/PSWindowsUpdate.zip","$tmp/PSWindowsUpdate.zip")
200
+ Add-Type -A 'System.IO.Compression.FileSystem'
201
+
202
+ If (!(Test-Path c:/windows/System32/WindowsPowerShell/v1.0/Modules/PSWindowsUpdate)){
203
+ log "Extracting PSWindowsUpdate module to c:/windows/System32/WindowsPowerShell/v1.0/Modules"
204
+ [IO.Compression.ZipFile]::ExtractToDirectory("$tmp/PSWindowsUpdate.zip", "c:/windows/System32/WindowsPowerShell/v1.0/Modules")
205
+ }
206
+ If (!(Test-Path c:/Users/$admin_username/Documents/WindowsPowerShell/Modules/PSWindowsUpdate)){
207
+ log "Extracting PSWindowsUpdate module to c:/Users/$admin_username/Documents/WindowsPowerShell"
208
+ [IO.Compression.ZipFile]::ExtractToDirectory("$tmp/PSWindowsUpdate.zip", "c:/Users/$admin_username/Documents/WindowsPowerShell/Modules")
209
+ }
210
+ }
211
+
212
+ <% if !$mu.skipApplyUpdates %>
213
+ Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" -Name AUOptions -Value 3
214
+ If (!(Test-Path "c:/mu-installer-ran-updates")){
215
+ log "Applying Windows updates"
216
+ Import-Module PSWindowsUpdate
217
+ Get-WUInstall -AcceptAll -IgnoreReboot
218
+ Start-Sleep -s 60
219
+ If (Test-Path "HKLM:/SOFTWARE/Microsoft/Windows/CurrentVersion/WindowsUpdate/Auto Update/RebootRequired"){
220
+ $need_reboot = $TRUE
221
+ }
222
+ }
223
+ <% end %>
224
+
225
+ if((Get-WURebootStatus -Silent) -eq $true){
226
+ log "Get-WURebootStatus says to reboot"
227
+ $need_reboot = $TRUE
228
+ }
229
+
230
+ $muca = importCert "Mu_CA.pem" "Root"
231
+
232
+ $myname = "<%= $mu.muID %>-<%= $mu.resourceName.upcase %>"
233
+
234
+ $nodecert = importCert "$myname.pfx" "My"
235
+ $thumb = $nodecert.Thumbprint
236
+ # XXX guard this properly
237
+ winrm delete winrm/config/Listener?Address=*+Transport=HTTPS
238
+ winrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"$myname`";CertificateThumbprint=`"$thumb`"}"
239
+ $ingroup = net localgroup WinRMRemoteWMIUsers__ | Where-Object {$_ -eq $admin_username}
240
+ if($ingroup -ne $admin_username){
241
+ net localgroup WinRMRemoteWMIUsers__ /add $admin_username
242
+ }
243
+
244
+ $winrmcert = importCert "$myname-winrm.crt" "TrustedPeople"
245
+ Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
246
+ Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name LocalAccountTokenFilterPolicy -Value 1
247
+ if($creds){
248
+ log "Enabling WinRM cert auth for $real_admin_user"
249
+ New-Item -Path WSMan:\localhost\ClientCertificate -Subject "$real_admin_user@localhost" -URI * -Issuer $muca.Thumbprint -Force -Credential $creds
250
+ }
251
+ winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="8192"}'
252
+ winrm set winrm/config '@{MaxTimeoutms="1800000"}'
253
+ Restart-Service WinRm
254
+
255
+ if ($need_reboot){
256
+ log "- REBOOT -"
257
+ Restart-Computer -Force
258
+ exit
259
+ }
260
+
261
+ if (!(Get-NetFirewallRule -DisplayName "Allow SSH" -ErrorAction SilentlyContinue)){
262
+ log "Opening port 22 in Windows Firewall"
263
+ New-NetFirewallRule -DisplayName "Allow SSH" -Direction Inbound -LocalPort 22 -Protocol TCP -Action Allow
264
+ }
265
+ if (!(Get-NetFirewallRule -DisplayName "Allow WinRM SSL" -ErrorAction SilentlyContinue)){
266
+ New-NetFirewallRule -DisplayName "Allow WinRM SSL" -Direction Inbound -LocalPort 5986 -Protocol TCP -Action Allow
267
+ }
268
+
269
+ Add-Content c:/mu-installer-ran-updates "$(Get-Date -f MM-dd-yyyy_HH:mm:ss)"
270
+ callMomma "mu_bootstrap"
271
+ Set-Content "c:/mu_userdata_complete" "yup"
272
+ Remove-Item -Recurse $tmp
273
+ Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Undefined
274
+ </powershell>
275
+ <persist>true</persist>