Skip to content

Commit 41ab82d

Browse files
committed
store the CA private key unencrypted
1 parent f3f978e commit 41ab82d

7 files changed

Lines changed: 60 additions & 22 deletions

File tree

src/roles/candlepin/tasks/certs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
notify:
1010
- Restart candlepin
1111

12-
- name: Decrypt Candlepin CA key
13-
ansible.builtin.command: openssl pkey -in "{{ candlepin_ca_key }}" -passin "file:{{ candlepin_ca_key_password }}"
12+
- name: Export Candlepin CA key
13+
ansible.builtin.command: openssl pkey -in "{{ candlepin_ca_key }}"
1414
register: _candlepin_ca_key
1515
changed_when: false
1616

src/roles/certificates/tasks/ca.yml

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,45 @@
44
path: "{{ certificates_ca_directory_certs }}/ca.crt"
55
register: _certificates_ca_cert
66

7+
- name: 'Check for an existing CA key'
8+
ansible.builtin.stat:
9+
path: "{{ certificates_ca_directory_keys }}/ca.key"
10+
register: _certificates_existing_ca_key
11+
12+
- name: 'Detect whether the existing CA key is password-encrypted'
13+
ansible.builtin.command:
14+
cmd: "grep -q ENCRYPTED {{ certificates_ca_directory_keys }}/ca.key"
15+
register: _certificates_ca_key_encrypted
16+
changed_when: false
17+
failed_when: false
18+
when: _certificates_existing_ca_key.stat.exists
19+
20+
- name: 'Decrypt a legacy password-encrypted CA key in place'
21+
community.crypto.openssl_privatekey_convert:
22+
src_path: "{{ certificates_ca_directory_keys }}/ca.key"
23+
src_passphrase: "{{ certificates_ca_password }}"
24+
dest_path: "{{ certificates_ca_directory_keys }}/ca.key"
25+
format: pkcs8
26+
mode: '0600'
27+
when:
28+
- _certificates_existing_ca_key.stat.exists
29+
- (_certificates_ca_key_encrypted.rc | default(1)) == 0
30+
no_log: true
31+
32+
- name: 'Remove the obsolete CA key password file'
33+
ansible.builtin.file:
34+
path: "{{ certificates_ca_directory_keys }}/ca.pwd"
35+
state: absent
36+
737
- name: 'Generate CA'
838
when:
939
- (not _certificates_ca_cert.stat.exists or certificates_renew_ca)
1040
block:
11-
- name: 'Create CA key password file'
12-
ansible.builtin.copy:
13-
content: "{{ certificates_ca_password }}"
14-
dest: "{{ certificates_ca_directory_keys }}/ca.pwd"
15-
owner: root
16-
group: root
17-
mode: '0600'
18-
no_log: true
19-
2041
- name: 'Create CA private key'
2142
community.crypto.openssl_privatekey:
2243
path: "{{ certificates_ca_directory_keys }}/ca.key"
2344
type: "{{ certificates_algorithm_type }}"
2445
size: "{{ certificates_algorithm_size }}"
25-
passphrase: "{{ certificates_ca_password }}"
2646
owner: root
2747
group: root
2848
mode: '0600'
@@ -31,7 +51,6 @@
3151
community.crypto.openssl_csr:
3252
path: "{{ certificates_ca_directory_requests }}/ca.csr"
3353
privatekey_path: "{{ certificates_ca_directory_keys }}/ca.key"
34-
privatekey_passphrase: "{{ certificates_ca_password }}"
3554
common_name: "{{ certificates_ca_subject }}"
3655
use_common_name_for_san: false
3756
basic_constraints:
@@ -49,7 +68,6 @@
4968
path: "{{ certificates_ca_directory_certs }}/ca.crt"
5069
csr_path: "{{ certificates_ca_directory_requests }}/ca.csr"
5170
privatekey_path: "{{ certificates_ca_directory_keys }}/ca.key"
52-
privatekey_passphrase: "{{ certificates_ca_password }}"
5371
provider: selfsigned
5472
selfsigned_not_after: "+{{ certificates_ca_validity_days }}d"
5573
force: "{{ certificates_renew_ca | bool }}"

src/roles/certificates/tasks/issue.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
provider: ownca
3333
ownca_path: "{{ certificates_ca_directory_certs }}/ca.crt"
3434
ownca_privatekey_path: "{{ certificates_ca_directory_keys }}/ca.key"
35-
ownca_privatekey_passphrase: "{{ certificates_ca_password }}"
3635
ownca_not_after: "+{{ certificates_validity_days }}d"
3736
force: "{{ certificates_renew | bool }}"
3837

@@ -63,6 +62,5 @@
6362
provider: ownca
6463
ownca_path: "{{ certificates_ca_directory }}/certs/ca.crt"
6564
ownca_privatekey_path: "{{ certificates_ca_directory }}/private/ca.key"
66-
ownca_privatekey_passphrase: "{{ certificates_ca_password }}"
6765
ownca_not_after: "+{{ certificates_validity_days }}d"
6866
force: "{{ certificates_renew | bool }}"

src/vars/base.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ certificates_ca_password: "{{ lookup('ansible.builtin.password', certificates_ca
88
candlepin_oauth_secret_file: "{{ obsah_state_path }}/candlepin-oauth-secret"
99
candlepin_oauth_secret: "{{ lookup('ansible.builtin.password', candlepin_oauth_secret_file, chars=['ascii_letters', 'digits'], length=32) }}"
1010

11-
candlepin_ca_key_password: "{{ ca_key_password }}"
1211
candlepin_ca_key: "{{ ca_key }}"
1312
candlepin_ca_certificate: "{{ ca_certificate }}"
1413
candlepin_tomcat_key: "{{ localhost_key }}"

src/vars/certificates.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---
22
certificates_ca_directory: /var/lib/foremanctl/certs
3-
ca_key_password: "{{ certificates_ca_directory }}/private/ca.pwd"
43
ca_certificate: "{{ certificates_ca_directory }}/certs/ca.crt"
54
ca_key: "{{ certificates_ca_directory }}/private/ca.key"
65
server_certificate: "{{ certificates_ca_directory }}/certs/{{ ansible_facts['fqdn'] }}.crt"

tests/certificates_test.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,28 @@ def test_ca_bundle_verifies_server_certificate(server, certificates):
103103
assert "OK" in cmd.stdout
104104

105105

106+
def test_ca_key_unencrypted(server, certificates):
107+
f = server.file(certificates['ca_key'])
108+
assert f.exists
109+
assert f.mode == 0o600
110+
assert 'ENCRYPTED' not in f.content_string
111+
cmd = server.run(f"openssl pkey -in {certificates['ca_key']} -noout")
112+
assert cmd.succeeded
113+
114+
115+
def test_ca_key_password_file_absent(server, certificates):
116+
ca_pwd = certificates['ca_key'].rsplit('/', 1)[0] + '/ca.pwd'
117+
assert not server.file(ca_pwd).exists
118+
119+
120+
def test_ca_key_matches_ca_certificate(server, certificates):
121+
key_pub = server.run(f"openssl pkey -in {certificates['ca_key']} -pubout")
122+
cert_pub = server.run(f"openssl x509 -in {certificates['ca_certificate']} -noout -pubkey")
123+
assert key_pub.succeeded
124+
assert cert_pub.succeeded
125+
assert key_pub.stdout == cert_pub.stdout
126+
127+
106128
@pytest.mark.parametrize("cert_key,expected_mode", [
107129
('server_certificate', 0o444),
108130
('server_ca_certificate', 0o444),

tests/migration_test.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ def test_certificate_directories(server, migrated_environment, subdir):
3333
assert d.mode == 0o755
3434

3535

36-
def test_ca_password_file(server, migrated_environment):
37-
f = server.file("/var/lib/foremanctl/certs/private/ca.pwd")
38-
assert f.exists
39-
assert f.mode == 0o600
36+
def test_ca_key_unencrypted(server, migrated_environment):
37+
assert not server.file("/var/lib/foremanctl/certs/private/ca.pwd").exists
38+
key = server.file("/var/lib/foremanctl/certs/private/ca.key")
39+
assert key.exists
40+
assert key.mode == 0o600
41+
assert "ENCRYPTED" not in key.content_string
4042

4143

4244
def test_ca_password_persisted(migrated_environment, obsah_state_path):

0 commit comments

Comments
 (0)