Switch TLS certificates to APP mode and share via peer relation#461
Switch TLS certificates to APP mode and share via peer relation#461
Conversation
- Changed TLSCertificatesRequiresV4 mode from Mode.UNIT to Mode.APP - Added certificate sharing via haproxy-peer relation app databag - Leader unit shares certificate data (cert, chain, private key) to peers - Non-leader units read certificate data from peer relation - Added _get_tls_information() helper for leader/non-leader branching - Added _reconcile_certificates() to handle sharing after writing to disk - Hooked peer relation-changed event to reconcile loop - Updated test fixtures for APP mode (local_app_data for CSR data, leader=True) Agent-Logs-Url: https://github.com/canonical/haproxy-operator/sessions/984ade73-92cb-4e20-89e1-2f2c22483668 Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com>
- Test leader shares certificates to peer relation app databag - Test non-leader reads certificates from peer relation - Test non-leader without peer data skips TLS gracefully - Test non-leader haproxy-route reads from peer relation - Test share_certificates_via_peer_relation method directly - Test get_tls_information_from_peer_relation with data - Test get_tls_information_from_peer_relation without data returns None Agent-Logs-Url: https://github.com/canonical/haproxy-operator/sessions/984ade73-92cb-4e20-89e1-2f2c22483668 Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com>
- Fix ruff RUF059: prefix unused variable with underscore - Fix ruff RUF015: use next() instead of list comprehension slice - Fix mypy union-attr: add assertions for optional relation types - Improve type annotation: use Application instead of typing.Any Agent-Logs-Url: https://github.com/canonical/haproxy-operator/sessions/984ade73-92cb-4e20-89e1-2f2c22483668 Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com>
| self.haproxy_service.reconcile_default(charm_state) | ||
| self.unit.status = ops.ActiveStatus() | ||
|
|
||
| def _get_tls_information( |
There was a problem hiding this comment.
@copilot This logic needs to be moved to the from_charm method of the TLSInformation dataclass.
There was a problem hiding this comment.
Moved the leader/non-leader branching logic into TLSInformation.from_charm() in state/tls.py. The method now returns Optional[TLSInformation] — leader path reads from the TLS library, non-leader path reads from the peer relation via _from_peer_relation(). Removed _get_tls_information() from charm.py and get_tls_information_from_peer_relation() from TLSRelationService. Also moved PEER_TLS_KEY constant to state/tls.py. See commit a3d6e5a.
…harm - Moved _get_tls_information() logic from charm.py into TLSInformation.from_charm() in state/tls.py per reviewer feedback - from_charm() now returns Optional[TLSInformation]: leader reads from TLS library, non-leader reads from peer relation via new _from_peer_relation() classmethod - Removed _get_tls_information() method from charm.py - Moved PEER_TLS_KEY constant to state/tls.py (canonical location for TLS state) - Removed get_tls_information_from_peer_relation() from TLSRelationService (logic now in TLSInformation._from_peer_relation) - Updated tests to test through TLSInformation.from_charm() Agent-Logs-Url: https://github.com/canonical/haproxy-operator/sessions/96fecf67-9c28-47d1-8590-78ac4718d7c2 Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com>
Agent-Logs-Url: https://github.com/canonical/haproxy-operator/sessions/96fecf67-9c28-47d1-8590-78ac4718d7c2 Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com>
Test results for commit 895766aTest coverage for 895766a Static code analysis report |
Test results for commit 895766aTest coverage for 895766a Static code analysis report |
Test results for commit 895766aTest coverage for 895766a Static code analysis report |
Test results for commit 895766aTest coverage for 895766a Static code analysis report |
Test results for commit 895766aUnit tests failed for 895766a ============================= test session starts ============================== tests/unit/test_charm.py::test_install FAILED =================================== FAILURES =================================== The above exception was the direct cause of the following exception: Traceback (most recent call last): |
Test results for commit 895766aTest coverage for 895766a Static code analysis report |
In HA deployments, each unit was requesting its own TLS certificate (UNIT mode), hitting Let's Encrypt's rate limit of 5 certs per domain per 168h. Switch to APP mode so a single certificate is requested per application, with the leader sharing it to peers.
Core changes
src/state/tls.py:TLSInformation.from_charm()now returnsOptional[TLSInformation]and handles both leader and non-leader paths — leader reads from TLS library, non-leader reads from peer relation via_from_peer_relation().PEER_TLS_KEYconstant is defined here as the canonical location for TLS state.src/charm.py: SwitchTLSCertificatesRequiresV4fromMode.UNITtoMode.APP. All callers useTLSInformation.from_charm()directly for leader/non-leader branching. Add_reconcile_certificates()which writes certs to disk and, if leader, shares to peer relation app databag. Observehaproxy-peersrelation-changedto trigger reconcile on non-leader units when cert data arrives.src/tls_relation.py: Addshare_certificates_via_peer_relation()to serialize cert+chain+key into peer relation app databag. Remove thecertificate_requestsguard fromcertificate_available()since non-leader units receive certs from peers, not the TLS library.Data flow
Test changes
certificates_integrationfixture to uselocal_app_data(APP mode stores CSRs in app databag, not unit databag)leader=Truefrom_charm(), non-leader with haproxy-route mode, round-trip serialization ofTLSInformation, empty peer data returnsNone