httpd_configmap_generator 0.1.1 → 0.3.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.
Files changed (35) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -2
  4. data/.yamllint +11 -0
  5. data/Dockerfile +3 -2
  6. data/Gemfile +4 -0
  7. data/README-active-directory.md +11 -15
  8. data/README-ipa.md +7 -12
  9. data/README-ldap.md +62 -0
  10. data/README-oidc.md +39 -0
  11. data/README-saml.md +9 -14
  12. data/README.md +37 -49
  13. data/bin/httpd_configmap_generator +36 -50
  14. data/httpd_configmap_generator.gemspec +5 -3
  15. data/lib/httpd_configmap_generator.rb +2 -0
  16. data/lib/httpd_configmap_generator/active_directory.rb +2 -2
  17. data/lib/httpd_configmap_generator/base.rb +10 -6
  18. data/lib/httpd_configmap_generator/base/command.rb +19 -17
  19. data/lib/httpd_configmap_generator/base/config_helper.rb +15 -0
  20. data/lib/httpd_configmap_generator/base/config_map.rb +43 -26
  21. data/lib/httpd_configmap_generator/base/file_helper.rb +67 -0
  22. data/lib/httpd_configmap_generator/base/kerberos.rb +10 -8
  23. data/lib/httpd_configmap_generator/base/network.rb +27 -25
  24. data/lib/httpd_configmap_generator/base/pam.rb +6 -4
  25. data/lib/httpd_configmap_generator/base/sssd.rb +1 -1
  26. data/lib/httpd_configmap_generator/ipa.rb +12 -1
  27. data/lib/httpd_configmap_generator/ldap.rb +186 -0
  28. data/lib/httpd_configmap_generator/oidc.rb +48 -0
  29. data/lib/httpd_configmap_generator/saml.rb +16 -14
  30. data/lib/httpd_configmap_generator/version.rb +1 -1
  31. data/templates/httpd-scc-sysadmin.yaml +38 -0
  32. metadata +18 -14
  33. data/lib/httpd_configmap_generator/base/config.rb +0 -13
  34. data/lib/httpd_configmap_generator/base/file.rb +0 -65
  35. data/lib/httpd_configmap_generator/options.rb +0 -13
@@ -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
@@ -1,3 +1,5 @@
1
+ require "socket"
2
+
1
3
  module HttpdConfigmapGenerator
2
4
  class Ipa < Base
3
5
  IPA_INSTALL_COMMAND = "/usr/sbin/ipa-client-install".freeze
@@ -9,7 +11,9 @@ module HttpdConfigmapGenerator
9
11
 
10
12
  def required_options
11
13
  super.merge(
12
- :ipa_server => { :description => "IPA Server Fqdn" },
14
+ :host => { :description => "Application Domain",
15
+ :short => "-h" },
16
+ :ipa_server => { :description => "IPA Server FQDN" },
13
17
  :ipa_password => { :description => "IPA Server Password" }
14
18
  )
15
19
  end
@@ -49,6 +53,7 @@ module HttpdConfigmapGenerator
49
53
  end
50
54
 
51
55
  def configure(opts)
56
+ opts[:host] = get_canonical_hostname(opts[:host])
52
57
  update_hostname(opts[:host])
53
58
  command_run!(IPA_INSTALL_COMMAND,
54
59
  :params => [
@@ -118,5 +123,11 @@ module HttpdConfigmapGenerator
118
123
  FileUtils.chown(APACHE_USER, nil, HTTP_KEYTAB)
119
124
  FileUtils.chmod(0o600, HTTP_KEYTAB)
120
125
  end
126
+
127
+ def get_canonical_hostname(hostname)
128
+ Socket.gethostbyname(hostname)[0]
129
+ rescue SocketError
130
+ hostname
131
+ end
121
132
  end
122
133
  end
@@ -0,0 +1,186 @@
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
+ :host => { :description => "Application Domain",
14
+ :short => "-h" },
15
+ :cert_file => { :description => "Cert File" },
16
+ :ldap_host => { :description => "LDAP Directory Host FQDN" },
17
+ :ldap_mode => { :description => "ldap | ldaps" },
18
+ :ldap_basedn => { :description => "LDAP Directory Base DN" },
19
+ )
20
+ end
21
+
22
+ def optional_options
23
+ super.merge(
24
+ :ldap_group_name => { :description => "LDAP Directory Group Name",
25
+ :default => "cn" },
26
+ :ldap_group_member => { :description => "Attribute containing the names of the group's members",
27
+ :default => "member" },
28
+ :ldap_group_object_class => { :description => "The object class of a group entry in LDAP",
29
+ :default => "groupOfNames" },
30
+ :ldap_id_use_start_tls => { :description => "Connection use tls?",
31
+ :default => true },
32
+ :ldap_port => { :description => "LDAP Directory Port" },
33
+ :ldap_tls_reqcert => { :description => "The checks to perform on server certificates.",
34
+ :default => "allow" },
35
+ :ldap_user_gid_number => { :description => "LDAP attribute corresponding to the user's gid",
36
+ :default => "gidNumber" },
37
+ :ldap_user_name => { :description => "LDAP Directory User Name",
38
+ :default => "cn"},
39
+ :ldap_user_object_class => { :description => "Object class of a user entry in LDAP",
40
+ :default => "posixAccount" },
41
+ :ldap_user_uid_number => { :description => "LDAP attribute corresponding to the user's id",
42
+ :default => "uidNumber" },
43
+ :ldap_user_search_base => { :description => "The user DN search scope" },
44
+ :ldap_group_search_base => { :description => "The group DN search scope" },
45
+ :support_non_posix => { :description => "Suppoert non-posix user records",
46
+ :default => false },
47
+ )
48
+ end
49
+
50
+ def persistent_files
51
+ %w(/etc/nsswitch.conf
52
+ /etc/openldap/ldap.conf
53
+ /etc/pam.d/fingerprint-auth-ac
54
+ /etc/pam.d/httpd-auth
55
+ /etc/pam.d/password-auth-ac
56
+ /etc/pam.d/postlogin-ac
57
+ /etc/pam.d/smartcard-auth-ac
58
+ /etc/pam.d/system-auth-ac
59
+ /etc/sssd/sssd.conf
60
+ /etc/sysconfig/authconfig) + [opts[:cert_file]]
61
+ end
62
+
63
+ def configure(opts)
64
+ update_hostname(opts[:host])
65
+
66
+ init_search_base
67
+ run_auth_config
68
+ configure_pam
69
+ configure_sssd
70
+ chmod_chown_cert_file
71
+ config_map = ConfigMap.new(opts)
72
+ config_map.generate(AUTH[:type], realm, persistent_files)
73
+ config_map.save(opts[:output])
74
+ rescue => err
75
+ log_command_error(err)
76
+ raise err
77
+ end
78
+
79
+ def unconfigure
80
+ return unless configured?
81
+ raise "Unable to unconfigure authentication against LDAP"
82
+ end
83
+
84
+ def configured?
85
+ File.exist?(SSSD_CONFIG)
86
+ end
87
+
88
+ def domain
89
+ opts[:ldap_basedn].split(",").collect do |p|
90
+ p.split('dc=')[1]
91
+ end.compact.join('.')
92
+ end
93
+
94
+ private
95
+
96
+ def ldapserver_url
97
+ opts[:ldap_port] ||= opts[:ldap_mode].downcase == "ldaps" ? 636 : 389
98
+ "#{opts[:ldap_mode]}://#{opts[:ldap_host]}:#{opts[:ldap_port]}"
99
+ end
100
+
101
+ def init_search_base
102
+ opts[:ldap_user_search_base] = opts[:ldap_basedn] if opts[:ldap_user_search_base] == ""
103
+ opts[:ldap_group_search_base] = opts[:ldap_basedn] if opts[:ldap_group_search_base] == ""
104
+ end
105
+
106
+ def configure_sssd
107
+ info_msg("Configuring SSSD Service")
108
+ sssd = Sssd.new(opts)
109
+ sssd.load(SSSD_CONFIG)
110
+
111
+ sssd.configure_domain("default")
112
+ domain_section = sssd.section("domain/default")
113
+ domain_section["ldap_group_member"] = opts[:ldap_group_member]
114
+ domain_section["ldap_group_name"] = opts[:ldap_group_name]
115
+ domain_section["ldap_group_object_class"] = opts[:ldap_group_object_class]
116
+ domain_section["ldap_group_search_base"] = opts[:ldap_group_search_base]
117
+ domain_section["ldap_id_use_start_tls"] = opts[:ldap_id_use_start_tls]
118
+ domain_section["ldap_network_timeout"] = "3"
119
+ domain_section["ldap_pwd_policy"] = "none"
120
+ domain_section["ldap_tls_cacert"] = opts[:cert_file]
121
+ domain_section["ldap_tls_reqcert"] = opts[:ldap_tls_reqcert]
122
+ domain_section["ldap_user_gid_number"] = opts[:ldap_user_gid_number]
123
+ domain_section["ldap_user_name"] = opts[:ldap_user_name]
124
+ domain_section["ldap_user_object_class"] = opts[:ldap_user_object_class]
125
+ domain_section["ldap_user_search_base"] = opts[:ldap_user_search_base]
126
+ domain_section["ldap_user_uid_number"] = opts[:ldap_user_uid_number]
127
+ domain_section.delete("ldap_tls_cacertdir")
128
+
129
+ sssd_section = sssd.section("sssd")
130
+ sssd_section["config_file_version"] = "2"
131
+ sssd_section["domains"] = domain
132
+ sssd_section["default_domain_suffix"] = domain
133
+ sssd_section["sbus_timeout"] = "30"
134
+ sssd_section["services"] = "nss, pam, ifp"
135
+
136
+ sssd.add_service("pam")
137
+
138
+ sssd.configure_ifp
139
+
140
+ if opts[:support_non_posix]
141
+ sssd.section("pam")["pam_app_services"] = "httpd-auth"
142
+
143
+ debug_msg("- Setting application section to [application/#{domain}]")
144
+ domain_section.key = "application/#{domain}"
145
+
146
+ debug_msg("- Adding domain section to [domain/#{domain}]")
147
+ sssd.section("domain/#{domain}")
148
+ else
149
+ debug_msg("- Setting domain section to [domain/#{domain}]")
150
+ domain_section.key = "domain/#{domain}"
151
+ end
152
+
153
+ debug_msg("- Creating #{SSSD_CONFIG}")
154
+ sssd.save(SSSD_CONFIG)
155
+ end
156
+
157
+ def chmod_chown_cert_file
158
+ FileUtils.chown('root', 'root', opts[:cert_file])
159
+ FileUtils.chmod(0o600, opts[:cert_file])
160
+ end
161
+
162
+ def run_auth_config
163
+ params = {
164
+ :ldapserver= => ldapserver_url,
165
+ :ldapbasedn= => opts[:ldap_basedn],
166
+ :enablesssd => nil,
167
+ :enablesssdauth => nil,
168
+ :enablelocauthorize => nil,
169
+ :enableldap => nil,
170
+ :enableldapauth => nil,
171
+ :disableldaptls => nil,
172
+ :enablerfc2307bis => nil,
173
+ :enablecachecreds => nil,
174
+ :update => nil
175
+ }
176
+
177
+ command_run!(AUTHCONFIG_COMMAND, :params => params)
178
+ end
179
+
180
+ def validate_options(opts)
181
+ super(opts)
182
+ raise "ldap-mode must be one of #{LDAP_MODES.join(", ")}" unless LDAP_MODES.include?(opts[:ldap_mode].downcase)
183
+ raise "TLS certificate File #{opts[:cert_file]} not found" unless File.exist?(opts[:cert_file])
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,48 @@
1
+ module HttpdConfigmapGenerator
2
+ class Oidc < Base
3
+
4
+ AUTH = {
5
+ :type => "openid-connect",
6
+ :subtype => "oidc"
7
+ }.freeze
8
+
9
+ def required_options
10
+ super.merge(
11
+ :oidc_url => { :description => "OpenID-Connect Provider URL",
12
+ :short => "-u" },
13
+ :oidc_client_id => { :description => "OpenID-Connect Provider Client ID",
14
+ :short => "-i" },
15
+ :oidc_client_secret => { :description => "OpenID-Connect Provider Client Secret",
16
+ :short => "-s" },
17
+ )
18
+ end
19
+
20
+ def configure(opts)
21
+ auth_oidc_data = {}
22
+ auth_oidc_data["auth-oidc-provider-metadata-url"] = opts[:oidc_url]
23
+ auth_oidc_data["auth-oidc-client-id"] = opts[:oidc_client_id]
24
+ auth_oidc_data["auth-oidc-client-secret"] = opts[:oidc_client_secret]
25
+
26
+ config_map = ConfigMap.new(opts)
27
+ config_map.generate(AUTH[:type], nil, nil, auth_oidc_data )
28
+ config_map.save(opts[:output])
29
+ rescue => err
30
+ log_command_error(err)
31
+ raise err
32
+ end
33
+
34
+ def validate_options(opts)
35
+ super(opts)
36
+ end
37
+
38
+ def configured?
39
+ false
40
+ end
41
+
42
+ def unconfigure
43
+ return unless configured?
44
+ end
45
+
46
+ end
47
+ end
48
+
@@ -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",
@@ -10,23 +10,25 @@ module HttpdConfigmapGenerator
10
10
  }.freeze
11
11
 
12
12
  def required_options
13
- super
13
+ super.merge(
14
+ :host => { :description => "Application Domain", :short => "-h" },
15
+ )
14
16
  end
15
17
 
16
18
  def optional_options
17
19
  super.merge(
18
20
  :keycloak_add_metadata => { :description => "Download and add the Keycloak metadata file",
19
21
  :default => false },
20
- :keycloak_server => { :description => "Keycloak Server Fqdn or IP" },
22
+ :keycloak_server => { :description => "Keycloak Server FQDN or IP" },
21
23
  :keycloak_realm => { :description => "Keycloak Realm for this client"}
22
24
  )
23
25
  end
24
26
 
25
27
  def persistent_files
26
28
  file_list = %w(
27
- /etc/httpd/saml2/miqsp-key.key
28
- /etc/httpd/saml2/miqsp-cert.cert
29
- /etc/httpd/saml2/miqsp-metadata.xml
29
+ /etc/httpd/saml2/sp-key.key
30
+ /etc/httpd/saml2/sp-cert.cert
31
+ /etc/httpd/saml2/sp-metadata.xml
30
32
  )
31
33
  file_list += [IDP_METADATA_FILE] if opts[:keycloak_add_metadata]
32
34
  file_list
@@ -53,7 +55,7 @@ module HttpdConfigmapGenerator
53
55
  end
54
56
 
55
57
  def configured?
56
- File.exist?(MIQSP_METADATA_FILE)
58
+ File.exist?(SP_METADATA_FILE)
57
59
  end
58
60
 
59
61
  def unconfigure
@@ -76,18 +78,18 @@ module HttpdConfigmapGenerator
76
78
  info_msg("Renaming mellon config files")
77
79
  Dir.chdir(SAML2_CONFIG_DIRECTORY) do
78
80
  Dir.glob("https_*.*") do |mellon_file|
79
- miq_saml2_file = nil
81
+ saml2_file = nil
80
82
  case mellon_file
81
83
  when /^https_.*\.key$/
82
- miq_saml2_file = "miqsp-key.key"
84
+ saml2_file = "sp-key.key"
83
85
  when /^https_.*\.cert$/
84
- miq_saml2_file = "miqsp-cert.cert"
86
+ saml2_file = "sp-cert.cert"
85
87
  when /^https_.*\.xml$/
86
- miq_saml2_file = "miqsp-metadata.xml"
88
+ saml2_file = "sp-metadata.xml"
87
89
  end
88
- if miq_saml2_file
89
- debug_msg("- renaming #{mellon_file} to #{miq_saml2_file}")
90
- File.rename(mellon_file, miq_saml2_file)
90
+ if saml2_file
91
+ debug_msg("- renaming #{mellon_file} to #{saml2_file}")
92
+ File.rename(mellon_file, saml2_file)
91
93
  end
92
94
  end
93
95
  end