Skip to content

Commit 80cee85

Browse files
Copilotmykaul
andcommitted
Add TLS tickets design document
Co-authored-by: mykaul <4655593+mykaul@users.noreply.github.com>
1 parent c3ca7e3 commit 80cee85

1 file changed

Lines changed: 270 additions & 0 deletions

File tree

TLS_TICKETS_DESIGN.md

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
# TLS Tickets Support Design Document
2+
3+
## Overview
4+
5+
This document describes the design and implementation of TLS session ticket support in the Scylla Python driver. TLS session tickets allow for quick TLS renegotiation by resuming previous TLS sessions, reducing the overhead of full handshakes when reconnecting to servers.
6+
7+
## Background
8+
9+
### What are TLS Session Tickets?
10+
11+
TLS session tickets (RFC 5077 and RFC 8446 for TLS 1.3) allow clients to cache session state and reuse it for subsequent connections. This provides:
12+
13+
- **Faster reconnections**: Reduced handshake latency by resuming previous sessions
14+
- **Less CPU usage**: Fewer cryptographic operations during reconnection
15+
- **Better performance**: Especially important for connection pools that frequently reconnect
16+
17+
### Python SSL Support
18+
19+
Python's `ssl` module provides built-in support for TLS session resumption:
20+
21+
- `SSLContext.num_tickets`: Controls the number of TLS 1.3 session tickets (default: 2)
22+
- `SSLSocket.session`: Returns the current session as an `SSLSession` object
23+
- `SSLSocket.session_reused`: Boolean indicating if the session was reused
24+
- `SSLContext.wrap_socket(..., session=...)`: Allows passing a session to reuse
25+
26+
## Current State
27+
28+
The driver currently:
29+
1. Uses `SSLContext` for TLS connections
30+
2. Creates new TLS sessions for each connection
31+
3. Does NOT cache or reuse TLS sessions
32+
4. Does NOT track session statistics
33+
34+
## Design
35+
36+
### Goals
37+
38+
1. **Enable TLS tickets by default** when SSL/TLS is enabled
39+
2. **Implement client-side session cache** to store and reuse sessions
40+
3. **Minimal API changes** - work transparently with existing SSL configuration
41+
4. **Thread-safe** session cache for concurrent connections
42+
5. **Per-endpoint session tracking** to reuse sessions for the same server
43+
44+
### Components
45+
46+
#### 1. TLS Session Cache
47+
48+
A thread-safe cache that stores TLS sessions per endpoint (host:port).
49+
50+
```python
51+
class TLSSessionCache:
52+
"""Thread-safe cache for TLS sessions."""
53+
54+
def __init__(self, max_size=100, ttl=3600):
55+
"""
56+
Args:
57+
max_size: Maximum number of sessions to cache
58+
ttl: Time-to-live for cached sessions in seconds
59+
"""
60+
self._sessions = {} # {endpoint_key: (session, timestamp)}
61+
self._lock = threading.RLock()
62+
self._max_size = max_size
63+
self._ttl = ttl
64+
65+
def get_session(self, endpoint_key):
66+
"""Get cached session for endpoint, if valid."""
67+
pass
68+
69+
def set_session(self, endpoint_key, session):
70+
"""Store session for endpoint."""
71+
pass
72+
73+
def clear_expired(self):
74+
"""Remove expired sessions."""
75+
pass
76+
```
77+
78+
#### 2. Integration Points
79+
80+
##### Cluster Level
81+
- Add `tls_session_cache` attribute to `Cluster` class
82+
- Initialize cache when `ssl_context` or `ssl_options` is provided
83+
- Share cache across all connections in the cluster
84+
85+
##### Connection Level
86+
- Modify `Connection._wrap_socket_from_context()` to:
87+
1. Check cache for existing session for the endpoint
88+
2. Pass cached session to `wrap_socket()` if available
89+
3. Store new session after successful connection
90+
- Track session reuse statistics
91+
92+
### Implementation Details
93+
94+
#### Session Cache Key
95+
96+
Use a tuple of `(host, port)` as the cache key to uniquely identify endpoints.
97+
98+
#### Session Expiration
99+
100+
- Default TTL: 1 hour (3600 seconds)
101+
- Sessions older than TTL are not reused
102+
- Periodic cleanup of expired sessions
103+
104+
#### Cache Size Management
105+
106+
- Default max size: 100 sessions
107+
- When cache is full, remove oldest sessions (LRU policy)
108+
109+
#### Statistics Tracking
110+
111+
Add connection-level attributes:
112+
- `session_reused`: Boolean indicating if current connection reused a session
113+
- Existing `SSLContext.session_stats()` can be queried for overall statistics
114+
115+
### Configuration
116+
117+
#### Cluster Configuration
118+
119+
Users can configure TLS session caching via new parameters:
120+
121+
```python
122+
cluster = Cluster(
123+
contact_points=['127.0.0.1'],
124+
ssl_context=ssl_context,
125+
tls_session_cache_enabled=True, # Default: True
126+
tls_session_cache_size=100, # Default: 100
127+
tls_session_cache_ttl=3600 # Default: 3600 seconds
128+
)
129+
```
130+
131+
For backward compatibility, TLS session caching is **enabled by default** when SSL is configured.
132+
133+
#### Disabling Session Cache
134+
135+
Users can disable session caching by setting:
136+
```python
137+
cluster = Cluster(
138+
...,
139+
tls_session_cache_enabled=False
140+
)
141+
```
142+
143+
## Implementation Plan
144+
145+
### Phase 1: Core Implementation
146+
147+
1. **Create TLSSessionCache class** in `cassandra/connection.py`
148+
- Thread-safe dictionary-based cache
149+
- TTL and max_size management
150+
- LRU eviction policy
151+
152+
2. **Modify Cluster class** in `cassandra/cluster.py`
153+
- Add configuration parameters
154+
- Initialize session cache when SSL is enabled
155+
- Pass cache to connections
156+
157+
3. **Modify Connection class** in `cassandra/connection.py`
158+
- Accept session cache in constructor
159+
- Implement session retrieval and storage
160+
- Update `_wrap_socket_from_context()` to use cached sessions
161+
162+
### Phase 2: Testing
163+
164+
1. **Unit tests**
165+
- Test TLSSessionCache operations
166+
- Test cache expiration and eviction
167+
- Test thread safety
168+
169+
2. **Integration tests**
170+
- Test session reuse across connections
171+
- Test with real SSL/TLS connections
172+
- Verify performance improvements
173+
174+
### Phase 3: Documentation
175+
176+
1. Update API documentation
177+
2. Add usage examples
178+
3. Document configuration options
179+
180+
## Testing Strategy
181+
182+
### Unit Tests
183+
184+
1. **TLSSessionCache Tests**
185+
- Test get/set operations
186+
- Test TTL expiration
187+
- Test max size and LRU eviction
188+
- Test thread safety
189+
190+
2. **Connection Tests**
191+
- Mock SSLContext and SSLSocket
192+
- Verify session is retrieved from cache
193+
- Verify session is stored after connection
194+
- Test with cache disabled
195+
196+
### Integration Tests
197+
198+
1. **SSL Connection Tests** (extend existing `tests/integration/long/test_ssl.py`)
199+
- Connect to SSL-enabled cluster
200+
- Verify first connection creates new session
201+
- Verify second connection reuses session
202+
- Check `session_reused` attribute
203+
- Verify session stats from `SSLContext.session_stats()`
204+
205+
2. **Performance Tests**
206+
- Measure connection time with/without session reuse
207+
- Verify reduced handshake latency
208+
209+
### Test with Different SSL Configurations
210+
211+
- Test with `ssl_context` directly provided
212+
- Test with `ssl_options` (legacy mode)
213+
- Test with cloud config
214+
- Test with twisted/eventlet reactors
215+
216+
## Security Considerations
217+
218+
1. **Session Security**: TLS sessions contain sensitive cryptographic material
219+
- Sessions are stored in memory only (not persisted)
220+
- Sessions expire after TTL
221+
- Sessions are not shared across different clusters
222+
223+
2. **Host Validation**: Sessions are cached per endpoint
224+
- Sessions for host A are not used for host B
225+
- Hostname verification still occurs on each connection
226+
227+
3. **Backward Compatibility**:
228+
- Feature is enabled by default but transparent
229+
- No breaking changes to existing API
230+
- Can be disabled if needed
231+
232+
## Performance Impact
233+
234+
### Expected Benefits
235+
236+
- **Reduced connection time**: 20-50% faster reconnections
237+
- **Lower CPU usage**: Fewer cryptographic operations
238+
- **Better throughput**: Especially for workloads with frequent reconnections
239+
240+
### Overhead
241+
242+
- **Memory**: Minimal (~1KB per cached session)
243+
- **Cache management**: O(1) operations with occasional O(n) cleanup
244+
245+
## Alternatives Considered
246+
247+
### 1. Global Session Cache
248+
249+
**Rejected**: Would share sessions across different clusters, which could be confusing and less secure.
250+
251+
### 2. No TTL/Expiration
252+
253+
**Rejected**: Sessions could become stale or accumulate indefinitely.
254+
255+
### 3. Disable by Default
256+
257+
**Rejected**: Session resumption is a standard TLS feature and should be enabled by default for better performance.
258+
259+
## Future Enhancements
260+
261+
1. **Configurable eviction policies**: LRU, LFU, FIFO
262+
2. **Session statistics**: Track cache hit/miss rates
263+
3. **Metrics integration**: Export session reuse metrics
264+
4. **Session serialization**: Persist sessions across driver restarts (optional)
265+
266+
## References
267+
268+
- [RFC 5077 - TLS Session Resumption without Server-Side State](https://tools.ietf.org/html/rfc5077)
269+
- [RFC 8446 - The Transport Layer Security (TLS) Protocol Version 1.3](https://tools.ietf.org/html/rfc8446)
270+
- [Python ssl module documentation](https://docs.python.org/3/library/ssl.html)

0 commit comments

Comments
 (0)