httpd_configmap_generator 0.1.2 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 97e1e062ab6b1f55d36ffe1de318f82892c78d8e
4
- data.tar.gz: 7a88bb96641736bb254238122b722547b61c5ec2
3
+ metadata.gz: 31a8b82ae49621578d09976757d636c2826580cc
4
+ data.tar.gz: a6621e89efda84c979e6635234382984a92dd258
5
5
  SHA512:
6
- metadata.gz: a2476f19b3e2ec40ce2a14cee8946850db609d2dbd5e215129fed1981d807cf34985bf13bc37c31277c0214ce3f97b10761ec4d13b17fb6ac757909acf9777d8
7
- data.tar.gz: 2b34b65675ab369a0821723e08259d06efa1619b168a3e80d019f696eb091dd8301e910454d14afe06611b6202afbdbfd884fe91360ffdbf128c0f584ed8dc05
6
+ metadata.gz: 7897d522c43687e7f0d29ae2519d7c0893d88fed0065e8e5158801a113e6a3af727e9418cf939117a506973eb4e53804b8b1fb890b57ad8e8f2478e62b0033cb
7
+ data.tar.gz: 19163527198bf275ed8990258796ba1f003386ff93ca323ff7a00d44bda2ba6852f25b5ab15698e1073704f37024636d4aff7739f84a4d8e1922ee352486fb8f
@@ -0,0 +1,62 @@
1
+ # Httpd Configmap Generator - LDAP
2
+
3
+ This documents how to run the httpd\_configmap\_generator tool to configure external authentication
4
+ for an LDAP server.
5
+
6
+
7
+ ## Usage for the `ldap` auth-type:
8
+
9
+ ```
10
+ $ httpd_configmap_generator ldap --help
11
+ Options:
12
+ -h, --host=<s> Application Domain
13
+ -o, --output=<s> Configuration map file to create
14
+ -c, --cert-file=<s> Cert File
15
+ -l, --ldap-host=<s> LDAP Directory Host FQDN
16
+ -a, --ldap-mode=<s> ldap | ldaps
17
+ -p, --ldap-basedn=<s> LDAP Directory Base DN
18
+ -f, --force Force configuration if configured already
19
+ -d, --debug Enable debugging
20
+ -g, --ldap-group-name=<s> LDAP Directory Group Name (default: cn)
21
+ -r, --ldap-group-member=<s> Attribute containing the names of the
22
+ group's members (default: member)
23
+ -u, --ldap-group-object-class=<s> The object class of a group entry in
24
+ LDAP (default: groupOfNames)
25
+ -i, --ldap-id-use-start-tls,
26
+ --no-ldap-id-use-start-tls Connection use tls? (default: true)
27
+ -t, --ldap-port=<s> LDAP Directory Port
28
+ -s, --ldap-tls-reqcert=<s> The checks to perform on server
29
+ certificates. (Default: allow)
30
+ -e, --ldap-user-gid-number=<s> LDAP attribute corresponding to the
31
+ user's gid (default: gidNumber)
32
+ -n, --ldap-user-name=<s> LDAP Directory User Name (default: cn)
33
+ -b, --ldap-user-object-class=<s> Object class of a user entry in LDAP
34
+ (default: posixAccount)
35
+ -m, --ldap-user-uid-number=<s> LDAP attribute corresponding to the
36
+ user's id (default: uidNumber)
37
+ --ldap-user-search-base=<s> The user DN search scope
38
+ --ldap-group-search-base=<s> The group DN search scope
39
+ -x, --support-non-posix Supports non-posix user records
40
+ --help Shows this message
41
+ ```
42
+
43
+ ### Example:
44
+
45
+ ```
46
+ $ httpd_configmap_generator ldap \
47
+ --force \
48
+ --host=application.example.com \
49
+ --ldap-mode=ldap \
50
+ --ldap-host=ldap-server.example.com \
51
+ --ldap-port=10389 \
52
+ --ldap-basedn=dc=example,dc=com \
53
+ --ldap-group-name=cn \
54
+ --ldap-group-search-base=ou=groups,dc=example,dc=com \
55
+ --ldap-group-object-class=groupOfNames \
56
+ --ldap-user-name=uid \
57
+ --ldap-user-search-base=ou=users,dc=example,dc=com \
58
+ --ldap-user-object-class=person \
59
+ --cert-file=/etc/openldap/cacerts/apacheds-cert.pem \
60
+ --debug \
61
+ -o /tmp/external-ldap.yaml
62
+ ```
@@ -56,10 +56,10 @@ $ httpd_configmap_generator saml \
56
56
  In the above example, the auth configmap file would include the following files:
57
57
 
58
58
  * /etc/httpd/saml2/
59
- - miqsp-metadata.xml
60
- - miqsp-cert.cert
61
- - miqsp-key.key
59
+ - sp-metadata.xml
60
+ - sp-cert.cert
61
+ - sp-key.key
62
62
  - idp-metadata.xml
63
63
 
64
- For Keycloak, the `miqsp-metadata.xml` file can be imported to create the Client ID for
64
+ For Keycloak, the `sp-metadata.xml` file can be imported to create the Client ID for
65
65
  the `application.example.com` application domain.
data/README.md CHANGED
@@ -28,7 +28,7 @@ httpd_configmap_generator 0.1.1 - External Authentication Configuration script
28
28
 
29
29
  Usage: httpd_configmap_generator auth_type | update | export [--help | options]
30
30
 
31
- supported auth_type: active-directory, ipa, saml
31
+ supported auth_type: active-directory, ipa, ldap, saml
32
32
 
33
33
  httpd_configmap_generator options are:
34
34
  -V, --version Version of the httpd_configmap_generator command
@@ -43,11 +43,12 @@ $ httpd_configmap_generator ipa --help
43
43
 
44
44
  ## Supported Authentication Types
45
45
 
46
- |auth-type | Identity Provider/Environment | for usage: |
47
- |------------------|------------------------------------------------|------------|
48
- | active-directory | Active Directory domain realm join | [README-active-directory](README-active-directory.md) |
49
- | ipa | IPA, IPA 2-factor authentication, IPA/AD Trust | [README-ipa](README-ipa.md) |
50
- | saml | Keycloak, etc. | [README-saml](README-saml.md) |
46
+ |auth-type | Identity Provider/Environment | for usage: |
47
+ |------------------|--------------------------------------------------|-------------------------------------------------------|
48
+ | active-directory | Active Directory domain realm join | [README-active-directory](README-active-directory.md) |
49
+ | ipa | IPA, IPA 2-factor authentication, IPA/AD Trust | [README-ipa](README-ipa.md) |
50
+ | ldap | Ldap directories | [README-ldap](README-ldap.md) |
51
+ | saml | Keycloak, etc. | [README-saml](README-saml.md) |
51
52
 
52
53
  ___
53
54
 
@@ -128,7 +129,7 @@ $ httpd_configmap_generator update \
128
129
  ```
129
130
  $ httpd_configmap_generator update \
130
131
  --input=/tmp/original-auth-configmap.yaml \
131
- --add-file=http://aab-keycloak:8080/auth/realms/miq/protocol/saml/description,/etc/httpd/saml2/idp-metadata.xml,644:root:root \
132
+ --add-file=http://aab-keycloak:8080/auth/realms/testrealm/protocol/saml/description,/etc/httpd/saml2/idp-metadata.xml,644:root:root \
132
133
  --output=/tmp/updated-auth-configmap.yaml
133
134
  ```
134
135
 
@@ -214,7 +215,7 @@ Example for generating a configuration map for IPA:
214
215
 
215
216
  ```
216
217
  $ docker exec $CONFIGMAP_GENERATOR_ID httpd_configmap_generator ipa \
217
- --host=miq-appliance.example.com \
218
+ --host=appliance.example.com \
218
219
  --ipa-server=ipaserver.example.com \
219
220
  --ipa-domain=example.com \
220
221
  --ipa-realm=EXAMPLE.COM \
@@ -261,18 +262,26 @@ ___
261
262
 
262
263
  #### If running without OCI systemd hooks (Minishift)
263
264
 
264
- The httpd-configmap-generator service account must be added to the miq-sysadmin SCC before the Httpd Auth Config pod can run.
265
+ The httpd-configmap-generator service account must be added to the httpd-scc-sysadmin SCC before the Httpd Configmap Generator can run.
265
266
 
266
267
  ##### As Admin
267
268
 
269
+ Create the httpd-scc-sysadmin SCC:
270
+
271
+ ```
272
+ $ oc create -f templates/httpd-scc-sysadmin.yaml
273
+ ```
274
+
275
+ Include the httpd-configmap-generator service account with the new SCC:
276
+
268
277
  ```
269
- $ oc adm policy add-scc-to-user miq-sysadmin system:serviceaccount:<your-namespace>:httpd-configmap-generator
278
+ $ oc adm policy add-scc-to-user httpd-scc-sysadmin system:serviceaccount:<your-namespace>:httpd-configmap-generator
270
279
  ```
271
280
 
272
- Verify that the httpd-configmap-generator service account is now included in the miq-sysadmin SCC:
281
+ Verify that the httpd-configmap-generator service account is now included in the httpd-scc-sysadmin SCC:
273
282
 
274
283
  ```
275
- $ oc describe scc miq-sysadmin | grep Users
284
+ $ oc describe scc httpd-scc-sysadmin | grep Users
276
285
  Users: system:serviceaccount:<your-namespace>:httpd-configmap-generator
277
286
  ```
278
287
 
@@ -284,7 +293,7 @@ Users: system:serviceaccount:<your-namespace>:httpd-configmap-generator
284
293
  $ oc adm policy add-scc-to-user anyuid system:serviceaccount:<your-namespace>:httpd-configmap-generator
285
294
  ```
286
295
 
287
- Verify that the httpd-configmap-generator service account is now included in the miq-sysadmin SCC:
296
+ Verify that the httpd-configmap-generator service account is included in the anyuid SCC:
288
297
 
289
298
  ```
290
299
  $ oc describe scc anyuid | grep Users
@@ -339,7 +348,7 @@ Example configuration:
339
348
 
340
349
  ```
341
350
  $ oc rsh $CONFIGMAP_GENERATOR_POD httpd_configmap_generator ipa \
342
- --host=miq-appliance.example.com \
351
+ --host=appliance.example.com \
343
352
  --ipa-server=ipaserver.example.com \
344
353
  --ipa-domain=example.com \
345
354
  --ipa-realm=EXAMPLE.COM \
@@ -2,6 +2,7 @@ require "httpd_configmap_generator/version"
2
2
  require "httpd_configmap_generator/base"
3
3
  require "httpd_configmap_generator/active_directory"
4
4
  require "httpd_configmap_generator/ipa"
5
+ require "httpd_configmap_generator/ldap"
5
6
  require "httpd_configmap_generator/saml"
6
7
  require "httpd_configmap_generator/update"
7
8
  require "httpd_configmap_generator/export"
@@ -1,8 +1,8 @@
1
1
  require "pathname"
2
2
  require "httpd_configmap_generator/base/command"
3
- require "httpd_configmap_generator/base/config"
3
+ require "httpd_configmap_generator/base/config_helper"
4
4
  require "httpd_configmap_generator/base/config_map"
5
- require "httpd_configmap_generator/base/file"
5
+ require "httpd_configmap_generator/base/file_helper"
6
6
  require "httpd_configmap_generator/base/kerberos"
7
7
  require "httpd_configmap_generator/base/network"
8
8
  require "httpd_configmap_generator/base/pam"
@@ -11,6 +11,13 @@ require "httpd_configmap_generator/base/sssd"
11
11
 
12
12
  module HttpdConfigmapGenerator
13
13
  class Base
14
+ include Command
15
+ include ConfigHelper
16
+ include FileHelper
17
+ include Kerberos
18
+ include Network
19
+ include Pam
20
+
14
21
  APACHE_USER = "apache".freeze
15
22
  HTTP_KEYTAB = "/etc/http.keytab".freeze
16
23
  IPA_COMMAND = "/usr/bin/ipa".freeze
@@ -2,27 +2,29 @@ require "awesome_spawn"
2
2
 
3
3
  module HttpdConfigmapGenerator
4
4
  class Base
5
- def command_run(executable, options = {})
6
- if opts && opts[:debug]
7
- debug_msg("Running Command: #{AwesomeSpawn.build_command_line(executable, options)}")
5
+ module Command
6
+ def command_run(executable, options = {})
7
+ if opts && opts[:debug]
8
+ debug_msg("Running Command: #{AwesomeSpawn.build_command_line(executable, options)}")
9
+ end
10
+ AwesomeSpawn.run(executable, options)
8
11
  end
9
- AwesomeSpawn.run(executable, options)
10
- end
11
12
 
12
- def command_run!(executable, options = {})
13
- if opts && opts[:debug]
14
- debug_msg("Running Command: #{AwesomeSpawn.build_command_line(executable, options)}")
13
+ def command_run!(executable, options = {})
14
+ if opts && opts[:debug]
15
+ debug_msg("Running Command: #{AwesomeSpawn.build_command_line(executable, options)}")
16
+ end
17
+ AwesomeSpawn.run!(executable, options)
15
18
  end
16
- AwesomeSpawn.run!(executable, options)
17
- end
18
19
 
19
- def log_command_error(err)
20
- err_msg("Command Error: #{err}")
21
- if err.kind_of?(AwesomeSpawn::CommandResultError)
22
- err_msg("stdout: #{err.result.output}")
23
- err_msg("stderr: #{err.result.error}")
24
- else
25
- err_msg(err.backtrace)
20
+ def log_command_error(err)
21
+ err_msg("Command Error: #{err}")
22
+ if err.kind_of?(AwesomeSpawn::CommandResultError)
23
+ err_msg("stdout: #{err.result.output}")
24
+ err_msg("stderr: #{err.result.error}")
25
+ else
26
+ err_msg(err.backtrace)
27
+ end
26
28
  end
27
29
  end
28
30
  end
@@ -0,0 +1,15 @@
1
+ require "active_support"
2
+ require "active_support/core_ext" # for Time.current
3
+
4
+ module HttpdConfigmapGenerator
5
+ class Base
6
+ module ConfigHelper
7
+ def config_file_backup(path)
8
+ if File.exist?(path)
9
+ timestamp = Time.current.strftime(TIMESTAMP_FORMAT)
10
+ FileUtils.copy(path, "#{path}.#{timestamp}")
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -84,30 +84,42 @@ module HttpdConfigmapGenerator
84
84
  file_specs = []
85
85
  file_list.each do |file_to_add|
86
86
  file_spec = file_to_add.split(",").map(&:strip)
87
- case file_spec.length
88
- when 1
89
- file = file_spec.first
90
- file_entry = file_entry_spec(file)
91
- when 2
92
- source_file, target_file = file_spec
93
- raise "Must specify a mode for URL file sources" if source_file =~ URI.regexp(%w(http https))
94
- file_entry = file_entry_spec(source_file, target_file)
95
- when 3
96
- source_file, target_file, mode = file_spec
97
- if source_file =~ URI.regexp(%w(http https))
98
- fetch_network_file(source_file, target_file)
99
- file_entry = file_entry_spec(target_file, target_file, mode)
87
+ file_entry =
88
+ case file_spec.length
89
+ when 1
90
+ file_entry_spec(file_spec.first)
91
+ when 2
92
+ source_file, target_file = file_spec
93
+ file_entry_for_source_target(source_file, target_file)
94
+ when 3
95
+ source_file, target_file, mode = file_spec
96
+ file_entry_for_source_target_mode(source_file, target_file, mode)
100
97
  else
101
- file_entry = file_entry_spec(source_file, target_file, mode)
98
+ raise "Invalid file specification #{file_to_add}"
102
99
  end
103
- else
104
- raise "Invalid file specification #{file_to_add}"
105
- end
106
100
  file_specs << file_entry
107
101
  end
108
102
  file_specs.sort_by { |file_spec| file_spec[:basename] }
109
103
  end
110
104
 
105
+ def file_entry_for_source_target(source_file, target_file)
106
+ raise "Must specify a mode for URL file sources" if source_file =~ URI.regexp(%w(http https))
107
+ file_entry = file_entry_spec(source_file, target_file)
108
+ file_entry[:source_file] = source_file
109
+ file_entry
110
+ end
111
+
112
+ def file_entry_for_source_target_mode(source_file, target_file, mode)
113
+ if source_file =~ URI.regexp(%w(http https))
114
+ fetch_network_file(source_file, target_file)
115
+ file_entry = file_entry_spec(target_file, target_file, mode)
116
+ else
117
+ file_entry = file_entry_spec(source_file, target_file, mode)
118
+ file_entry[:source_file] = source_file
119
+ end
120
+ file_entry
121
+ end
122
+
111
123
  def file_entry_spec(source_file, target_file = nil, mode = nil)
112
124
  target_file = source_file.dup unless target_file
113
125
  unless mode
@@ -152,7 +164,7 @@ module HttpdConfigmapGenerator
152
164
 
153
165
  def include_files(file_specs)
154
166
  file_specs.each do |file_spec|
155
- content = File.read(file_spec[:target])
167
+ content = File.read(file_spec[:source_file] || file_spec[:target])
156
168
  content = Base64.encode64(content) if file_spec[:binary]
157
169
  # encode(:universal_newline => true) will convert \r\n to \n, necessary for to_yaml to render properly.
158
170
  config_map[DATA_SECTION].merge!(file_basename(file_spec) => content.encode(:universal_newline => true))
@@ -0,0 +1,67 @@
1
+ require "pathname"
2
+
3
+ module HttpdConfigmapGenerator
4
+ class Base
5
+ module FileHelper
6
+ def template_directory
7
+ @template_directory ||=
8
+ Pathname.new(Gem::Specification.find_by_name("httpd_configmap_generator").full_gem_path).join("templates")
9
+ end
10
+
11
+ def cp_template(file, src_dir, dest_dir = "/")
12
+ src_path = path_join(src_dir, file)
13
+ dest_path = path_join(dest_dir, file.gsub(".erb", ""))
14
+ if src_path.to_s.include?(".erb")
15
+ File.write(dest_path, ERB.new(File.read(src_path), nil, '-').result(binding))
16
+ else
17
+ FileUtils.cp(src_path, dest_path)
18
+ end
19
+ end
20
+
21
+ def delete_target_file(file_path)
22
+ if File.exist?(file_path)
23
+ if opts[:force]
24
+ info_msg("File #{file_path} exists, forcing a delete")
25
+ File.delete(file_path)
26
+ else
27
+ raise "File #{file_path} already exist"
28
+ end
29
+ end
30
+ end
31
+
32
+ def create_target_directory(file_path)
33
+ dirname = File.dirname(file_path)
34
+ return if File.exist?(dirname)
35
+ debug_msg("Creating directory #{dirname} ...")
36
+ FileUtils.mkdir_p(dirname)
37
+ end
38
+
39
+ def rm_file(file, dir = "/")
40
+ path = path_join(dir, file)
41
+ File.delete(path) if File.exist?(path)
42
+ end
43
+
44
+ def path_join(*args)
45
+ path = Pathname.new(args.shift)
46
+ args.each { |path_seg| path = path.join("./#{path_seg}") }
47
+ path
48
+ end
49
+
50
+ def file_binary?(file)
51
+ data = File.read(file)
52
+ ascii = control = binary = total = 0
53
+ data[0..512].each_byte do |c|
54
+ total += 1
55
+ if c < 32
56
+ control += 1
57
+ elsif c >= 32 && c <= 128
58
+ ascii += 1
59
+ else
60
+ binary += 1
61
+ end
62
+ end
63
+ control.to_f / ascii > 0.1 || binary.to_f / ascii > 0.05
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,13 +1,15 @@
1
1
  module HttpdConfigmapGenerator
2
2
  class Base
3
- def enable_kerberos_dns_lookups
4
- info_msg("Configuring Kerberos DNS Lookups")
5
- config_file_backup(KERBEROS_CONFIG_FILE)
6
- krb5config = File.read(KERBEROS_CONFIG_FILE)
7
- krb5config[/(\s*)dns_lookup_kdc(\s*)=(\s*)(.*)/, 4] = 'true' if krb5config[/(\s*)dns_lookup_kdc(\s*)=/]
8
- krb5config[/(\s*)dns_lookup_realm(\s*)=(\s*)(.*)/, 4] = 'true' if krb5config[/(\s*)dns_lookup_realm(\s*)=/]
9
- debug_msg("- Updating #{KERBEROS_CONFIG_FILE}")
10
- File.write(KERBEROS_CONFIG_FILE, krb5config)
3
+ module Kerberos
4
+ def enable_kerberos_dns_lookups
5
+ info_msg("Configuring Kerberos DNS Lookups")
6
+ config_file_backup(KERBEROS_CONFIG_FILE)
7
+ krb5config = File.read(KERBEROS_CONFIG_FILE)
8
+ krb5config[/(\s*)dns_lookup_kdc(\s*)=(\s*)(.*)/, 4] = 'true' if krb5config[/(\s*)dns_lookup_kdc(\s*)=/]
9
+ krb5config[/(\s*)dns_lookup_realm(\s*)=(\s*)(.*)/, 4] = 'true' if krb5config[/(\s*)dns_lookup_realm(\s*)=/]
10
+ debug_msg("- Updating #{KERBEROS_CONFIG_FILE}")
11
+ File.write(KERBEROS_CONFIG_FILE, krb5config)
12
+ end
11
13
  end
12
14
  end
13
15
  end
@@ -1,37 +1,39 @@
1
1
  module HttpdConfigmapGenerator
2
2
  class Base
3
- HOSTNAME_COMMAND = "/usr/bin/hostname".freeze
3
+ module Network
4
+ HOSTNAME_COMMAND = "/usr/bin/hostname".freeze
4
5
 
5
- def realm
6
- domain.upcase
7
- end
6
+ def realm
7
+ domain.upcase
8
+ end
8
9
 
9
- def domain
10
- domain_from_host(opts[:host])
11
- end
10
+ def domain
11
+ domain_from_host(opts[:host])
12
+ end
12
13
 
13
- def domain_from_host(host)
14
- host.gsub(/^([^.]+\.)/, '') if host.present? && host.include?('.')
15
- end
14
+ def domain_from_host(host)
15
+ host.gsub(/^([^.]+\.)/, '') if host.present? && host.include?('.')
16
+ end
16
17
 
17
- def host_reachable?(host)
18
- require "net/ping"
19
- Net::Ping::External.new(host).ping
20
- end
18
+ def host_reachable?(host)
19
+ require "net/ping"
20
+ Net::Ping::External.new(host).ping
21
+ end
21
22
 
22
- def update_hostname(host)
23
- command_run!(HOSTNAME_COMMAND, :params => [host]) if command_run(HOSTNAME_COMMAND).output.strip != host
24
- end
23
+ def update_hostname(host)
24
+ command_run!(HOSTNAME_COMMAND, :params => [host]) if command_run(HOSTNAME_COMMAND).output.strip != host
25
+ end
25
26
 
26
- def fetch_network_file(source_file, target_file)
27
- require "net/http"
27
+ def fetch_network_file(source_file, target_file)
28
+ require "net/http"
28
29
 
29
- delete_target_file(target_file)
30
- create_target_directory(target_file)
31
- info_msg("Downloading #{source_file} ...")
32
- result = Net::HTTP.get_response(URI(source_file))
33
- raise "Failed to fetch URL file source #{source_file}" unless result.kind_of?(Net::HTTPSuccess)
34
- File.write(target_file, result.body)
30
+ delete_target_file(target_file)
31
+ create_target_directory(target_file)
32
+ info_msg("Downloading #{source_file} ...")
33
+ result = Net::HTTP.get_response(URI(source_file))
34
+ raise "Failed to fetch URL file source #{source_file}" unless result.kind_of?(Net::HTTPSuccess)
35
+ File.write(target_file, result.body)
36
+ end
35
37
  end
36
38
  end
37
39
  end
@@ -1,9 +1,11 @@
1
1
  module HttpdConfigmapGenerator
2
2
  class Base
3
- def configure_pam
4
- info_msg("Configuring PAM")
5
- debug_msg("- Creating #{PAM_CONFIG}")
6
- cp_template(PAM_CONFIG, template_directory)
3
+ module Pam
4
+ def configure_pam
5
+ info_msg("Configuring PAM")
6
+ debug_msg("- Creating #{PAM_CONFIG}")
7
+ cp_template(PAM_CONFIG, template_directory)
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -43,7 +43,7 @@ module HttpdConfigmapGenerator
43
43
 
44
44
  def section(key)
45
45
  if key =~ /^domain\/.*$/
46
- key = sssd.entries.collect(&:key).select { |k| k.downcase == key.downcase }.first
46
+ key = sssd.entries.collect(&:key).select { |k| k.downcase == key.downcase }.first || key
47
47
  end
48
48
  sssd.section(key)
49
49
  end
@@ -0,0 +1,185 @@
1
+ module HttpdConfigmapGenerator
2
+ class Ldap < Base
3
+ AUTHCONFIG_COMMAND = "/usr/sbin/authconfig".freeze
4
+ LDAP_MODES = %w(ldap ldaps).freeze
5
+
6
+ AUTH = {
7
+ :type => "external",
8
+ :subtype => "ldap"
9
+ }.freeze
10
+
11
+ def required_options
12
+ super.merge(
13
+ :cert_file => { :description => "Cert File" },
14
+ :ldap_host => { :description => "LDAP Directory Host FQDN" },
15
+ :ldap_mode => { :description => "ldap | ldaps" },
16
+ :ldap_basedn => { :description => "LDAP Directory Base DN" },
17
+ )
18
+ end
19
+
20
+ def optional_options
21
+ super.merge(
22
+ :ldap_group_name => { :description => "LDAP Directory Group Name",
23
+ :default => "cn" },
24
+ :ldap_group_member => { :description => "Attribute containing the names of the group's members",
25
+ :default => "member" },
26
+ :ldap_group_object_class => { :description => "The object class of a group entry in LDAP",
27
+ :default => "groupOfNames" },
28
+ :ldap_id_use_start_tls => { :description => "Connection use tls?",
29
+ :default => true },
30
+ :ldap_port => { :description => "LDAP Directory Port" },
31
+ :ldap_tls_reqcert => { :description => "The checks to perform on server certificates.",
32
+ :default => "allow" },
33
+ :ldap_user_gid_number => { :description => "LDAP attribute corresponding to the user's gid",
34
+ :default => "gidNumber" },
35
+ :ldap_user_name => { :description => "LDAP Directory User Name",
36
+ :default => "cn"},
37
+ :ldap_user_object_class => { :description => "Object class of a user entry in LDAP",
38
+ :default => "posixAccount" },
39
+ :ldap_user_uid_number => { :description => "LDAP attribute corresponding to the user's id",
40
+ :default => "uidNumber" },
41
+ :ldap_user_search_base => { :description => "The user DN search scope" },
42
+ :ldap_group_search_base => { :description => "The group DN search scope" },
43
+ :support_non_posix => { :description => "Suppoert non-posix user records",
44
+ :default => false },
45
+ )
46
+ end
47
+
48
+ def persistent_files
49
+ %w(/etc/nsswitch.conf
50
+ /etc/openldap/ldap.conf
51
+ /etc/pam.d/fingerprint-auth-ac
52
+ /etc/pam.d/httpd-auth
53
+ /etc/pam.d/password-auth-ac
54
+ /etc/pam.d/postlogin-ac
55
+ /etc/pam.d/smartcard-auth-ac
56
+ /etc/pam.d/system-auth-ac
57
+ /etc/sssd/sssd.conf
58
+ /etc/sysconfig/authconfig
59
+ /etc/sysconfig/network) + [opts[:cert_file]]
60
+ end
61
+
62
+ def configure(opts)
63
+ update_hostname(opts[:host])
64
+
65
+ init_search_base
66
+ run_auth_config
67
+ configure_pam
68
+ configure_sssd
69
+ chmod_chown_cert_file
70
+ config_map = ConfigMap.new(opts)
71
+ config_map.generate(AUTH[:type], realm, persistent_files)
72
+ config_map.save(opts[:output])
73
+ rescue => err
74
+ log_command_error(err)
75
+ raise err
76
+ end
77
+
78
+ def unconfigure
79
+ return unless configured?
80
+ raise "Unable to unconfigure authentication against LDAP"
81
+ end
82
+
83
+ def configured?
84
+ File.exist?(SSSD_CONFIG)
85
+ end
86
+
87
+ def domain
88
+ opts[:ldap_basedn].split(",").collect do |p|
89
+ p.split('dc=')[1]
90
+ end.compact.join('.')
91
+ end
92
+
93
+ private
94
+
95
+ def ldapserver_url
96
+ opts[:ldap_port] ||= opts[:ldap_mode].downcase == "ldaps" ? 636 : 389
97
+ "#{opts[:ldap_mode]}://#{opts[:ldap_host]}:#{opts[:ldap_port]}"
98
+ end
99
+
100
+ def init_search_base
101
+ opts[:ldap_user_search_base] = opts[:ldap_basedn] if opts[:ldap_user_search_base] == ""
102
+ opts[:ldap_group_search_base] = opts[:ldap_basedn] if opts[:ldap_group_search_base] == ""
103
+ end
104
+
105
+ def configure_sssd
106
+ info_msg("Configuring SSSD Service")
107
+ sssd = Sssd.new(opts)
108
+ sssd.load(SSSD_CONFIG)
109
+
110
+ sssd.configure_domain("default")
111
+ domain_section = sssd.section("domain/default")
112
+ domain_section["ldap_group_member"] = opts[:ldap_group_member]
113
+ domain_section["ldap_group_name"] = opts[:ldap_group_name]
114
+ domain_section["ldap_group_object_class"] = opts[:ldap_group_object_class]
115
+ domain_section["ldap_group_search_base"] = opts[:ldap_group_search_base]
116
+ domain_section["ldap_id_use_start_tls"] = opts[:ldap_id_use_start_tls]
117
+ domain_section["ldap_network_timeout"] = "3"
118
+ domain_section["ldap_pwd_policy"] = "none"
119
+ domain_section["ldap_tls_cacert"] = opts[:cert_file]
120
+ domain_section["ldap_tls_reqcert"] = opts[:ldap_tls_reqcert]
121
+ domain_section["ldap_user_gid_number"] = opts[:ldap_user_gid_number]
122
+ domain_section["ldap_user_name"] = opts[:ldap_user_name]
123
+ domain_section["ldap_user_object_class"] = opts[:ldap_user_object_class]
124
+ domain_section["ldap_user_search_base"] = opts[:ldap_user_search_base]
125
+ domain_section["ldap_user_uid_number"] = opts[:ldap_user_uid_number]
126
+ domain_section.delete("ldap_tls_cacertdir")
127
+
128
+ sssd_section = sssd.section("sssd")
129
+ sssd_section["config_file_version"] = "2"
130
+ sssd_section["domains"] = domain
131
+ sssd_section["default_domain_suffix"] = domain
132
+ sssd_section["sbus_timeout"] = "30"
133
+ sssd_section["services"] = "nss, pam, ifp"
134
+
135
+ sssd.add_service("pam")
136
+
137
+ sssd.configure_ifp
138
+
139
+ if opts[:support_non_posix]
140
+ sssd.section("pam")["pam_app_services"] = "httpd-auth"
141
+
142
+ debug_msg("- Setting application section to [application/#{domain}]")
143
+ domain_section.key = "application/#{domain}"
144
+
145
+ debug_msg("- Adding domain section to [domain/#{domain}]")
146
+ sssd.section("domain/#{domain}")
147
+ else
148
+ debug_msg("- Setting domain section to [domain/#{domain}]")
149
+ domain_section.key = "domain/#{domain}"
150
+ end
151
+
152
+ debug_msg("- Creating #{SSSD_CONFIG}")
153
+ sssd.save(SSSD_CONFIG)
154
+ end
155
+
156
+ def chmod_chown_cert_file
157
+ FileUtils.chown('root', 'root', opts[:cert_file])
158
+ FileUtils.chmod(0o600, opts[:cert_file])
159
+ end
160
+
161
+ def run_auth_config
162
+ params = {
163
+ :ldapserver= => ldapserver_url,
164
+ :ldapbasedn= => opts[:ldap_basedn],
165
+ :enablesssd => nil,
166
+ :enablesssdauth => nil,
167
+ :enablelocauthorize => nil,
168
+ :enableldap => nil,
169
+ :enableldapauth => nil,
170
+ :disableldaptls => nil,
171
+ :enablerfc2307bis => nil,
172
+ :enablecachecreds => nil,
173
+ :update => nil
174
+ }
175
+
176
+ command_run!(AUTHCONFIG_COMMAND, :params => params)
177
+ end
178
+
179
+ def validate_options(opts)
180
+ super(opts)
181
+ raise "ldap-mode must be one of #{LDAP_MODES.join(", ")}" unless LDAP_MODES.include?(opts[:ldap_mode].downcase)
182
+ raise "TLS certificate File #{opts[:cert_file]} not found" unless File.exist?(opts[:cert_file])
183
+ end
184
+ end
185
+ end
@@ -2,7 +2,7 @@ module HttpdConfigmapGenerator
2
2
  class Saml < Base
3
3
  MELLON_CREATE_METADATA_COMMAND = "/usr/libexec/mod_auth_mellon/mellon_create_metadata.sh".freeze
4
4
  SAML2_CONFIG_DIRECTORY = "/etc/httpd/saml2".freeze
5
- MIQSP_METADATA_FILE = "#{SAML2_CONFIG_DIRECTORY}/miqsp-metadata.xml".freeze
5
+ SP_METADATA_FILE = "#{SAML2_CONFIG_DIRECTORY}/sp-metadata.xml".freeze
6
6
  IDP_METADATA_FILE = "#{SAML2_CONFIG_DIRECTORY}/idp-metadata.xml".freeze
7
7
  AUTH = {
8
8
  :type => "saml",
@@ -24,9 +24,9 @@ module HttpdConfigmapGenerator
24
24
 
25
25
  def persistent_files
26
26
  file_list = %w(
27
- /etc/httpd/saml2/miqsp-key.key
28
- /etc/httpd/saml2/miqsp-cert.cert
29
- /etc/httpd/saml2/miqsp-metadata.xml
27
+ /etc/httpd/saml2/sp-key.key
28
+ /etc/httpd/saml2/sp-cert.cert
29
+ /etc/httpd/saml2/sp-metadata.xml
30
30
  )
31
31
  file_list += [IDP_METADATA_FILE] if opts[:keycloak_add_metadata]
32
32
  file_list
@@ -53,7 +53,7 @@ module HttpdConfigmapGenerator
53
53
  end
54
54
 
55
55
  def configured?
56
- File.exist?(MIQSP_METADATA_FILE)
56
+ File.exist?(SP_METADATA_FILE)
57
57
  end
58
58
 
59
59
  def unconfigure
@@ -76,18 +76,18 @@ module HttpdConfigmapGenerator
76
76
  info_msg("Renaming mellon config files")
77
77
  Dir.chdir(SAML2_CONFIG_DIRECTORY) do
78
78
  Dir.glob("https_*.*") do |mellon_file|
79
- miq_saml2_file = nil
79
+ saml2_file = nil
80
80
  case mellon_file
81
81
  when /^https_.*\.key$/
82
- miq_saml2_file = "miqsp-key.key"
82
+ saml2_file = "sp-key.key"
83
83
  when /^https_.*\.cert$/
84
- miq_saml2_file = "miqsp-cert.cert"
84
+ saml2_file = "sp-cert.cert"
85
85
  when /^https_.*\.xml$/
86
- miq_saml2_file = "miqsp-metadata.xml"
86
+ saml2_file = "sp-metadata.xml"
87
87
  end
88
- if miq_saml2_file
89
- debug_msg("- renaming #{mellon_file} to #{miq_saml2_file}")
90
- File.rename(mellon_file, miq_saml2_file)
88
+ if saml2_file
89
+ debug_msg("- renaming #{mellon_file} to #{saml2_file}")
90
+ File.rename(mellon_file, saml2_file)
91
91
  end
92
92
  end
93
93
  end
@@ -1,3 +1,3 @@
1
1
  module HttpdConfigmapGenerator
2
- VERSION = "0.1.2".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -0,0 +1,38 @@
1
+ allowHostDirVolumePlugin: false
2
+ allowHostIPC: false
3
+ allowHostNetwork: false
4
+ allowHostPID: false
5
+ allowHostPorts: false
6
+ allowPrivilegedContainer: false
7
+ allowedCapabilities:
8
+ apiVersion: v1
9
+ defaultAddCapabilities:
10
+ - SYS_ADMIN
11
+ fsGroup:
12
+ type: RunAsAny
13
+ groups:
14
+ - system:cluster-admins
15
+ kind: SecurityContextConstraints
16
+ metadata:
17
+ annotations:
18
+ kubernetes.io/description: httpd-scc-sysadmin provides all features of the anyuid SCC but allows users to have SYS_ADMIN capabilities. This is the required scc for Pods requiring to run with systemd and the message bus.
19
+ creationTimestamp:
20
+ name: httpd-scc-sysadmin
21
+ priority: 10
22
+ readOnlyRootFilesystem: false
23
+ requiredDropCapabilities:
24
+ - MKNOD
25
+ - SYS_CHROOT
26
+ runAsUser:
27
+ type: RunAsAny
28
+ seLinuxContext:
29
+ type: MustRunAs
30
+ supplementalGroups:
31
+ type: RunAsAny
32
+ users:
33
+ volumes:
34
+ - configMap
35
+ - downwardAPI
36
+ - emptyDir
37
+ - persistentVolumeClaim
38
+ - secret
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httpd_configmap_generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Httpd Auth Config Developers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-26 00:00:00.000000000 Z
11
+ date: 2017-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: codeclimate-test-reporter
@@ -151,6 +151,7 @@ files:
151
151
  - LICENSE
152
152
  - README-active-directory.md
153
153
  - README-ipa.md
154
+ - README-ldap.md
154
155
  - README-saml.md
155
156
  - README.md
156
157
  - Rakefile
@@ -162,9 +163,9 @@ files:
162
163
  - lib/httpd_configmap_generator/active_directory.rb
163
164
  - lib/httpd_configmap_generator/base.rb
164
165
  - lib/httpd_configmap_generator/base/command.rb
165
- - lib/httpd_configmap_generator/base/config.rb
166
+ - lib/httpd_configmap_generator/base/config_helper.rb
166
167
  - lib/httpd_configmap_generator/base/config_map.rb
167
- - lib/httpd_configmap_generator/base/file.rb
168
+ - lib/httpd_configmap_generator/base/file_helper.rb
168
169
  - lib/httpd_configmap_generator/base/kerberos.rb
169
170
  - lib/httpd_configmap_generator/base/network.rb
170
171
  - lib/httpd_configmap_generator/base/pam.rb
@@ -172,11 +173,13 @@ files:
172
173
  - lib/httpd_configmap_generator/base/sssd.rb
173
174
  - lib/httpd_configmap_generator/export.rb
174
175
  - lib/httpd_configmap_generator/ipa.rb
176
+ - lib/httpd_configmap_generator/ldap.rb
175
177
  - lib/httpd_configmap_generator/saml.rb
176
178
  - lib/httpd_configmap_generator/update.rb
177
179
  - lib/httpd_configmap_generator/version.rb
178
180
  - templates/etc/pam.d/httpd-auth
179
181
  - templates/httpd-configmap-generator-template.yaml
182
+ - templates/httpd-scc-sysadmin.yaml
180
183
  homepage: https://github.com/ManageIQ/httpd_configmap_generator
181
184
  licenses:
182
185
  - Apache-2.0
@@ -1,13 +0,0 @@
1
- require "active_support"
2
- require "active_support/core_ext" # for Time.current
3
-
4
- module HttpdConfigmapGenerator
5
- class Base
6
- def config_file_backup(path)
7
- if File.exist?(path)
8
- timestamp = Time.current.strftime(TIMESTAMP_FORMAT)
9
- FileUtils.copy(path, "#{path}.#{timestamp}")
10
- end
11
- end
12
- end
13
- end
@@ -1,65 +0,0 @@
1
- require "pathname"
2
-
3
- module HttpdConfigmapGenerator
4
- class Base
5
- def template_directory
6
- @template_directory ||=
7
- Pathname.new(Gem::Specification.find_by_name("httpd_configmap_generator").full_gem_path).join("templates")
8
- end
9
-
10
- def cp_template(file, src_dir, dest_dir = "/")
11
- src_path = path_join(src_dir, file)
12
- dest_path = path_join(dest_dir, file.gsub(".erb", ""))
13
- if src_path.to_s.include?(".erb")
14
- File.write(dest_path, ERB.new(File.read(src_path), nil, '-').result(binding))
15
- else
16
- FileUtils.cp(src_path, dest_path)
17
- end
18
- end
19
-
20
- def delete_target_file(file_path)
21
- if File.exist?(file_path)
22
- if opts[:force]
23
- info_msg("File #{file_path} exists, forcing a delete")
24
- File.delete(file_path)
25
- else
26
- raise "File #{file_path} already exist"
27
- end
28
- end
29
- end
30
-
31
- def create_target_directory(file_path)
32
- dirname = File.dirname(file_path)
33
- return if File.exist?(dirname)
34
- debug_msg("Creating directory #{dirname} ...")
35
- FileUtils.mkdir_p(dirname)
36
- end
37
-
38
- def rm_file(file, dir = "/")
39
- path = path_join(dir, file)
40
- File.delete(path) if File.exist?(path)
41
- end
42
-
43
- def path_join(*args)
44
- path = Pathname.new(args.shift)
45
- args.each { |path_seg| path = path.join("./#{path_seg}") }
46
- path
47
- end
48
-
49
- def file_binary?(file)
50
- data = File.read(file)
51
- ascii = control = binary = total = 0
52
- data[0..512].each_byte do |c|
53
- total += 1
54
- if c < 32
55
- control += 1
56
- elsif c >= 32 && c <= 128
57
- ascii += 1
58
- else
59
- binary += 1
60
- end
61
- end
62
- control.to_f / ascii > 0.1 || binary.to_f / ascii > 0.05
63
- end
64
- end
65
- end