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.
- checksums.yaml +5 -5
- data/Berksfile +4 -5
- data/Berksfile.lock +179 -0
- data/README.md +1 -6
- data/ansible/roles/geerlingguy.firewall/templates/firewall.bash.j2 +0 -0
- data/ansible/roles/mu-installer/README.md +33 -0
- data/ansible/roles/mu-installer/defaults/main.yml +2 -0
- data/ansible/roles/mu-installer/handlers/main.yml +2 -0
- data/ansible/roles/mu-installer/meta/main.yml +60 -0
- data/ansible/roles/mu-installer/tasks/main.yml +13 -0
- data/ansible/roles/mu-installer/tests/inventory +2 -0
- data/ansible/roles/mu-installer/tests/test.yml +5 -0
- data/ansible/roles/mu-installer/vars/main.yml +2 -0
- data/bin/mu-adopt +125 -0
- data/bin/mu-aws-setup +4 -4
- data/bin/mu-azure-setup +265 -0
- data/bin/mu-azure-tests +43 -0
- data/bin/mu-cleanup +20 -8
- data/bin/mu-configure +224 -98
- data/bin/mu-deploy +8 -3
- data/bin/mu-gcp-setup +16 -8
- data/bin/mu-gen-docs +92 -8
- data/bin/mu-load-config.rb +52 -12
- data/bin/mu-momma-cat +36 -0
- data/bin/mu-node-manage +34 -27
- data/bin/mu-self-update +2 -2
- data/bin/mu-ssh +12 -8
- data/bin/mu-upload-chef-artifacts +11 -4
- data/bin/mu-user-manage +3 -0
- data/cloud-mu.gemspec +8 -11
- data/cookbooks/firewall/libraries/helpers_iptables.rb +2 -2
- data/cookbooks/firewall/metadata.json +1 -1
- data/cookbooks/firewall/recipes/default.rb +5 -9
- data/cookbooks/mu-firewall/attributes/default.rb +2 -0
- data/cookbooks/mu-firewall/metadata.rb +1 -1
- data/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +0 -0
- data/cookbooks/mu-master/Berksfile +2 -2
- data/cookbooks/mu-master/files/default/check_mem.pl +0 -0
- data/cookbooks/mu-master/files/default/cloudamatic.png +0 -0
- data/cookbooks/mu-master/metadata.rb +5 -4
- data/cookbooks/mu-master/recipes/389ds.rb +1 -1
- data/cookbooks/mu-master/recipes/basepackages.rb +30 -10
- data/cookbooks/mu-master/recipes/default.rb +59 -7
- data/cookbooks/mu-master/recipes/firewall-holes.rb +1 -1
- data/cookbooks/mu-master/recipes/init.rb +65 -47
- data/cookbooks/mu-master/recipes/{eks-kubectl.rb → kubectl.rb} +4 -10
- data/cookbooks/mu-master/recipes/sssd.rb +2 -1
- data/cookbooks/mu-master/recipes/update_nagios_only.rb +6 -6
- data/cookbooks/mu-master/templates/default/web_app.conf.erb +2 -2
- data/cookbooks/mu-master/templates/mods/ldap.conf.erb +4 -0
- data/cookbooks/mu-php54/Berksfile +1 -2
- data/cookbooks/mu-php54/metadata.rb +4 -5
- data/cookbooks/mu-php54/recipes/default.rb +1 -1
- data/cookbooks/mu-splunk/templates/default/splunk-init.erb +0 -0
- data/cookbooks/mu-tools/Berksfile +3 -2
- data/cookbooks/mu-tools/files/default/Mu_CA.pem +33 -0
- data/cookbooks/mu-tools/libraries/helper.rb +20 -8
- data/cookbooks/mu-tools/metadata.rb +5 -2
- data/cookbooks/mu-tools/recipes/apply_security.rb +2 -3
- data/cookbooks/mu-tools/recipes/eks.rb +1 -1
- data/cookbooks/mu-tools/recipes/gcloud.rb +5 -30
- data/cookbooks/mu-tools/recipes/nagios.rb +1 -1
- data/cookbooks/mu-tools/recipes/rsyslog.rb +1 -0
- data/cookbooks/mu-tools/recipes/selinux.rb +19 -0
- data/cookbooks/mu-tools/recipes/split_var_partitions.rb +0 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +256 -122
- data/cookbooks/mu-tools/resources/disk.rb +3 -1
- data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +1 -1
- data/cookbooks/mu-tools/templates/default/etc_hosts.erb +1 -1
- data/cookbooks/mu-tools/templates/default/{kubeconfig.erb → kubeconfig-eks.erb} +0 -0
- data/cookbooks/mu-tools/templates/default/kubeconfig-gke.erb +27 -0
- data/cookbooks/mu-tools/templates/windows-10/sshd_config.erb +137 -0
- data/cookbooks/mu-utility/recipes/nat.rb +4 -0
- data/extras/alpha.png +0 -0
- data/extras/beta.png +0 -0
- data/extras/clean-stock-amis +2 -2
- data/extras/generate-stock-images +131 -0
- data/extras/git-fix-permissions-hook +0 -0
- data/extras/image-generators/AWS/centos6.yaml +17 -0
- data/extras/image-generators/{aws → AWS}/centos7-govcloud.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/centos7.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/rhel7.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/win2k12.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/win2k16.yaml +0 -0
- data/extras/image-generators/{aws → AWS}/windows.yaml +0 -0
- data/extras/image-generators/{gcp → Google}/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +18 -0
- data/extras/python_rpm/build.sh +0 -0
- data/extras/release.png +0 -0
- data/extras/ruby_rpm/build.sh +0 -0
- data/extras/ruby_rpm/muby.spec +1 -1
- data/install/README.md +43 -5
- data/install/deprecated-bash-library.sh +0 -0
- data/install/installer +1 -1
- data/install/jenkinskeys.rb +0 -0
- data/install/mu-master.yaml +55 -0
- data/modules/mommacat.ru +41 -7
- data/modules/mu.rb +444 -149
- data/modules/mu/adoption.rb +500 -0
- data/modules/mu/cleanup.rb +235 -158
- data/modules/mu/cloud.rb +675 -138
- data/modules/mu/clouds/aws.rb +156 -24
- data/modules/mu/clouds/aws/alarm.rb +4 -14
- data/modules/mu/clouds/aws/bucket.rb +60 -18
- data/modules/mu/clouds/aws/cache_cluster.rb +8 -20
- data/modules/mu/clouds/aws/collection.rb +12 -22
- data/modules/mu/clouds/aws/container_cluster.rb +209 -118
- data/modules/mu/clouds/aws/database.rb +120 -45
- data/modules/mu/clouds/aws/dnszone.rb +7 -18
- data/modules/mu/clouds/aws/endpoint.rb +5 -15
- data/modules/mu/clouds/aws/firewall_rule.rb +144 -72
- data/modules/mu/clouds/aws/folder.rb +4 -11
- data/modules/mu/clouds/aws/function.rb +6 -16
- data/modules/mu/clouds/aws/group.rb +4 -12
- data/modules/mu/clouds/aws/habitat.rb +11 -13
- data/modules/mu/clouds/aws/loadbalancer.rb +40 -28
- data/modules/mu/clouds/aws/log.rb +5 -13
- data/modules/mu/clouds/aws/msg_queue.rb +9 -24
- data/modules/mu/clouds/aws/nosqldb.rb +4 -12
- data/modules/mu/clouds/aws/notifier.rb +6 -13
- data/modules/mu/clouds/aws/role.rb +69 -40
- data/modules/mu/clouds/aws/search_domain.rb +17 -20
- data/modules/mu/clouds/aws/server.rb +184 -94
- data/modules/mu/clouds/aws/server_pool.rb +33 -38
- data/modules/mu/clouds/aws/storage_pool.rb +5 -12
- data/modules/mu/clouds/aws/user.rb +59 -33
- data/modules/mu/clouds/aws/userdata/linux.erb +18 -30
- data/modules/mu/clouds/aws/userdata/windows.erb +9 -9
- data/modules/mu/clouds/aws/vpc.rb +214 -145
- data/modules/mu/clouds/azure.rb +978 -44
- data/modules/mu/clouds/azure/container_cluster.rb +413 -0
- data/modules/mu/clouds/azure/firewall_rule.rb +500 -0
- data/modules/mu/clouds/azure/habitat.rb +167 -0
- data/modules/mu/clouds/azure/loadbalancer.rb +205 -0
- data/modules/mu/clouds/azure/role.rb +211 -0
- data/modules/mu/clouds/azure/server.rb +810 -0
- data/modules/mu/clouds/azure/user.rb +257 -0
- data/modules/mu/clouds/azure/userdata/README.md +4 -0
- data/modules/mu/clouds/azure/userdata/linux.erb +137 -0
- data/modules/mu/clouds/azure/userdata/windows.erb +275 -0
- data/modules/mu/clouds/azure/vpc.rb +782 -0
- data/modules/mu/clouds/cloudformation.rb +12 -9
- data/modules/mu/clouds/cloudformation/firewall_rule.rb +5 -13
- data/modules/mu/clouds/cloudformation/server.rb +10 -1
- data/modules/mu/clouds/cloudformation/server_pool.rb +1 -0
- data/modules/mu/clouds/cloudformation/vpc.rb +0 -2
- data/modules/mu/clouds/google.rb +554 -117
- data/modules/mu/clouds/google/bucket.rb +173 -32
- data/modules/mu/clouds/google/container_cluster.rb +1112 -157
- data/modules/mu/clouds/google/database.rb +24 -47
- data/modules/mu/clouds/google/firewall_rule.rb +344 -89
- data/modules/mu/clouds/google/folder.rb +156 -79
- data/modules/mu/clouds/google/group.rb +272 -82
- data/modules/mu/clouds/google/habitat.rb +177 -52
- data/modules/mu/clouds/google/loadbalancer.rb +9 -34
- data/modules/mu/clouds/google/role.rb +1211 -0
- data/modules/mu/clouds/google/server.rb +491 -227
- data/modules/mu/clouds/google/server_pool.rb +233 -48
- data/modules/mu/clouds/google/user.rb +479 -125
- data/modules/mu/clouds/google/userdata/linux.erb +3 -3
- data/modules/mu/clouds/google/userdata/windows.erb +9 -9
- data/modules/mu/clouds/google/vpc.rb +381 -223
- data/modules/mu/config.rb +689 -214
- data/modules/mu/config/bucket.rb +1 -1
- data/modules/mu/config/cache_cluster.rb +1 -1
- data/modules/mu/config/cache_cluster.yml +0 -4
- data/modules/mu/config/container_cluster.rb +18 -9
- data/modules/mu/config/database.rb +6 -23
- data/modules/mu/config/firewall_rule.rb +9 -15
- data/modules/mu/config/folder.rb +22 -21
- data/modules/mu/config/habitat.rb +22 -21
- data/modules/mu/config/loadbalancer.rb +2 -2
- data/modules/mu/config/role.rb +9 -40
- data/modules/mu/config/server.rb +26 -5
- data/modules/mu/config/server_pool.rb +1 -1
- data/modules/mu/config/storage_pool.rb +2 -2
- data/modules/mu/config/user.rb +4 -0
- data/modules/mu/config/vpc.rb +350 -110
- data/modules/mu/defaults/{amazon_images.yaml → AWS.yaml} +37 -39
- data/modules/mu/defaults/Azure.yaml +17 -0
- data/modules/mu/defaults/Google.yaml +24 -0
- data/modules/mu/defaults/README.md +1 -1
- data/modules/mu/deploy.rb +168 -125
- data/modules/mu/groomer.rb +2 -1
- data/modules/mu/groomers/ansible.rb +104 -32
- data/modules/mu/groomers/chef.rb +96 -44
- data/modules/mu/kittens.rb +20602 -0
- data/modules/mu/logger.rb +38 -11
- data/modules/mu/master.rb +90 -8
- data/modules/mu/master/chef.rb +2 -3
- data/modules/mu/master/ldap.rb +0 -1
- data/modules/mu/master/ssl.rb +250 -0
- data/modules/mu/mommacat.rb +917 -513
- data/modules/scratchpad.erb +1 -1
- data/modules/tests/super_complex_bok.yml +0 -0
- data/modules/tests/super_simple_bok.yml +0 -0
- data/roles/mu-master.json +2 -1
- data/spec/azure_creds +5 -0
- data/spec/mu.yaml +56 -0
- data/spec/mu/clouds/azure_spec.rb +164 -27
- data/spec/spec_helper.rb +5 -0
- data/test/clean_up.py +0 -0
- data/test/exec_inspec.py +0 -0
- data/test/exec_mu_install.py +0 -0
- data/test/exec_retry.py +0 -0
- data/test/smoke_test.rb +0 -0
- metadata +90 -118
- data/cookbooks/mu-jenkins/Berksfile +0 -14
- data/cookbooks/mu-jenkins/CHANGELOG.md +0 -13
- data/cookbooks/mu-jenkins/LICENSE +0 -37
- data/cookbooks/mu-jenkins/README.md +0 -105
- data/cookbooks/mu-jenkins/attributes/default.rb +0 -42
- data/cookbooks/mu-jenkins/files/default/cleanup_deploy_config.xml +0 -73
- data/cookbooks/mu-jenkins/files/default/deploy_config.xml +0 -44
- data/cookbooks/mu-jenkins/metadata.rb +0 -21
- data/cookbooks/mu-jenkins/recipes/default.rb +0 -195
- data/cookbooks/mu-jenkins/recipes/node-ssh-config.rb +0 -54
- data/cookbooks/mu-jenkins/recipes/public_key.rb +0 -24
- data/cookbooks/mu-jenkins/templates/default/example_job.config.xml.erb +0 -24
- data/cookbooks/mu-jenkins/templates/default/org.jvnet.hudson.plugins.SSHBuildWrapper.xml.erb +0 -14
- data/cookbooks/mu-jenkins/templates/default/ssh_config.erb +0 -6
- data/cookbooks/nagios/Berksfile +0 -11
- data/cookbooks/nagios/CHANGELOG.md +0 -589
- data/cookbooks/nagios/CONTRIBUTING.md +0 -11
- data/cookbooks/nagios/LICENSE +0 -37
- data/cookbooks/nagios/README.md +0 -328
- data/cookbooks/nagios/TESTING.md +0 -2
- data/cookbooks/nagios/attributes/config.rb +0 -171
- data/cookbooks/nagios/attributes/default.rb +0 -228
- data/cookbooks/nagios/chefignore +0 -102
- data/cookbooks/nagios/definitions/command.rb +0 -33
- data/cookbooks/nagios/definitions/contact.rb +0 -33
- data/cookbooks/nagios/definitions/contactgroup.rb +0 -33
- data/cookbooks/nagios/definitions/host.rb +0 -33
- data/cookbooks/nagios/definitions/hostdependency.rb +0 -33
- data/cookbooks/nagios/definitions/hostescalation.rb +0 -34
- data/cookbooks/nagios/definitions/hostgroup.rb +0 -33
- data/cookbooks/nagios/definitions/nagios_conf.rb +0 -38
- data/cookbooks/nagios/definitions/resource.rb +0 -33
- data/cookbooks/nagios/definitions/service.rb +0 -33
- data/cookbooks/nagios/definitions/servicedependency.rb +0 -33
- data/cookbooks/nagios/definitions/serviceescalation.rb +0 -34
- data/cookbooks/nagios/definitions/servicegroup.rb +0 -33
- data/cookbooks/nagios/definitions/timeperiod.rb +0 -33
- data/cookbooks/nagios/libraries/base.rb +0 -314
- data/cookbooks/nagios/libraries/command.rb +0 -91
- data/cookbooks/nagios/libraries/contact.rb +0 -230
- data/cookbooks/nagios/libraries/contactgroup.rb +0 -112
- data/cookbooks/nagios/libraries/custom_option.rb +0 -36
- data/cookbooks/nagios/libraries/data_bag_helper.rb +0 -23
- data/cookbooks/nagios/libraries/default.rb +0 -90
- data/cookbooks/nagios/libraries/host.rb +0 -412
- data/cookbooks/nagios/libraries/hostdependency.rb +0 -181
- data/cookbooks/nagios/libraries/hostescalation.rb +0 -173
- data/cookbooks/nagios/libraries/hostgroup.rb +0 -119
- data/cookbooks/nagios/libraries/nagios.rb +0 -282
- data/cookbooks/nagios/libraries/resource.rb +0 -59
- data/cookbooks/nagios/libraries/service.rb +0 -455
- data/cookbooks/nagios/libraries/servicedependency.rb +0 -215
- data/cookbooks/nagios/libraries/serviceescalation.rb +0 -195
- data/cookbooks/nagios/libraries/servicegroup.rb +0 -144
- data/cookbooks/nagios/libraries/timeperiod.rb +0 -160
- data/cookbooks/nagios/libraries/users_helper.rb +0 -54
- data/cookbooks/nagios/metadata.rb +0 -25
- data/cookbooks/nagios/recipes/_load_databag_config.rb +0 -153
- data/cookbooks/nagios/recipes/_load_default_config.rb +0 -241
- data/cookbooks/nagios/recipes/apache.rb +0 -48
- data/cookbooks/nagios/recipes/default.rb +0 -204
- data/cookbooks/nagios/recipes/nginx.rb +0 -82
- data/cookbooks/nagios/recipes/pagerduty.rb +0 -143
- data/cookbooks/nagios/recipes/server_package.rb +0 -40
- data/cookbooks/nagios/recipes/server_source.rb +0 -164
- data/cookbooks/nagios/templates/default/apache2.conf.erb +0 -96
- data/cookbooks/nagios/templates/default/cgi.cfg.erb +0 -266
- data/cookbooks/nagios/templates/default/commands.cfg.erb +0 -13
- data/cookbooks/nagios/templates/default/contacts.cfg.erb +0 -37
- data/cookbooks/nagios/templates/default/hostgroups.cfg.erb +0 -25
- data/cookbooks/nagios/templates/default/hosts.cfg.erb +0 -15
- data/cookbooks/nagios/templates/default/htpasswd.users.erb +0 -6
- data/cookbooks/nagios/templates/default/nagios.cfg.erb +0 -22
- data/cookbooks/nagios/templates/default/nginx.conf.erb +0 -62
- data/cookbooks/nagios/templates/default/pagerduty.cgi.erb +0 -185
- data/cookbooks/nagios/templates/default/resource.cfg.erb +0 -27
- data/cookbooks/nagios/templates/default/servicedependencies.cfg.erb +0 -15
- data/cookbooks/nagios/templates/default/servicegroups.cfg.erb +0 -14
- data/cookbooks/nagios/templates/default/services.cfg.erb +0 -14
- data/cookbooks/nagios/templates/default/templates.cfg.erb +0 -31
- data/cookbooks/nagios/templates/default/timeperiods.cfg.erb +0 -13
- data/extras/image-generators/aws/centos6.yaml +0 -18
- data/modules/mu/defaults/google_images.yaml +0 -16
- 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,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>
|