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
data/modules/mu/logger.rb
CHANGED
|
@@ -36,21 +36,24 @@ module MU
|
|
|
36
36
|
@verbosity = MU::Logger::NORMAL
|
|
37
37
|
@quiet = false
|
|
38
38
|
@html = false
|
|
39
|
+
@color = true
|
|
39
40
|
@handle = STDOUT
|
|
40
41
|
|
|
41
42
|
@@log_semaphere = Mutex.new
|
|
42
43
|
|
|
43
44
|
# @param verbosity [Integer]: See {MU::Logger.QUIET}, {MU::Logger.NORMAL}, {MU::Logger.LOUD}
|
|
44
45
|
# @param html [Boolean]: Enable web-friendly log output.
|
|
45
|
-
def initialize(verbosity=MU::Logger::NORMAL, html=false, handle=STDOUT)
|
|
46
|
+
def initialize(verbosity=MU::Logger::NORMAL, html=false, handle=STDOUT, color=true)
|
|
46
47
|
@verbosity = verbosity
|
|
47
48
|
@html = html
|
|
48
49
|
@handle = handle
|
|
50
|
+
@color = color
|
|
49
51
|
@summary = []
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
attr_reader :summary
|
|
53
55
|
attr_accessor :verbosity
|
|
56
|
+
attr_accessor :color
|
|
54
57
|
attr_accessor :quiet
|
|
55
58
|
attr_accessor :html
|
|
56
59
|
attr_accessor :handle
|
|
@@ -65,7 +68,8 @@ module MU
|
|
|
65
68
|
details: nil,
|
|
66
69
|
html: @html,
|
|
67
70
|
verbosity: @verbosity,
|
|
68
|
-
handle: @handle
|
|
71
|
+
handle: @handle,
|
|
72
|
+
color: @color
|
|
69
73
|
)
|
|
70
74
|
verbosity = MU::Logger::NORMAL if verbosity.nil?
|
|
71
75
|
return if verbosity == MU::Logger::SILENT
|
|
@@ -98,12 +102,14 @@ module MU
|
|
|
98
102
|
# We get passed literal quoted newlines sometimes, fix 'em. Get Windows'
|
|
99
103
|
# ugly line feeds too.
|
|
100
104
|
if !details.nil?
|
|
105
|
+
details = details.dup # in case it's frozen or something
|
|
101
106
|
details.gsub!(/\\n/, "\n")
|
|
102
107
|
details.gsub!(/(\\r|\r)/, "")
|
|
103
108
|
end
|
|
104
109
|
|
|
105
110
|
msg = msg.first if msg.is_a?(Array)
|
|
106
111
|
msg = "" if msg == nil
|
|
112
|
+
msg = msg.to_s if !msg.is_a?(String) and msg.respond_to?(:to_s)
|
|
107
113
|
|
|
108
114
|
@@log_semaphere.synchronize {
|
|
109
115
|
case level
|
|
@@ -114,9 +120,12 @@ module MU
|
|
|
114
120
|
if @html
|
|
115
121
|
html_out "#{time} - #{caller_name} - #{msg}", "orange"
|
|
116
122
|
html_out " #{details}" if details
|
|
117
|
-
|
|
123
|
+
elsif color
|
|
118
124
|
handle.puts "#{time} - #{caller_name} - #{msg}".yellow.on_black
|
|
119
125
|
handle.puts "#{details}".white.on_black if details
|
|
126
|
+
else
|
|
127
|
+
handle.puts "#{time} - #{caller_name} - #{msg}"
|
|
128
|
+
handle.puts "#{details}" if details
|
|
120
129
|
end
|
|
121
130
|
Syslog.log(Syslog::LOG_DEBUG, msg.gsub(/%/, ''))
|
|
122
131
|
Syslog.log(Syslog::LOG_DEBUG, details.gsub(/%/, '')) if details
|
|
@@ -125,14 +134,18 @@ module MU
|
|
|
125
134
|
if verbosity >= MU::Logger::NORMAL
|
|
126
135
|
if @html
|
|
127
136
|
html_out "#{time} - #{caller_name} - #{msg}", "green"
|
|
128
|
-
|
|
137
|
+
elsif color
|
|
129
138
|
handle.puts "#{time} - #{caller_name} - #{msg}".green.on_black
|
|
139
|
+
else
|
|
140
|
+
handle.puts "#{time} - #{caller_name} - #{msg}"
|
|
130
141
|
end
|
|
131
142
|
if verbosity >= MU::Logger::LOUD
|
|
132
143
|
if @html
|
|
133
144
|
html_out " #{details}"
|
|
134
|
-
|
|
145
|
+
elsif color
|
|
135
146
|
handle.puts "#{details}".white.on_black if details
|
|
147
|
+
else
|
|
148
|
+
handle.puts "#{details}" if details
|
|
136
149
|
end
|
|
137
150
|
end
|
|
138
151
|
Syslog.log(Syslog::LOG_NOTICE, msg.gsub(/%/, ''))
|
|
@@ -141,14 +154,18 @@ module MU
|
|
|
141
154
|
when NOTICE
|
|
142
155
|
if @html
|
|
143
156
|
html_out "#{time} - #{caller_name} - #{msg}", "yellow"
|
|
144
|
-
|
|
157
|
+
elsif color
|
|
145
158
|
handle.puts "#{time} - #{caller_name} - #{msg}".yellow.on_black
|
|
159
|
+
else
|
|
160
|
+
handle.puts "#{time} - #{caller_name} - #{msg}"
|
|
146
161
|
end
|
|
147
162
|
if verbosity >= MU::Logger::LOUD
|
|
148
163
|
if @html
|
|
149
164
|
html_out "#{caller_name} - #{msg}"
|
|
150
|
-
|
|
165
|
+
elsif color
|
|
151
166
|
handle.puts "#{details}".white.on_black if details
|
|
167
|
+
else
|
|
168
|
+
handle.puts "#{details}" if details
|
|
152
169
|
end
|
|
153
170
|
end
|
|
154
171
|
Syslog.log(Syslog::LOG_NOTICE, msg.gsub(/%/, ''))
|
|
@@ -156,14 +173,18 @@ module MU
|
|
|
156
173
|
when WARN
|
|
157
174
|
if @html
|
|
158
175
|
html_out "#{time} - #{caller_name} - #{msg}", "orange"
|
|
159
|
-
|
|
176
|
+
elsif color
|
|
160
177
|
handle.puts "#{time} - #{caller_name} - #{msg}".light_red.on_black
|
|
178
|
+
else
|
|
179
|
+
handle.puts "#{time} - #{caller_name} - #{msg}"
|
|
161
180
|
end
|
|
162
181
|
if verbosity >= MU::Logger::LOUD
|
|
163
182
|
if @html
|
|
164
183
|
html_out "#{caller_name} - #{msg}"
|
|
165
|
-
|
|
184
|
+
elsif color
|
|
166
185
|
handle.puts "#{details}".white.on_black if details
|
|
186
|
+
else
|
|
187
|
+
handle.puts "#{details}" if details
|
|
167
188
|
end
|
|
168
189
|
end
|
|
169
190
|
Syslog.log(Syslog::LOG_WARNING, msg.gsub(/%/, ''))
|
|
@@ -172,9 +193,12 @@ module MU
|
|
|
172
193
|
if @html
|
|
173
194
|
html_out "#{time} - #{caller_name} - #{msg}", "red"
|
|
174
195
|
html_out " #{details}" if details
|
|
175
|
-
|
|
196
|
+
elsif color
|
|
176
197
|
handle.puts "#{time} - #{caller_name} - #{msg}".red.on_black
|
|
177
198
|
handle.puts "#{details}".white.on_black if details
|
|
199
|
+
else
|
|
200
|
+
handle.puts "#{time} - #{caller_name} - #{msg}"
|
|
201
|
+
handle.puts "#{details}" if details
|
|
178
202
|
end
|
|
179
203
|
Syslog.log(Syslog::LOG_ERR, msg.gsub(/%/, ''))
|
|
180
204
|
Syslog.log(Syslog::LOG_ERR, details.gsub(/%/, '')) if details
|
|
@@ -182,9 +206,12 @@ module MU
|
|
|
182
206
|
if @html
|
|
183
207
|
html_out "#{time} - #{caller_name} - #{msg}"
|
|
184
208
|
html_out " #{details}" if details
|
|
185
|
-
|
|
209
|
+
elsif color
|
|
186
210
|
handle.puts "#{time} - #{caller_name} - #{msg}".white.on_black
|
|
187
211
|
handle.puts "#{details}".white.on_black if details
|
|
212
|
+
else
|
|
213
|
+
handle.puts "#{time} - #{caller_name} - #{msg}"
|
|
214
|
+
handle.puts "#{details}" if details
|
|
188
215
|
end
|
|
189
216
|
Syslog.log(Syslog::LOG_NOTICE, msg.gsub(/%/, ''))
|
|
190
217
|
Syslog.log(Syslog::LOG_NOTICE, details.gsub(/%/, '')) if details
|
data/modules/mu/master.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/local/ruby-current/bin/ruby
|
|
2
1
|
# Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the BSD-3 license (the "License");
|
|
@@ -23,6 +22,7 @@ module MU
|
|
|
23
22
|
require 'fileutils'
|
|
24
23
|
autoload :Chef, 'mu/master/chef'
|
|
25
24
|
autoload :LDAP, 'mu/master/ldap'
|
|
25
|
+
autoload :SSL, 'mu/master/ssl'
|
|
26
26
|
|
|
27
27
|
# @param users [Hash]: User metadata of the type returned by listUsers
|
|
28
28
|
def self.printUsersToTerminal(users = MU::Master.listUsers)
|
|
@@ -169,7 +169,7 @@ module MU
|
|
|
169
169
|
itemname = Password.pronounceable(32)
|
|
170
170
|
# Make sure this itemname isn't already in use
|
|
171
171
|
MU::Groomer::Chef.getSecret(vault: "scratchpad", item: itemname)
|
|
172
|
-
rescue MU::Groomer::
|
|
172
|
+
rescue MU::Groomer::MuNoSuchSecret
|
|
173
173
|
MU::Groomer::Chef.saveSecret(vault: "scratchpad", item: itemname, data: data)
|
|
174
174
|
return itemname
|
|
175
175
|
end while true
|
|
@@ -195,7 +195,7 @@ module MU
|
|
|
195
195
|
end
|
|
196
196
|
alias_device = cryptfile ? "/dev/mapper/"+path.gsub(/[^0-9a-z_\-]/i, "_") : realdevice
|
|
197
197
|
|
|
198
|
-
if !File.
|
|
198
|
+
if !File.exist?(realdevice)
|
|
199
199
|
MU.log "Creating #{path} volume"
|
|
200
200
|
if MU::Cloud::AWS.hosted?
|
|
201
201
|
dummy_svr = MU::Cloud::AWS::Server.new(
|
|
@@ -250,7 +250,7 @@ module MU
|
|
|
250
250
|
keyfile.close
|
|
251
251
|
|
|
252
252
|
# we can assume that mu-master::init installed cryptsetup-luks
|
|
253
|
-
if !File.
|
|
253
|
+
if !File.exist?(alias_device)
|
|
254
254
|
MU.log "Initializing crypto on #{alias_device}", MU::NOTICE
|
|
255
255
|
%x{/sbin/cryptsetup luksFormat #{realdevice} #{keyfile.path} --batch-mode}
|
|
256
256
|
%x{/sbin/cryptsetup luksOpen #{realdevice} #{alias_device.gsub(/.*?\/([^\/]+)$/, '\1')} --key-file #{keyfile.path}}
|
|
@@ -264,7 +264,7 @@ module MU
|
|
|
264
264
|
%x{/sbin/mkfs.xfs "#{alias_device}"}
|
|
265
265
|
%x{/usr/sbin/xfs_admin -L "#{path.gsub(/[^0-9a-z_\-]/i, "_")}" "#{alias_device}"}
|
|
266
266
|
end
|
|
267
|
-
Dir.mkdir(path, 0700) if !Dir.
|
|
267
|
+
Dir.mkdir(path, 0700) if !Dir.exist?(path) # XXX recursive
|
|
268
268
|
%x{/usr/sbin/xfs_info "#{alias_device}" > /dev/null 2>&1}
|
|
269
269
|
if $?.exitstatus != 0
|
|
270
270
|
MU.log "Mounting #{alias_device} to #{path}"
|
|
@@ -292,7 +292,7 @@ module MU
|
|
|
292
292
|
|
|
293
293
|
# Remove Scratchpad entries which have exceeded their maximum age.
|
|
294
294
|
def self.cleanExpiredScratchpads
|
|
295
|
-
return if !$MU_CFG['scratchpad'].has_key?('max_age') or $MU_CFG['scratchpad']['max_age'] < 1
|
|
295
|
+
return if !$MU_CFG['scratchpad'] or !$MU_CFG['scratchpad'].has_key?('max_age') or $MU_CFG['scratchpad']['max_age'] < 1
|
|
296
296
|
@scratchpad_semaphore.synchronize {
|
|
297
297
|
entries = MU::Groomer::Chef.getSecret(vault: "scratchpad")
|
|
298
298
|
entries.each { |pad|
|
|
@@ -347,8 +347,8 @@ module MU
|
|
|
347
347
|
ldap_users['mu'] = {}
|
|
348
348
|
ldap_users['mu']['admin'] = true
|
|
349
349
|
ldap_users['mu']['non_ldap'] = true
|
|
350
|
-
ldap_users.each_pair { |
|
|
351
|
-
key =
|
|
350
|
+
ldap_users.each_pair { |uname, data|
|
|
351
|
+
key = uname.to_s
|
|
352
352
|
all_user_data[key] = {}
|
|
353
353
|
userdir = $MU_CFG['installdir']+"/var/users/#{key}"
|
|
354
354
|
if !Dir.exist?(userdir)
|
|
@@ -369,6 +369,88 @@ module MU
|
|
|
369
369
|
all_user_data
|
|
370
370
|
end
|
|
371
371
|
|
|
372
|
+
|
|
373
|
+
@@kubectl_path = nil
|
|
374
|
+
# Locate a working +kubectl+ executable and return its fully-qualified
|
|
375
|
+
# path.
|
|
376
|
+
def self.kubectl
|
|
377
|
+
return @@kubectl_path if @@kubectl_path
|
|
378
|
+
|
|
379
|
+
paths = ["/opt/mu/bin"]+ENV['PATH'].split(/:/)
|
|
380
|
+
best = nil
|
|
381
|
+
best_version = nil
|
|
382
|
+
paths.uniq.each { |path|
|
|
383
|
+
if File.exist?(path+"/kubectl")
|
|
384
|
+
version = %x{#{path}/kubectl version --short --client}.chomp.sub(/.*Client version:\s+v/i, '')
|
|
385
|
+
next if !$?.success?
|
|
386
|
+
if !best_version or MU.version_sort(best_version, version) > 0
|
|
387
|
+
best_version = version
|
|
388
|
+
best = path+"/kubectl"
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
}
|
|
392
|
+
if !best
|
|
393
|
+
MU.log "Failed to find a working kubectl executable in any path", MU::WARN, details: paths.uniq.sort
|
|
394
|
+
return nil
|
|
395
|
+
else
|
|
396
|
+
MU.log "Kubernetes commands will use #{best} (#{best_version})"
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
@@kubectl_path = best
|
|
400
|
+
@@kubectl_path
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# Given an array of hashes representing Kubernetes resources,
|
|
404
|
+
def self.applyKubernetesResources(name, blobs = [], kubeconfig: nil, outputdir: nil)
|
|
405
|
+
use_tmp = false
|
|
406
|
+
if !outputdir
|
|
407
|
+
require 'tempfile'
|
|
408
|
+
use_tmp = true
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
count = 0
|
|
412
|
+
blobs.each { |blob|
|
|
413
|
+
f = nil
|
|
414
|
+
blobfile = if use_tmp
|
|
415
|
+
f = Tempfile.new("k8s-resource-#{count.to_s}-#{name}")
|
|
416
|
+
f.puts blob.to_yaml
|
|
417
|
+
f.close
|
|
418
|
+
f.path
|
|
419
|
+
else
|
|
420
|
+
path = outputdir+"/k8s-resource-#{count.to_s}-#{name}"
|
|
421
|
+
File.open(path, "w") { |fh|
|
|
422
|
+
fh.puts blob.to_yaml
|
|
423
|
+
}
|
|
424
|
+
path
|
|
425
|
+
end
|
|
426
|
+
next if !kubectl
|
|
427
|
+
done = false
|
|
428
|
+
retries = 0
|
|
429
|
+
begin
|
|
430
|
+
%x{#{kubectl} --kubeconfig "#{kubeconfig}" get -f #{blobfile} > /dev/null 2>&1}
|
|
431
|
+
arg = $?.exitstatus == 0 ? "apply" : "create"
|
|
432
|
+
cmd = %Q{#{kubectl} --kubeconfig "#{kubeconfig}" #{arg} -f #{blobfile}}
|
|
433
|
+
MU.log "Applying Kubernetes resource #{count.to_s} with kubectl #{arg}", MU::NOTICE, details: cmd
|
|
434
|
+
output = %x{#{cmd} 2>&1}
|
|
435
|
+
if $?.exitstatus == 0
|
|
436
|
+
MU.log "Kubernetes resource #{count.to_s} #{arg} was successful: #{output}", details: blob.to_yaml
|
|
437
|
+
done = true
|
|
438
|
+
else
|
|
439
|
+
MU.log "Kubernetes resource #{count.to_s} #{arg} failed: #{output}", MU::WARN, details: blob.to_yaml
|
|
440
|
+
if retries < 5
|
|
441
|
+
sleep 5
|
|
442
|
+
else
|
|
443
|
+
MU.log "Giving up on Kubernetes resource #{count.to_s} #{arg}"
|
|
444
|
+
done = true
|
|
445
|
+
end
|
|
446
|
+
retries += 1
|
|
447
|
+
end
|
|
448
|
+
f.unlink if use_tmp
|
|
449
|
+
end while !done
|
|
450
|
+
count += 1
|
|
451
|
+
}
|
|
452
|
+
end
|
|
453
|
+
|
|
372
454
|
# Update Mu's local cache/metadata for the given user, fixing permissions
|
|
373
455
|
# and updating stored values. Create a single-user group for the user, as
|
|
374
456
|
# well.
|
data/modules/mu/master/chef.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/local/ruby-current/bin/ruby
|
|
2
1
|
# Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the BSD-3 license (the "License");
|
|
@@ -112,7 +111,7 @@ module MU
|
|
|
112
111
|
f.puts "chef_server_url 'https://#{$MU_CFG["public_address"]}/organizations/#{chef_user}'"
|
|
113
112
|
f.puts "validation_client_name '#{chef_user}-validator'"
|
|
114
113
|
}
|
|
115
|
-
if !File.
|
|
114
|
+
if !File.exist?("#{chefdir}/client.rb") or
|
|
116
115
|
File.read("#{chefdir}/client.rb") != File.read("#{chefdir}/client.rb.tmp.#{Process.pid}")
|
|
117
116
|
File.rename(chefdir+"/client.rb.tmp.#{Process.pid}", chefdir+"/client.rb")
|
|
118
117
|
FileUtils.chown_R(user, user+".mu-user", Etc.getpwnam(user).dir+"/.chef")
|
|
@@ -143,7 +142,7 @@ module MU
|
|
|
143
142
|
# f.puts "verify_api_cert false"
|
|
144
143
|
# f.puts "ssl_verify_mode :verify_none"
|
|
145
144
|
}
|
|
146
|
-
if !File.
|
|
145
|
+
if !File.exist?("#{chefdir}/knife.rb") or
|
|
147
146
|
File.read("#{chefdir}/knife.rb") != File.read("#{chefdir}/knife.rb.tmp.#{Process.pid}")
|
|
148
147
|
File.rename(chefdir+"/knife.rb.tmp.#{Process.pid}", chefdir+"/knife.rb")
|
|
149
148
|
FileUtils.chown_R(user, user+".mu-user", Etc.getpwnam(user).dir+"/.chef")
|
data/modules/mu/master/ldap.rb
CHANGED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Copyright:: Copyright (c) 2019 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 Master
|
|
17
|
+
# Create and manage our own internal SSL signing authority
|
|
18
|
+
class SSL
|
|
19
|
+
|
|
20
|
+
# List of Mu services for which we'll generate SSL certs signed by our
|
|
21
|
+
# authority.
|
|
22
|
+
SERVICES = ["rsyslog", "mommacat", "ldap", "consul", "vault"]
|
|
23
|
+
|
|
24
|
+
# Exception class for when we can't find the +openssl+ command
|
|
25
|
+
class MuSSLNotFound < MU::MuError;end
|
|
26
|
+
|
|
27
|
+
# TODO set file/dir ownerships to honor for_user if we were invoked as root
|
|
28
|
+
|
|
29
|
+
# @param for_user [String]
|
|
30
|
+
def self.bootstrap(for_user: MU.mu_user)
|
|
31
|
+
ssldir = MU.dataDir(for_user)+"/ssl"
|
|
32
|
+
Dir.mkdir(ssldir, 0755) if !Dir.exist?(ssldir)
|
|
33
|
+
|
|
34
|
+
alt_names = [MU.mu_public_ip, MU.my_private_ip, MU.mu_public_addr, Socket.gethostbyname(Socket.gethostname).first, "localhost", "127.0.0.1"].uniq
|
|
35
|
+
alt_names.reject! { |s| s.nil? }
|
|
36
|
+
|
|
37
|
+
getCert("Mu_CA", "/CN=#{MU.mu_public_addr}/OU=Mu Server at #{MU.mu_public_addr}/O=eGlobalTech/C=US", sans: alt_names, ca: true)
|
|
38
|
+
|
|
39
|
+
SERVICES.each { |service|
|
|
40
|
+
getCert(service, "/CN=#{MU.mu_public_addr}/OU=Mu #{service}/O=eGlobalTech/C=US", sans: alt_names)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @param name [String]
|
|
46
|
+
# @param for_user [String]
|
|
47
|
+
# @return [OpenSSL::PKey::RSA]
|
|
48
|
+
def self.getKey(name, for_user: MU.mu_user, keysize: 4096)
|
|
49
|
+
ssldir = MU.dataDir(for_user)+"/ssl"
|
|
50
|
+
if !File.exist?(ssldir+"/"+name+".key")
|
|
51
|
+
key = OpenSSL::PKey::RSA.new keysize
|
|
52
|
+
File.write(ssldir+"/"+name+".key", key)
|
|
53
|
+
end
|
|
54
|
+
File.chmod(0400, ssldir+"/"+name+".key")
|
|
55
|
+
OpenSSL::PKey::RSA.new(File.read(ssldir+"/"+name+".key"))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @param for_user [String]
|
|
59
|
+
# @return [Integer]
|
|
60
|
+
def self.incrementCASerial(for_user: MU.mu_user)
|
|
61
|
+
ssldir = MU.dataDir(for_user)+"/ssl"
|
|
62
|
+
cur = 0
|
|
63
|
+
if File.exist?(ssldir+"/serial")
|
|
64
|
+
cur = File.read(ssldir+"/serial").chomp.to_i
|
|
65
|
+
end
|
|
66
|
+
File.open("#{ssldir}/serial", File::CREAT|File::RDWR, 0600) { |f|
|
|
67
|
+
f.flock(File::LOCK_EX)
|
|
68
|
+
cur += 1
|
|
69
|
+
f.rewind
|
|
70
|
+
f.truncate(0)
|
|
71
|
+
f.puts cur
|
|
72
|
+
f.flush
|
|
73
|
+
f.flock(File::LOCK_UN)
|
|
74
|
+
}
|
|
75
|
+
cur
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# Given a Certificate Signing Request, sign it with our internal CA and
|
|
80
|
+
# write the resulting signed certificate. Only works on local files.
|
|
81
|
+
# @param csr_path [String]: The CSR to sign, as a file.
|
|
82
|
+
def self.sign(csr_path, sans = [], for_user: MU.mu_user)
|
|
83
|
+
certdir = File.dirname(csr_path)
|
|
84
|
+
certname = File.basename(csr_path, ".csr")
|
|
85
|
+
if File.exist?("#{certdir}/#{certname}.crt")
|
|
86
|
+
MU.log "Not re-signing SSL certificate request #{csr_path}, #{certdir}/#{certname}.crt already exists", MU::DEBUG
|
|
87
|
+
return
|
|
88
|
+
end
|
|
89
|
+
MU.log "Signing SSL certificate request #{csr_path} with #{MU.mySSLDir}/Mu_CA.pem"
|
|
90
|
+
|
|
91
|
+
begin
|
|
92
|
+
csr = OpenSSL::X509::Request.new File.read csr_path
|
|
93
|
+
rescue Exception => e
|
|
94
|
+
MU.log e.message, MU::ERR, details: File.read(csr_path)
|
|
95
|
+
raise e
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
cakey = getKey("Mu_CA")
|
|
99
|
+
cacert = getCert("Mu_CA", ca: true).first
|
|
100
|
+
|
|
101
|
+
cert = OpenSSL::X509::Certificate.new
|
|
102
|
+
cert.serial = incrementCASerial(for_user: for_user)
|
|
103
|
+
cert.version = 0x2
|
|
104
|
+
cert.not_before = Time.now
|
|
105
|
+
cert.not_after = Time.now + 180000000
|
|
106
|
+
cert.subject = csr.subject
|
|
107
|
+
cert.public_key = csr.public_key
|
|
108
|
+
cert.issuer = cacert.subject
|
|
109
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
|
110
|
+
ef.issuer_certificate = cacert
|
|
111
|
+
ef.subject_certificate = cert
|
|
112
|
+
ef.subject_request = csr
|
|
113
|
+
if !sans.nil? and !sans.empty? and
|
|
114
|
+
!formatSANS(sans).nil? and !formatSANS(sans).empty?
|
|
115
|
+
cert.add_extension(ef.create_extension("subjectAltName",formatSANS(sans),false))
|
|
116
|
+
end
|
|
117
|
+
cert.add_extension(ef.create_extension("keyUsage","nonRepudiation,digitalSignature,keyEncipherment", false))
|
|
118
|
+
cert.add_extension(ef.create_extension("extendedKeyUsage","clientAuth,serverAuth,codeSigning,emailProtection",false))
|
|
119
|
+
cert.sign cakey, OpenSSL::Digest::SHA256.new
|
|
120
|
+
|
|
121
|
+
File.open("#{certdir}/#{certname}.crt", 'w', 0644) { |f|
|
|
122
|
+
f.write cert.to_pem
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
cert
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @param name [String]
|
|
129
|
+
# @param cn_str [String]
|
|
130
|
+
# @param sans [Array<String>]
|
|
131
|
+
# @param ca [Array<String>]
|
|
132
|
+
# @param for_user [String]
|
|
133
|
+
# @return [OpenSSL::X509::Certificate]
|
|
134
|
+
def self.getReq(name, cn_str = nil, sans: [], ca: false, for_user: MU.mu_user)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# @param name [String]
|
|
138
|
+
# @param cn_str [String]
|
|
139
|
+
# @param sans [Array<String>]
|
|
140
|
+
# @param ca [Array<String>]
|
|
141
|
+
# @param for_user [String]
|
|
142
|
+
# @param pfx [Boolean]
|
|
143
|
+
# @return [OpenSSL::X509::Certificate]
|
|
144
|
+
def self.getCert(name, cn_str = nil, sans: [], ca: false, for_user: MU.mu_user, pfx: false)
|
|
145
|
+
ssldir = MU.dataDir(for_user)+"/ssl"
|
|
146
|
+
filename = ca ? "#{ssldir}/#{name}.pem" : "#{ssldir}/#{name}.crt"
|
|
147
|
+
keyfile = "#{ssldir}/#{name}.key"
|
|
148
|
+
pfxfile = "#{ssldir}/#{name}.pfx"
|
|
149
|
+
pfx_cert = nil
|
|
150
|
+
|
|
151
|
+
if File.exist?(filename)
|
|
152
|
+
pfx_cert = toPfx(filename, keyfile, pfxfile) if pfx
|
|
153
|
+
cert = OpenSSL::X509::Certificate.new(File.read(filename))
|
|
154
|
+
return [cert, pfx_cert]
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
if cn_str.nil?
|
|
158
|
+
raise MuError, "Can't generate an SSL cert for #{name} without a CN"
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
key = getKey(name, for_user: for_user)
|
|
162
|
+
|
|
163
|
+
puts cn_str
|
|
164
|
+
cn = OpenSSL::X509::Name.parse(cn_str)
|
|
165
|
+
|
|
166
|
+
# If we're generating our local CA, we're not really doing a CSR, but
|
|
167
|
+
# the operation is close to identical.
|
|
168
|
+
csr = if ca
|
|
169
|
+
MU.log "Generating Mu CA certificate", MU::NOTICE, details: filename
|
|
170
|
+
csr = OpenSSL::X509::Certificate.new
|
|
171
|
+
csr.not_before = Time.now
|
|
172
|
+
csr.not_after = Time.now + 180000000
|
|
173
|
+
csr
|
|
174
|
+
else
|
|
175
|
+
MU.log "Generating Mu-signed certificate for #{name}", MU::NOTICE, details: filename
|
|
176
|
+
OpenSSL::X509::Request.new
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
csr.version = 0x2 # by which we mean '3'
|
|
180
|
+
csr.subject = cn
|
|
181
|
+
csr.public_key = key.public_key
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
# If we're the CA certificate, declare ourselves our own issuer and
|
|
185
|
+
# write, instead of going through the rest of the motions.
|
|
186
|
+
if ca
|
|
187
|
+
csr.issuer = csr.subject
|
|
188
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
|
189
|
+
csr.serial = 1
|
|
190
|
+
ef.subject_certificate = csr
|
|
191
|
+
ef.issuer_certificate = csr
|
|
192
|
+
csr.add_extension(ef.create_extension("subjectAltName",formatSANS(sans),false))
|
|
193
|
+
csr.add_extension(ef.create_extension("basicConstraints", "CA:TRUE", true))
|
|
194
|
+
csr.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
|
|
195
|
+
csr.add_extension(ef.create_extension("subjectKeyIdentifier", "hash", false))
|
|
196
|
+
csr.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always", false))
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
csr.sign key, OpenSSL::Digest::SHA256.new
|
|
200
|
+
|
|
201
|
+
cert = if !ca
|
|
202
|
+
File.open("#{ssldir}/#{name}.csr", 'w', 0644) { |f|
|
|
203
|
+
f.write csr.to_pem
|
|
204
|
+
}
|
|
205
|
+
sign("#{ssldir}/#{name}.csr", sans, for_user: for_user)
|
|
206
|
+
else
|
|
207
|
+
csr
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
File.open(filename, 'w', 0644) { |f|
|
|
211
|
+
f.write cert.to_pem
|
|
212
|
+
}
|
|
213
|
+
pfx_cert = toPfx(filename, keyfile, pfxfile) if pfx
|
|
214
|
+
|
|
215
|
+
if MU.mu_user != "mu" and Process.uid == 0
|
|
216
|
+
owner_uid = Etc.getpwnam(for_user).uid
|
|
217
|
+
File.chown(owner_uid, nil, filename)
|
|
218
|
+
File.chown(owner_uid, nil, pfxfile) if pfx
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
[cert, pfx_cert]
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
private
|
|
226
|
+
|
|
227
|
+
def self.toPfx(certfile, keyfile, pfxfile)
|
|
228
|
+
cacert = getCert("Mu_CA", ca: true).first
|
|
229
|
+
cert = OpenSSL::X509::Certificate.new(File.read(certfile))
|
|
230
|
+
key = OpenSSL::PKey::RSA.new(File.read(keyfile))
|
|
231
|
+
pfx = OpenSSL::PKCS12.create(nil, nil, key, cert, [cacert], nil, nil, nil, nil)
|
|
232
|
+
File.open(pfxfile, 'w', 0644) { |f|
|
|
233
|
+
f.write pfx.to_der
|
|
234
|
+
}
|
|
235
|
+
pfx
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def self.formatSANS(sans)
|
|
239
|
+
sans.map { |s|
|
|
240
|
+
if s.match(/^\d+\.\d+\.\d+\.\d+$/)
|
|
241
|
+
"IP:"+s
|
|
242
|
+
else
|
|
243
|
+
"DNS:"+s
|
|
244
|
+
end
|
|
245
|
+
}.join(",")
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|