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 +4 -4
- data/README-ldap.md +62 -0
- data/README-saml.md +4 -4
- data/README.md +23 -14
- data/lib/httpd_configmap_generator.rb +1 -0
- data/lib/httpd_configmap_generator/base.rb +9 -2
- data/lib/httpd_configmap_generator/base/command.rb +19 -17
- data/lib/httpd_configmap_generator/base/config_helper.rb +15 -0
- data/lib/httpd_configmap_generator/base/config_map.rb +30 -18
- data/lib/httpd_configmap_generator/base/file_helper.rb +67 -0
- data/lib/httpd_configmap_generator/base/kerberos.rb +10 -8
- data/lib/httpd_configmap_generator/base/network.rb +27 -25
- data/lib/httpd_configmap_generator/base/pam.rb +6 -4
- data/lib/httpd_configmap_generator/base/sssd.rb +1 -1
- data/lib/httpd_configmap_generator/ldap.rb +185 -0
- data/lib/httpd_configmap_generator/saml.rb +12 -12
- data/lib/httpd_configmap_generator/version.rb +1 -1
- data/templates/httpd-scc-sysadmin.yaml +38 -0
- metadata +7 -4
- data/lib/httpd_configmap_generator/base/config.rb +0 -13
- data/lib/httpd_configmap_generator/base/file.rb +0 -65
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31a8b82ae49621578d09976757d636c2826580cc
|
4
|
+
data.tar.gz: a6621e89efda84c979e6635234382984a92dd258
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7897d522c43687e7f0d29ae2519d7c0893d88fed0065e8e5158801a113e6a3af727e9418cf939117a506973eb4e53804b8b1fb890b57ad8e8f2478e62b0033cb
|
7
|
+
data.tar.gz: 19163527198bf275ed8990258796ba1f003386ff93ca323ff7a00d44bda2ba6852f25b5ab15698e1073704f37024636d4aff7739f84a4d8e1922ee352486fb8f
|
data/README-ldap.md
ADDED
@@ -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
|
+
```
|
data/README-saml.md
CHANGED
@@ -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
|
-
-
|
60
|
-
-
|
61
|
-
-
|
59
|
+
- sp-metadata.xml
|
60
|
+
- sp-cert.cert
|
61
|
+
- sp-key.key
|
62
62
|
- idp-metadata.xml
|
63
63
|
|
64
|
-
For Keycloak, the `
|
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
|
47
|
-
|
48
|
-
| active-directory | Active Directory domain realm join
|
49
|
-
| ipa | IPA, IPA 2-factor authentication, IPA/AD Trust
|
50
|
-
|
|
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/
|
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=
|
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
|
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
|
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
|
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
|
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
|
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=
|
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/
|
3
|
+
require "httpd_configmap_generator/base/config_helper"
|
4
4
|
require "httpd_configmap_generator/base/config_map"
|
5
|
-
require "httpd_configmap_generator/base/
|
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
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
3
|
+
module Network
|
4
|
+
HOSTNAME_COMMAND = "/usr/bin/hostname".freeze
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def realm
|
7
|
+
domain.upcase
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def domain
|
11
|
+
domain_from_host(opts[:host])
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
def domain_from_host(host)
|
15
|
+
host.gsub(/^([^.]+\.)/, '') if host.present? && host.include?('.')
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
def host_reachable?(host)
|
19
|
+
require "net/ping"
|
20
|
+
Net::Ping::External.new(host).ping
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
27
|
-
|
27
|
+
def fetch_network_file(source_file, target_file)
|
28
|
+
require "net/http"
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
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/
|
28
|
-
/etc/httpd/saml2/
|
29
|
-
/etc/httpd/saml2/
|
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?(
|
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
|
-
|
79
|
+
saml2_file = nil
|
80
80
|
case mellon_file
|
81
81
|
when /^https_.*\.key$/
|
82
|
-
|
82
|
+
saml2_file = "sp-key.key"
|
83
83
|
when /^https_.*\.cert$/
|
84
|
-
|
84
|
+
saml2_file = "sp-cert.cert"
|
85
85
|
when /^https_.*\.xml$/
|
86
|
-
|
86
|
+
saml2_file = "sp-metadata.xml"
|
87
87
|
end
|
88
|
-
if
|
89
|
-
debug_msg("- renaming #{mellon_file} to #{
|
90
|
-
File.rename(mellon_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
|
@@ -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.
|
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-
|
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/
|
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/
|
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
|