Skip to content

Commit ddc4b09

Browse files
(SIMP-10456) Load multiple CA certificates (#15)
* (SIMP-10456) Load multiple CA certificates SIMP-10456 #close * increase password complexity for FIPS compat * set complexity to safe chars
1 parent 99c106f commit ddc4b09

File tree

7 files changed

+139
-15
lines changed

7 files changed

+139
-15
lines changed

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
* Wed Sep 22 2021 Trevor Vaughan <tvaughan@onyxpoint.com> - 0.1.2
2+
- Ensure that the instances can load multiple CA certificates
3+
14
* Tue Aug 03 2021 Trevor Vaughan <tvaughan@onyxoint.com> - 0.1.1
25
- Fixed
36
- Ensure that dirsrv.target is enabled so that all 389ds instances start at boot

manifests/init.pp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@
4040
recurse => true
4141
}
4242

43+
file { "$config_dir/ca_import.sh":
44+
ensure => 'file',
45+
owner => 'root',
46+
group => 'root',
47+
mode => '0700',
48+
content => epp("${module_name}/ca_import.sh.epp")
49+
}
50+
4351
$instances.each |$id, $options| {
4452
ds389::instance { $id:
4553
* => $options

manifests/instance/tls.pp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
Stdlib::Absolutepath $key = "/etc/pki/simp_apps/${module_name}_${title}/x509/private/${facts['fqdn']}.pem",
6161
Stdlib::Absolutepath $cafile = "/etc/pki/simp_apps/${module_name}_${title}/x509/cacerts/cacerts.pem",
6262
Ds389::ConfigItems $dse_config = simplib::dlookup('ds389::instance::tls', 'dse_config', { 'default_value' => {} }),
63-
String[16] $token = simplib::passgen("ds389_${title}_pki", { 'length' => 32 }),
63+
String[16] $token = simplib::passgen("ds389_${title}_pki", { 'length' => 32, 'complexity' => 1 }),
6464
String[1] $service_group = 'dirsrv'
6565
) {
6666
assert_private()
@@ -192,10 +192,11 @@
192192
subscribe => Exec["Build ${title} p12"]
193193
}
194194

195-
exec { "Import ${title} CA":
196-
command => "certutil -D -d ${_instance_base} -n 'CA Certificate' ||:; certutil -A -i ${cafile} -d ${_instance_base} -n 'CA Certificate' -t 'CT,,' -a -f ${_token_file}",
197-
unless => "certutil -d ${_instance_base} -L -n 'CA Certificate'",
195+
exec { "Import ${title} CAs":
196+
command => "${ds389::config_dir}/ca_import.sh -i '${cafile}' -o '${_instance_base}'",
197+
onlyif => "${ds389::config_dir}/ca_import.sh -i '${cafile}' -o '${_instance_base}' -c; [ \$? -eq 2 ]",
198198
path => ['/bin', '/usr/bin'],
199+
require => File["${ds389::config_dir}/ca_import.sh"],
199200
subscribe => Exec["Build ${title} p12"]
200201
}
201202

metadata.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "simp-ds389",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"author": "SIMP Team",
55
"summary": "Management of 389 Directory Server",
66
"license": "Apache-2.0",

spec/acceptance/nodesets/default.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,8 @@ HOSTS:
2424
CONFIG:
2525
log_level: verbose
2626
type: aio
27-
<% if ENV['BEAKER_fips'] -%>
2827
vagrant_memsize: 1024
29-
<% else -%>
30-
vagrant_memsize: 512
31-
<% end -%>
32-
vagrant_cpus: 1
28+
vagrant_cpus: 2
3329
<% if ENV['BEAKER_PUPPET_ENVIRONMENT'] -%>
3430
puppet_environment: <%= ENV['BEAKER_PUPPET_ENVIRONMENT'] %>
3531
<% end -%>

spec/defines/instance/tls_spec.rb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
it { is_expected.to_not create_exec("Validate #{title} p12") }
5757
it { is_expected.to_not create_exec("Build #{title} p12") }
5858
it { is_expected.to_not create_exec("Import #{title} p12") }
59-
it { is_expected.to_not create_exec("Import #{title} CA") }
59+
it { is_expected.to_not create_exec("Import #{title} CAs") }
6060
it { is_expected.to_not create_ds389__instance__dn__add("RSA DN for #{title}") }
6161
it { is_expected.to_not create_ds389__instance__attr__set("Configure PKI for #{title}") }
6262
end
@@ -129,8 +129,9 @@
129129
end
130130

131131
it do
132-
expect(subject).to create_exec("Import #{title} CA")
133-
.with_command("certutil -D -d #{instance_base} -n 'CA Certificate' ||:; certutil -A -i #{params[:cafile]} -d #{instance_base} -n 'CA Certificate' -t 'CT,,' -a -f #{token_file}")
132+
expect(subject).to create_exec("Import #{title} CAs")
133+
.with_command("/usr/share/puppet_ds389_config/ca_import.sh -i '#{params[:cafile]}' -o '#{instance_base}'")
134+
.with_onlyif("/usr/share/puppet_ds389_config/ca_import.sh -i '#{params[:cafile]}' -o '#{instance_base}' -c; [ $? -eq 2 ]")
134135
.with_path(['/bin', '/usr/bin'])
135136
.that_subscribes_to("Exec[Build #{title} p12]")
136137
end
@@ -202,7 +203,7 @@
202203
it { is_expected.to create_exec("Validate #{title} p12") }
203204
it { is_expected.to create_exec("Build #{title} p12") }
204205
it { is_expected.to create_exec("Import #{title} p12") }
205-
it { is_expected.to create_exec("Import #{title} CA") }
206+
it { is_expected.to create_exec("Import #{title} CAs") }
206207
it { is_expected.to create_ds389__instance__dn__add("RSA DN for #{title}") }
207208
it { is_expected.to create_ds389__instance__attr__set("Configure PKI for #{title}") }
208209
end
@@ -255,7 +256,7 @@
255256
it { is_expected.to_not create_exec("Validate #{title} p12") }
256257
it { is_expected.to_not create_exec("Build #{title} p12") }
257258
it { is_expected.to_not create_exec("Import #{title} p12") }
258-
it { is_expected.to_not create_exec("Import #{title} CA") }
259+
it { is_expected.to_not create_exec("Import #{title} CAs") }
259260
it { is_expected.to_not create_ds389__instance__dn__add("RSA DN for #{title}") }
260261
it { is_expected.to_not create_ds389__instance__attr__set("Configure PKI for #{title}") }
261262
end

templates/ca_import.sh.epp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#!/bin/bash
2+
3+
usage() {
4+
echo "Import PEM CA certificates into a trust store using certutil"
5+
echo
6+
echo "Usage: $0 -i <input_pem> -o <output_dir>"
7+
echo " -i <input_pem> Path to the input CAcerts PEM"
8+
echo " -o <output_dir> Path to the certutil store"
9+
echo " -t <token_file> Path to the certutil token file"
10+
echo " -c Only compare, do not update; exits with 2 if update needed"
11+
echo " -h This help"
12+
exit 0
13+
}
14+
15+
compare_only=false
16+
17+
[ $# -eq 0 ] && usage
18+
while getopts ":hci:o:t:" opt; do
19+
case $opt in
20+
c)
21+
compare_only=true
22+
;;
23+
i)
24+
input_pem=${OPTARG}
25+
;;
26+
o)
27+
output_dir=${OPTARG}
28+
;;
29+
t)
30+
token_file=${OPTARG}
31+
;;
32+
h | *)
33+
usage
34+
exit 0
35+
;;
36+
esac
37+
done
38+
39+
if [ -z "${input_pem}" ] || [ -z "${output_dir}" ]; then
40+
echo "Error: You must specify both 'input_pem' and 'output_dir'"
41+
exit 1
42+
fi
43+
44+
if ! $compare_only; then
45+
if [ -z "${token_file}" ]; then
46+
token_file="${output_dir}/p12token.txt"
47+
fi
48+
49+
if [ ! -f "${token_file}" ]; then
50+
echo "Error: Could not find a token file at '${token_file}'"
51+
exit 1
52+
fi
53+
fi
54+
55+
56+
if [ ! -f "${input_pem}" ]; then
57+
echo "Error: Could not find input PEM at '${input_pem}'"
58+
exit 1
59+
fi
60+
61+
if [ ! -d "${output_dir}" ]; then
62+
echo "Error: Could not find output directory at '${output_dir}'"
63+
exit 1
64+
fi
65+
66+
# Validate the output dir
67+
certutil -d "${output_dir}" -L >/dev/null 2>&1
68+
if [ $? -ne 0 ]; then
69+
echo "Error: '${output_dir}' is not a valid database target"
70+
exit 1
71+
fi
72+
73+
# Get the existing CA fingerprints
74+
current_fingerprints=$(
75+
certutil -d "${output_dir}" -L | \
76+
grep '[[:space:]]CT,' | \
77+
sed 's/^\(.\+\)CT,.*/\1/' | \
78+
sed 's/[[:space:]]\+$//' | \
79+
while read cert; do
80+
(
81+
certutil -d "${output_dir}" -L -a -n "${cert}" | \
82+
openssl x509 -noout -fingerprint | \
83+
cut -f2 -d'='
84+
)
85+
done
86+
)
87+
88+
umask 0077
89+
tmpdir=$(mktemp -d -t 389ds-cert-import-XXXXXXXXXX)
90+
91+
(
92+
cd "$tmpdir"
93+
94+
csplit -z -q "${input_pem}" '/^\-\+BEGIN CERTIFICATE\-\+$/' '{*}'
95+
96+
for x in *; do
97+
fprint=$( openssl x509 -in "${x}" -noout -fingerprint | cut -f2 -d'=' )
98+
99+
if [[ ! ${current_fingerprints[*]} =~ $fprint ]]; then
100+
if $compare_only; then
101+
exit 2
102+
fi
103+
104+
cert_name=$( openssl x509 -in "${x}" -noout -subject_hash )
105+
106+
certutil -D -d "${output_dir}" -n "${cert_name}" >/dev/null 2>&1 ||:
107+
certutil -A -i "${x}" -d "${output_dir}" -n "${cert_name}" -t 'CT,,' -a -f "${token_file}"
108+
fi
109+
done
110+
)
111+
exit_code=$?
112+
113+
rm -rf "$tmpdir"
114+
115+
exit $exit_code

0 commit comments

Comments
 (0)