cloud-mu 2.1.0beta → 3.0.0beta
Sign up to get free protection for your applications and to get access to all the features.
- 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
|