httpd_configmap_generator 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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