Skip to content

Commit a7e5877

Browse files
committed
Add katello-certs-check as foreman-certificate-check
Signed-off-by: Eric D. Helms <ericdhelms@gmail.com>
1 parent 329bd48 commit a7e5877

36 files changed

+1214
-7
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
#!/usr/bin/env bash
2+
3+
# Define colors uses for status output
4+
RED=$(tput setaf 1 2> /dev/null)
5+
GREEN=$(tput setaf 2 2> /dev/null)
6+
RESET=$(tput sgr0 2> /dev/null)
7+
8+
CABUNDLE_MAX_ISSUERS=32
9+
10+
function usage () {
11+
cat <<HELP >&2
12+
Verifies, that custom SSL certificate files are usable as part of the installation.
13+
When passing filenames use absolute paths.
14+
15+
usage: $0 -c CERT_FILE -k KEY_FILE -b CA_BUNDLE_FILE
16+
HELP
17+
}
18+
19+
while getopts "c:k:b:" opt; do
20+
case $opt in
21+
c)
22+
CERT_FILE="$(readlink -f $OPTARG)"
23+
;;
24+
k)
25+
KEY_FILE="$(readlink -f $OPTARG)"
26+
;;
27+
b)
28+
CA_BUNDLE_FILE="$(readlink -f $OPTARG)"
29+
;;
30+
h)
31+
usage
32+
exit 0
33+
;;
34+
?)
35+
usage
36+
exit 1
37+
;;
38+
esac
39+
done
40+
41+
EXIT_CODE=0
42+
43+
if [ -z "$CERT_FILE" -o -z "$KEY_FILE" -o -z "$CA_BUNDLE_FILE" ]; then
44+
echo 'One of the required parameters is missing.' >&2
45+
usage
46+
exit 1
47+
fi
48+
49+
function error () {
50+
echo -e "\n${RED}[FAIL]${RESET}\n"
51+
CURRENT_EXIT_CODE=$1
52+
EXIT_CODE=$((EXIT_CODE|CURRENT_EXIT_CODE))
53+
echo -e $2 >&2
54+
}
55+
56+
function success () {
57+
echo -e "\n${GREEN}[OK]${RESET}\n"
58+
}
59+
60+
function check-files-exist() {
61+
if [[ ! -f "$CA_BUNDLE_FILE" ]] || [[ ! -f "$CERT_FILE" ]] || [[ ! -f "$KEY_FILE" ]] ; then
62+
echo "One of '${CERT_FILE}', '${KEY_FILE}' or '${CA_BUNDLE_FILE}' not found" >&2
63+
exit 1
64+
fi
65+
}
66+
67+
function check-server-cert-encoding () {
68+
printf 'Checking server certificate encoding: '
69+
openssl x509 -inform pem -in $CERT_FILE -noout -text &> /dev/null
70+
if [[ $? == "0" ]]; then
71+
success
72+
else
73+
openssl x509 -inform der -in $CERT_FILE -noout -text &> /dev/null
74+
if [[ $? == "0" ]]; then
75+
error 8 "The server certificate is in DER encoding, which is incompatible.\n\n"
76+
printf "Run the following command to convert the certificate to PEM encoding,\n"
77+
printf "then test it again.\n"
78+
printf "# openssl x509 -in %s -outform pem -out %s.pem\n\n" $(basename $CERT_FILE) $(basename $CERT_FILE)
79+
printf "When you run $(basename $0) again, use file\n"
80+
printf "%s.pem for the server certificate.\n\n" $(basename $CERT_FILE)
81+
else
82+
error 9 "The encoding of the server certificate is unknown."
83+
fi
84+
fi
85+
}
86+
87+
function check-expiration () {
88+
CERT_EXP=$(openssl x509 -noout -enddate -in $CERT_FILE | sed -e 's/notAfter=//' | awk '{$NF="";}1')
89+
CA_EXP=$(openssl x509 -noout -enddate -in $CA_BUNDLE_FILE | sed -e 's/notAfter=//' | awk '{$NF="";}1')
90+
DATE_TODAY=$(date -u +%Y%m%d%H%M%S)
91+
CERT_DATE=$(date -d"${CERT_EXP}" +%Y%m%d%H%M%S)
92+
CA_DATE=$(date -d"${CA_EXP}" +%Y%m%d%H%M%S)
93+
printf "Checking expiration of certificate: "
94+
if [[ $DATE_TODAY -gt $CERT_DATE ]]; then
95+
error 6 "The certificate \"$CERT_FILE\" has already expired on: $CERT_EXP"
96+
else
97+
success
98+
fi
99+
printf "Checking expiration of CA bundle: "
100+
if [[ $DATE_TODAY -gt $CA_DATE ]]; then
101+
error 7 "The CA bundle \"$CA_BUNDLE_FILE\" has already expired on: $CA_EXP"
102+
else
103+
success
104+
fi
105+
}
106+
107+
function check-cert-ca-flag () {
108+
printf "Checking if server certificate has CA:TRUE flag "
109+
openssl x509 -in $CERT_FILE -noout -text | grep -q CA:TRUE
110+
if [[ $? -ne 0 ]]; then
111+
success
112+
else
113+
error 7 "The server certificate is marked as a CA and can not be used."
114+
fi
115+
}
116+
117+
function check-passphrase () {
118+
printf "Checking for private key passphrase: "
119+
CHECK=$(cat $KEY_FILE | grep ENCRYPTED)
120+
if [[ $? == "0" ]]; then
121+
error 2 "The $KEY_FILE contains a passphrase, remove the key's passphrase by doing:
122+
\nmv $KEY_FILE $KEY_FILE.old
123+
\nopenssl pkey -in $KEY_FILE.old -out $KEY_FILE"
124+
exit 2
125+
else
126+
success
127+
fi
128+
}
129+
130+
function check-priv-key () {
131+
printf "Checking to see if the private key matches the certificate: "
132+
CERT_PUBKEY_SUM=$(openssl x509 -noout -pubkey -in $CERT_FILE | openssl sha512)
133+
KEY_PUBKEY_SUM=$(openssl pkey -pubout -in $KEY_FILE | openssl sha512)
134+
if [[ "$CERT_PUBKEY_SUM" != "$KEY_PUBKEY_SUM" ]]; then
135+
error 2 "The $KEY_FILE does not match the $CERT_FILE"
136+
else
137+
success
138+
fi
139+
}
140+
141+
function check-ca-bundle () {
142+
printf "Checking CA bundle against the certificate file: "
143+
ERROR_PATTERN="error [0-9]+ at"
144+
CHECK=$(openssl verify -no-CApath -no-CAstore -CAfile $CA_BUNDLE_FILE -purpose sslserver -verbose $CERT_FILE 2>&1)
145+
CHECK_STATUS=$?
146+
147+
if [[ $CHECK_STATUS != "0" || $CHECK =~ $ERROR_PATTERN ]]; then
148+
error 4 "The $CA_BUNDLE_FILE does not verify the $CERT_FILE"
149+
echo -e "${CHECK/OK/}\n"
150+
else
151+
success
152+
fi
153+
}
154+
155+
function check-ca-bundle-size () {
156+
printf "Checking CA bundle size: "
157+
CHECK=$(grep -c "^--*BEGIN" $CA_BUNDLE_FILE)
158+
printf $CHECK
159+
if [[ $CHECK -lt $CABUNDLE_MAX_ISSUERS ]]; then
160+
success
161+
else
162+
CERRTISSUER=$(openssl x509 -noout -in $CERT_FILE -issuer 2>&1)
163+
error 10 "The CA bundle counts $CHECK issuers. Please trim your CA bundle and include only the certs relevant to your cert file"
164+
echo $CERTISSUER
165+
echo
166+
fi
167+
}
168+
169+
function check-ca-bundle-trust-rules () {
170+
printf "Checking if CA bundle has trust rules: "
171+
CHECK=$(grep 'BEGIN TRUSTED CERTIFICATE' $CA_BUNDLE_FILE| wc -l)
172+
printf $CHECK
173+
if [[ $CHECK -lt 1 ]]; then
174+
success
175+
else
176+
error 10 "The CA bundle contains $CHECK certificate(s) with trust rules. This will create problems for older systems. Please, recreate the bundle using certificates without trust rules."
177+
echo
178+
fi
179+
}
180+
181+
function check-cert-san () {
182+
printf "Checking Subject Alt Name on certificate "
183+
DNS_LIST=$(openssl x509 -noout -text -in $CERT_FILE | grep DNS:)
184+
if [[ $? == "0" ]]; then
185+
success
186+
printf "Checking if any Subject Alt Name on certificate matches the Subject CN"
187+
SUBJECT_CN=$(openssl x509 -in $CERT_FILE -noout -subject -nameopt multiline|grep commonName|cut -d '=' -f 2|tr -d ' ')
188+
for DNS in ${DNS_LIST}
189+
do
190+
DNS_VALUE="$( echo ${DNS//DNS:/} | tr -d ',')"
191+
if [ $SUBJECT_CN == $DNS_VALUE ]
192+
then
193+
success
194+
return
195+
fi
196+
done
197+
error 11 "The $CERT_FILE does not have a Subject Alt Name matching the Subject CN"
198+
else
199+
error 11 "The $CERT_FILE does not contain a Subject Alt Name. Common Name is deprecated, use Subject Alt Name instead. See: https://tools.ietf.org/html/rfc2818#section-3.1"
200+
fi
201+
}
202+
203+
function check-cert-usage-key-encipherment () {
204+
printf "Checking Key Usage extension on certificate for Key Encipherment "
205+
CHECK=$(openssl x509 -noout -text -in $CERT_FILE | grep -A1 'X509v3 Key Usage:' | grep 'Key Encipherment')
206+
if [[ $? == "0" ]]; then
207+
success
208+
else
209+
error 4 "The $CERT_FILE does not allow for the 'Key Encipherment' key usage."
210+
fi
211+
}
212+
213+
function check-shortname () {
214+
printf "Checking for use of shortname as CN"
215+
216+
SUBJECT_CN=$(openssl x509 -in $CERT_FILE -noout -subject -nameopt multiline|grep commonName|cut -d '=' -f 2|tr -d ' ')
217+
if [[ $SUBJECT_CN != *"."* ]]; then
218+
error 1 "The $(basename $CERT_FILE) is using a shortname for Common Name (CN) and cannot be used.\n"
219+
fi
220+
221+
DNS_LIST=$(openssl x509 -noout -text -in $CERT_FILE | grep DNS:)
222+
if [[ $? == "0" ]]; then
223+
for DNS in ${DNS_LIST}
224+
do
225+
DNS_VALUE="$( echo ${DNS//DNS:/} | tr -d ',')"
226+
227+
if [[ $DNS_VALUE == *"."* ]]; then
228+
success
229+
return
230+
fi
231+
done
232+
error 1 "The $(basename $CERT_FILE) is using only shortnames for Subject Alt Name and cannot be used.\n"
233+
fi
234+
}
235+
236+
function check-ca-signing-algorithm () {
237+
printf "Checking CA signing algorithm for sha1: "
238+
CHECK=$(openssl crl2pkcs7 -nocrl -certfile "$CA_BUNDLE_FILE" | openssl pkcs7 -print | grep algorithm | grep -q 'sha1WithRSAEncryption')
239+
if [[ $? == "0" ]]; then
240+
error 4 "The file '$CA_BUNDLE_FILE' contains a certificate signed with sha1 and will break installation. Update the server CA certificate and its chain with one signed by sha256 or stronger."
241+
else
242+
success
243+
fi
244+
}
245+
246+
check-files-exist
247+
check-server-cert-encoding
248+
check-expiration
249+
check-cert-ca-flag
250+
check-passphrase
251+
check-priv-key
252+
check-ca-bundle
253+
check-ca-bundle-size
254+
check-ca-bundle-trust-rules
255+
check-cert-san
256+
check-cert-usage-key-encipherment
257+
check-shortname
258+
check-ca-signing-algorithm
259+
260+
if [[ $EXIT_CODE == "0" ]]; then
261+
echo -e "${GREEN}Validation succeeded${RESET}\n"
262+
else
263+
exit $EXIT_CODE
264+
fi

src/roles/certificate_checks/tasks/main.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
---
2-
- name: Fetch katello_certs_check
3-
ansible.builtin.get_url:
4-
url: https://raw.githubusercontent.com/theforeman/foreman-installer/refs/heads/develop/bin/katello-certs-check
5-
dest: /usr/bin/katello-certs-check
2+
- name: Install foreman-certificate-check
3+
ansible.builtin.copy:
4+
src: foreman-certificate-check
5+
dest: /usr/local/bin/foreman-certificate-check
66
mode: '0755'
77

88
- name: Check certificates
99
ansible.builtin.command:
1010
argv:
11-
- "/usr/bin/katello-certs-check"
12-
- "-t"
13-
- "foreman"
11+
- "/usr/local/bin/foreman-certificate-check"
1412
- "-c"
1513
- "{{ certificate_checks_certificate }}"
1614
- "-k"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Generate Certificates
2+
3+
To generate a new set of certificates:
4+
5+
```
6+
./create_certs.sh
7+
```
8+
9+
In order to modify properties of the certificates, edit the `extensions.txt` before re-generating.
10+
11+
To regenerate a particular set of certificates, remove them from the `certs/` directory and re-run the generation script.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDETCCAfmgAwIBAgIUW99nJU3DgZdPE4KtDWgL6cTrEAgwDQYJKoZIhvcNAQEL
3+
BQAwGDEWMBQGA1UEAwwNVGhpcmRwYXJ0eSBDQTAeFw0yMDExMTgxNTQ0NTJaFw0z
4+
MDExMTYxNTQ0NTJaMBgxFjAUBgNVBAMMDVRoaXJkcGFydHkgQ0EwggEiMA0GCSqG
5+
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDs4Haoc6xj4cTiGYzcqLBiX6fnDpmVPXaD
6+
kE6s0iFYuqZcZgFIuVetgWn4ew7NvDgm1HwCA6EnKBY4zxMd+xic2vO8Pm9SqNWB
7+
0bIdyKvHn1o3u9TMRcnHbp4MvlTTsd0Hr91n+J6Kv7TVUihhsWQH6YILqaKMaEa3
8+
78ssaLrTULdCHQ3vB0XyZGj3NLv5PYq6Yt92hG8M7vyVeBPdEECidD1csAOefk8T
9+
EBRgXgl7dpBa16dZ9nNQzurxOGrRgFsW4wIQit3AU/Y3Zyz1f9hTcG+xHGHUzzsy
10+
jaV345Mdito5DNaGqkh+7PUccb1JihuS6ePZl5J6GQSjktFwPL2jAgMBAAGjUzBR
11+
MB0GA1UdDgQWBBRKB5Wwmh4CsZHFmnAczPb6wjMRajAfBgNVHSMEGDAWgBRKB5Ww
12+
mh4CsZHFmnAczPb6wjMRajAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
13+
A4IBAQCs7kfOgqFXpYqAYjxq+NlQeeWSyEMdU/5QbSjxS68U3wXZ2JR+N7ptmn8B
14+
IaeIF8BMFkLKKCG0s486YnOGKBkmbE5xxAJYctzJSrAjCtkBqqCVMtqpomuXawJv
15+
tB+HwKV3IW43lM8S3DJ5XbEWlZctqGb803ud6Mt2Rlyc6afPyFzt5DPrgvwkgKmX
16+
cLgkvUP0W4dinOG3PqE5NbxqIMw+0kzyrbGYLO7Klwsqjfms++XXIdREzS/nt8+9
17+
c2uERABlpV58p/xyZjJMGGnU0YIhOfn6+LQ6gyqU3qKdj6/VtcQ6SnZC3GE3adqT
18+
LpdSdMc5aL5hr2hZl/uVvrKLYDGz
19+
-----END CERTIFICATE-----
20+
-----BEGIN TRUSTED CERTIFICATE-----
21+
MIIDHTCCAgWgAwIBAgIUK+x25LNYYMHS83aWDnAYviwxEYEwDQYJKoZIhvcNAQEL
22+
BQAwHjEcMBoGA1UEAwwTVGVzdCBTZWxmLVNpZ25lZCBDQTAeFw0yMDExMTgwMjMw
23+
NDNaFw0zMDExMTYwMjMwNDNaMB4xHDAaBgNVBAMME1Rlc3QgU2VsZi1TaWduZWQg
24+
Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC92114uygw5KcqPCz1
25+
E/Cwd3Lo2ytyPD9FchWKPOxXpNisHMOr4zAfsxERXmgBLawHIkqc2Xae3TqHGGQa
26+
ll3J3HukwghZQAyjcNG/Q2Q2QqfQW1tzxHRnz2EKBoRoyhmVXcnu+qBoEgkf5QI/
27+
Rk9HzLJINZPcZuMEkRgcf5q1h/F+PY2yCMwT5qjB6whn6zX6FP6G3//fRtkZw4cI
28+
FPPjKJedbHlYEifRigmJfu+T5Q5xz19Og/1zDwfl7is5eBUV+KEoIE7UpmvR1UrM
29+
+T6WYl3vxeM08y1QU6vR9GqummDMinfWLj0hV+dYwI9/1fHIjfPqgxPUa5AGw7ik
30+
vyrvAgMBAAGjUzBRMB0GA1UdDgQWBBQz80R5aRb/egnEMKHQonUM3xgj6DAfBgNV
31+
HSMEGDAWgBQz80R5aRb/egnEMKHQonUM3xgj6DAPBgNVHRMBAf8EBTADAQH/MA0G
32+
CSqGSIb3DQEBCwUAA4IBAQCdiBvQx6ExmteTzwkGCheKwUMvzCehuwvpoJRE/JXo
33+
zz67414oyWXkSN8/9HE3nkH/xxunD/Ni+N9ppk7iicSpyOKfdDXiaS8qq1O1OXCx
34+
CjoVuIFAPFWOEEhLdnb1v8YVWx2JwcbGvhCLNSoK1a6uwCmWixtoeQiKspBfwFcb
35+
wfU9qNdXsezBljahE4Q2E4SR+XclA6iHdooX4ajnleamqeH0ephyCqvMAhzfJA5F
36+
O1+SJRFbIjwfKxsEJS6Czrn+EU2eLtxk5g5+oO06ZYj4rVOfgc2Wc0+cisgP0fT/
37+
WVkAxgGS6L0jGvZSisEUBpoidJNddWnf9mzUT2kJ5DCOMAwwCgYIKwYBBQUHAwE=
38+
-----END TRUSTED CERTIFICATE-----
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDETCCAfmgAwIBAgIUW99nJU3DgZdPE4KtDWgL6cTrEAgwDQYJKoZIhvcNAQEL
3+
BQAwGDEWMBQGA1UEAwwNVGhpcmRwYXJ0eSBDQTAeFw0yMDExMTgxNTQ0NTJaFw0z
4+
MDExMTYxNTQ0NTJaMBgxFjAUBgNVBAMMDVRoaXJkcGFydHkgQ0EwggEiMA0GCSqG
5+
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDs4Haoc6xj4cTiGYzcqLBiX6fnDpmVPXaD
6+
kE6s0iFYuqZcZgFIuVetgWn4ew7NvDgm1HwCA6EnKBY4zxMd+xic2vO8Pm9SqNWB
7+
0bIdyKvHn1o3u9TMRcnHbp4MvlTTsd0Hr91n+J6Kv7TVUihhsWQH6YILqaKMaEa3
8+
78ssaLrTULdCHQ3vB0XyZGj3NLv5PYq6Yt92hG8M7vyVeBPdEECidD1csAOefk8T
9+
EBRgXgl7dpBa16dZ9nNQzurxOGrRgFsW4wIQit3AU/Y3Zyz1f9hTcG+xHGHUzzsy
10+
jaV345Mdito5DNaGqkh+7PUccb1JihuS6ePZl5J6GQSjktFwPL2jAgMBAAGjUzBR
11+
MB0GA1UdDgQWBBRKB5Wwmh4CsZHFmnAczPb6wjMRajAfBgNVHSMEGDAWgBRKB5Ww
12+
mh4CsZHFmnAczPb6wjMRajAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
13+
A4IBAQCs7kfOgqFXpYqAYjxq+NlQeeWSyEMdU/5QbSjxS68U3wXZ2JR+N7ptmn8B
14+
IaeIF8BMFkLKKCG0s486YnOGKBkmbE5xxAJYctzJSrAjCtkBqqCVMtqpomuXawJv
15+
tB+HwKV3IW43lM8S3DJ5XbEWlZctqGb803ud6Mt2Rlyc6afPyFzt5DPrgvwkgKmX
16+
cLgkvUP0W4dinOG3PqE5NbxqIMw+0kzyrbGYLO7Klwsqjfms++XXIdREzS/nt8+9
17+
c2uERABlpV58p/xyZjJMGGnU0YIhOfn6+LQ6gyqU3qKdj6/VtcQ6SnZC3GE3adqT
18+
LpdSdMc5aL5hr2hZl/uVvrKLYDGz
19+
-----END CERTIFICATE-----
20+
-----BEGIN CERTIFICATE-----
21+
MIIDHTCCAgWgAwIBAgIUK+x25LNYYMHS83aWDnAYviwxEYEwDQYJKoZIhvcNAQEL
22+
BQAwHjEcMBoGA1UEAwwTVGVzdCBTZWxmLVNpZ25lZCBDQTAeFw0yMDExMTgwMjMw
23+
NDNaFw0zMDExMTYwMjMwNDNaMB4xHDAaBgNVBAMME1Rlc3QgU2VsZi1TaWduZWQg
24+
Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC92114uygw5KcqPCz1
25+
E/Cwd3Lo2ytyPD9FchWKPOxXpNisHMOr4zAfsxERXmgBLawHIkqc2Xae3TqHGGQa
26+
ll3J3HukwghZQAyjcNG/Q2Q2QqfQW1tzxHRnz2EKBoRoyhmVXcnu+qBoEgkf5QI/
27+
Rk9HzLJINZPcZuMEkRgcf5q1h/F+PY2yCMwT5qjB6whn6zX6FP6G3//fRtkZw4cI
28+
FPPjKJedbHlYEifRigmJfu+T5Q5xz19Og/1zDwfl7is5eBUV+KEoIE7UpmvR1UrM
29+
+T6WYl3vxeM08y1QU6vR9GqummDMinfWLj0hV+dYwI9/1fHIjfPqgxPUa5AGw7ik
30+
vyrvAgMBAAGjUzBRMB0GA1UdDgQWBBQz80R5aRb/egnEMKHQonUM3xgj6DAfBgNV
31+
HSMEGDAWgBQz80R5aRb/egnEMKHQonUM3xgj6DAPBgNVHRMBAf8EBTADAQH/MA0G
32+
CSqGSIb3DQEBCwUAA4IBAQCdiBvQx6ExmteTzwkGCheKwUMvzCehuwvpoJRE/JXo
33+
zz67414oyWXkSN8/9HE3nkH/xxunD/Ni+N9ppk7iicSpyOKfdDXiaS8qq1O1OXCx
34+
CjoVuIFAPFWOEEhLdnb1v8YVWx2JwcbGvhCLNSoK1a6uwCmWixtoeQiKspBfwFcb
35+
wfU9qNdXsezBljahE4Q2E4SR+XclA6iHdooX4ajnleamqeH0ephyCqvMAhzfJA5F
36+
O1+SJRFbIjwfKxsEJS6Czrn+EU2eLtxk5g5+oO06ZYj4rVOfgc2Wc0+cisgP0fT/
37+
WVkAxgGS6L0jGvZSisEUBpoidJNddWnf9mzUT2kJ5DCO
38+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)