6
6
This class handles certificate request and renewal through
7
7
the interaction with the TLS Certificates Operator.
8
8
9
- This library needs that https://charmhub.io/tls-certificates-interface/libraries/tls_certificates
10
- library is imported to work.
9
+ This library needs that the following libraries are imported to work:
10
+ - https://charmhub.io/certificate-transfer-interface/libraries/certificate_transfer
11
+ - https://charmhub.io/tls-certificates-interface/libraries/tls_certificates
11
12
12
13
It also needs the following methods in the charm class:
13
14
— get_hostname_by_unit: to retrieve the DNS hostname of the unit.
24
25
import socket
25
26
from typing import List , Optional
26
27
28
+ from charms .certificate_transfer_interface .v0 .certificate_transfer import (
29
+ CertificateAvailableEvent as CertificateAddedEvent ,
30
+ )
31
+ from charms .certificate_transfer_interface .v0 .certificate_transfer import (
32
+ CertificateRemovedEvent as CertificateRemovedEvent ,
33
+ )
34
+ from charms .certificate_transfer_interface .v0 .certificate_transfer import (
35
+ CertificateTransferRequires ,
36
+ )
27
37
from charms .tls_certificates_interface .v2 .tls_certificates import (
28
38
CertificateAvailableEvent ,
29
39
CertificateExpiringEvent ,
45
55
46
56
# Increment this PATCH version before using `charmcraft publish-lib` or reset
47
57
# to 0 if you are raising the major API version.
48
- LIBPATCH = 13
58
+ LIBPATCH = 14
49
59
50
60
logger = logging .getLogger (__name__ )
51
61
SCOPE = "unit"
52
- TLS_RELATION = "certificates"
62
+ TLS_CREATION_RELATION = "certificates"
63
+ TLS_TRANSFER_RELATION = "receive-ca-cert"
53
64
54
65
55
66
class PostgreSQLTLS (Object ):
@@ -63,18 +74,29 @@ def __init__(
63
74
self .charm = charm
64
75
self .peer_relation = peer_relation
65
76
self .additional_dns_names = additional_dns_names or []
66
- self .certs = TLSCertificatesRequiresV2 (self .charm , TLS_RELATION )
77
+ self .certs_creation = TLSCertificatesRequiresV2 (self .charm , TLS_CREATION_RELATION )
78
+ self .certs_transfer = CertificateTransferRequires (self .charm , TLS_TRANSFER_RELATION )
67
79
self .framework .observe (
68
80
self .charm .on .set_tls_private_key_action , self ._on_set_tls_private_key
69
81
)
70
82
self .framework .observe (
71
- self .charm .on [TLS_RELATION ].relation_joined , self ._on_tls_relation_joined
83
+ self .charm .on [TLS_CREATION_RELATION ].relation_joined , self ._on_tls_relation_joined
84
+ )
85
+ self .framework .observe (
86
+ self .charm .on [TLS_CREATION_RELATION ].relation_broken , self ._on_tls_relation_broken
87
+ )
88
+ self .framework .observe (
89
+ self .certs_creation .on .certificate_available , self ._on_certificate_available
90
+ )
91
+ self .framework .observe (
92
+ self .certs_creation .on .certificate_expiring , self ._on_certificate_expiring
72
93
)
73
94
self .framework .observe (
74
- self .charm .on [TLS_RELATION ].relation_broken , self ._on_tls_relation_broken
95
+ self .certs_transfer .on .certificate_available , self ._on_certificate_added
96
+ )
97
+ self .framework .observe (
98
+ self .certs_transfer .on .certificate_removed , self ._on_certificate_removed
75
99
)
76
- self .framework .observe (self .certs .on .certificate_available , self ._on_certificate_available )
77
- self .framework .observe (self .certs .on .certificate_expiring , self ._on_certificate_expiring )
78
100
79
101
def _on_set_tls_private_key (self , event : ActionEvent ) -> None :
80
102
"""Set the TLS private key, which will be used for requesting the certificate."""
@@ -93,8 +115,8 @@ def _request_certificate(self, param: Optional[str]):
93
115
self .charm .set_secret (SCOPE , "key" , key .decode ("utf-8" ))
94
116
self .charm .set_secret (SCOPE , "csr" , csr .decode ("utf-8" ))
95
117
96
- if self .charm .model .get_relation (TLS_RELATION ):
97
- self .certs .request_certificate_creation (certificate_signing_request = csr )
118
+ if self .charm .model .get_relation (TLS_CREATION_RELATION ):
119
+ self .certs_creation .request_certificate_creation (certificate_signing_request = csr )
98
120
99
121
@staticmethod
100
122
def _parse_tls_file (raw_content : str ) -> bytes :
@@ -117,6 +139,7 @@ def _on_tls_relation_broken(self, event: RelationBrokenEvent) -> None:
117
139
self .charm .set_secret (SCOPE , "ca" , None )
118
140
self .charm .set_secret (SCOPE , "cert" , None )
119
141
self .charm .set_secret (SCOPE , "chain" , None )
142
+
120
143
if not self .charm .update_config ():
121
144
logger .debug ("Cannot update config at this moment" )
122
145
event .defer ()
@@ -163,12 +186,52 @@ def _on_certificate_expiring(self, event: CertificateExpiringEvent) -> None:
163
186
subject = self .charm .get_hostname_by_unit (self .charm .unit .name ),
164
187
** self ._get_sans (),
165
188
)
166
- self .certs .request_certificate_renewal (
189
+ self .certs_creation .request_certificate_renewal (
167
190
old_certificate_signing_request = old_csr ,
168
191
new_certificate_signing_request = new_csr ,
169
192
)
170
193
self .charm .set_secret (SCOPE , "csr" , new_csr .decode ("utf-8" ))
171
194
195
+ def _on_certificate_added (self , event : CertificateAddedEvent ) -> None :
196
+ """Enable TLS when TLS certificate is added."""
197
+ relation = self .charm .model .get_relation (TLS_TRANSFER_RELATION , event .relation_id )
198
+ if relation is None :
199
+ logger .error ("Relationship not established anymore." )
200
+ return
201
+
202
+ secret_name = f"ca-{ relation .app .name } "
203
+ self .charm .set_secret (SCOPE , secret_name , event .ca )
204
+
205
+ try :
206
+ if not self .charm .push_ca_file_into_workload (secret_name ):
207
+ logger .debug ("Cannot push TLS certificates at this moment" )
208
+ event .defer ()
209
+ return
210
+ except (PebbleConnectionError , PathError , ProtocolError , RetryError ) as e :
211
+ logger .error ("Cannot push TLS certificates: %r" , e )
212
+ event .defer ()
213
+ return
214
+
215
+ def _on_certificate_removed (self , event : CertificateRemovedEvent ) -> None :
216
+ """Disable TLS when TLS certificate is removed."""
217
+ relation = self .charm .model .get_relation (TLS_TRANSFER_RELATION , event .relation_id )
218
+ if relation is None :
219
+ logger .error ("Relationship not established anymore." )
220
+ return
221
+
222
+ secret_name = f"ca-{ relation .app .name } "
223
+ self .charm .set_secret (SCOPE , secret_name , None )
224
+
225
+ try :
226
+ if not self .charm .clean_ca_file_from_workload (secret_name ):
227
+ logger .debug ("Cannot clean CA certificates at this moment" )
228
+ event .defer ()
229
+ return
230
+ except (PebbleConnectionError , PathError , ProtocolError , RetryError ) as e :
231
+ logger .error ("Cannot clean CA certificates: %r" , e )
232
+ event .defer ()
233
+ return
234
+
172
235
def _get_sans (self ) -> dict :
173
236
"""Create a list of Subject Alternative Names for a PostgreSQL unit.
174
237
0 commit comments