Skip to content

Commit c7a6631

Browse files
committed
feat(redis): add Cluster, Sentinel, and TLS/SSL support
Redis deployment modes: - Three modes: standalone (default), cluster, sentinel - Full TLS/SSL configuration for managed Redis services (GCP Memorystore, AWS ElastiCache, Azure Cache) - Key prefixing for multi-tenant deployments - Pipeline transaction=False for cluster cross-slot compat - Empty password/nodes sanitization for Helm deployments Infrastructure: - Add .editorconfig for consistent coding style - Docker Compose for Redis Cluster and Cluster+TLS testing - TLS cert generation/cleanup scripts for integration tests - Update Helm chart with Redis deployment mode config - Update docs: CONFIGURATION with Redis Cluster/Sentinel/TLS Service updates: - All Redis-backed services use key-prefixed make_key() - Session, state, file, metrics, health, api_key services updated - Config validator enhanced for Redis modes
1 parent 53e445d commit c7a6631

31 files changed

Lines changed: 2781 additions & 130 deletions

.editorconfig

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
root = true
2+
3+
[*]
4+
end_of_line = lf
5+
insert_final_newline = true
6+
trim_trailing_whitespace = true
7+
charset = utf-8
8+
9+
[*.py]
10+
indent_style = space
11+
indent_size = 4
12+
max_line_length = 120
13+
14+
[*.go]
15+
indent_style = tab
16+
indent_size = 4
17+
18+
[*.{yml,yaml}]
19+
indent_style = space
20+
indent_size = 2
21+
22+
[*.{sh,bash}]
23+
indent_style = space
24+
indent_size = 2
25+
26+
[*.{toml,cfg,ini}]
27+
indent_style = space
28+
indent_size = 4
29+
30+
[*.{js,ts,json}]
31+
indent_style = space
32+
indent_size = 2
33+
34+
[*.{html,css}]
35+
indent_style = space
36+
indent_size = 2
37+
38+
[*.md]
39+
trim_trailing_whitespace = false
40+
41+
[Dockerfile*]
42+
indent_style = space
43+
indent_size = 4
44+
45+
[Makefile]
46+
indent_style = tab
47+
48+
[justfile]
49+
indent_style = space
50+
indent_size = 4
51+
52+
[*.{tf,hcl}]
53+
indent_style = space
54+
indent_size = 2
55+
56+
[helm-deployments/**/*.yaml]
57+
indent_style = space
58+
indent_size = 2

.env.example

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ API_KEY_CACHE_TTL=300
3232
RATE_LIMIT_ENABLED=true
3333

3434
# Redis Configuration
35+
# Deployment mode: standalone (default), cluster, or sentinel
36+
REDIS_MODE=standalone
3537
REDIS_HOST=localhost
3638
REDIS_PORT=6379
3739
REDIS_PASSWORD=
@@ -42,6 +44,33 @@ REDIS_MAX_CONNECTIONS=20
4244
REDIS_SOCKET_TIMEOUT=5
4345
REDIS_SOCKET_CONNECT_TIMEOUT=5
4446

47+
# Optional key prefix — useful when sharing a Redis instance across environments
48+
# All keys will be stored as <prefix><key> (e.g. "prod:sessions:abc")
49+
REDIS_KEY_PREFIX=
50+
51+
# Redis Cluster Mode (REDIS_MODE=cluster)
52+
# Comma-separated list of host:port pairs for cluster startup nodes
53+
# REDIS_CLUSTER_NODES=node1:6379,node2:6379,node3:6379
54+
55+
# Redis Sentinel Mode (REDIS_MODE=sentinel)
56+
# Comma-separated list of host:port pairs for Sentinel instances
57+
# REDIS_SENTINEL_NODES=sentinel1:26379,sentinel2:26379,sentinel3:26379
58+
# REDIS_SENTINEL_MASTER=mymaster
59+
# REDIS_SENTINEL_PASSWORD=
60+
61+
# Redis TLS/SSL Configuration
62+
# Required for most managed Redis services (GCP Memorystore, AWS ElastiCache, Azure Cache)
63+
REDIS_TLS_ENABLED=false
64+
# REDIS_TLS_CA_CERT_FILE=/path/to/ca.crt
65+
# REDIS_TLS_CERT_FILE=/path/to/client.crt
66+
# REDIS_TLS_KEY_FILE=/path/to/client.key
67+
# REDIS_TLS_INSECURE=false
68+
# Hostname verification is off by default because managed Redis services
69+
# and Redis Cluster mode expose node IPs that don't match cert CN/SAN.
70+
# The CA certificate chain is still fully verified. Enable hostname
71+
# checking when your Redis server hostnames match certificate CN/SAN.
72+
# REDIS_TLS_CHECK_HOSTNAME=false
73+
4574
# MinIO/S3 Configuration
4675
MINIO_ENDPOINT=localhost:9000
4776
MINIO_ACCESS_KEY=minioadmin
@@ -144,6 +173,37 @@ METRICS_ARCHIVE_RETENTION_DAYS=90
144173
ENABLE_NETWORK_ISOLATION=true
145174
ENABLE_FILESYSTEM_ISOLATION=true
146175

176+
# Kubernetes Execution Configuration
177+
# Execution mode: 'agent' (default, recommended) or 'nsenter' (legacy)
178+
# agent: Executor-agent binary runs inside the main container.
179+
# No nsenter, no capabilities, no privilege escalation.
180+
# Compatible with GKE Sandbox (gVisor) and restricted Pod Security Standards.
181+
# nsenter: Sidecar uses nsenter to enter the main container's mount namespace.
182+
# Requires shareProcessNamespace, SYS_PTRACE/SYS_ADMIN/SYS_CHROOT caps,
183+
# and allowPrivilegeEscalation: true. NOT compatible with GKE Sandbox.
184+
K8S_EXECUTION_MODE=agent
185+
# K8S_EXECUTOR_PORT=9090 # Port for the executor-agent HTTP server (agent mode only)
186+
187+
# Sidecar image — must match the execution mode:
188+
# agent mode: aronmuon/kubecoderun-sidecar-agent:latest (default)
189+
# nsenter mode: aronmuon/kubecoderun-sidecar-nsenter:latest
190+
# K8S_SIDECAR_IMAGE=aronmuon/kubecoderun-sidecar-agent:latest
191+
192+
# Image pull policy for execution pods (Always, IfNotPresent, Never)
193+
# K8S_IMAGE_PULL_POLICY=Always
194+
195+
# Image pull secrets for private container registries (comma-separated secret names)
196+
# These Kubernetes secrets must already exist in the execution namespace.
197+
# Leave empty or unset if not using private registries.
198+
# K8S_IMAGE_PULL_SECRETS=my-registry-secret,another-secret
199+
200+
# GKE Sandbox (gVisor) Configuration
201+
# Requires K8S_EXECUTION_MODE=agent (nsenter is incompatible with gVisor)
202+
# GKE_SANDBOX_ENABLED=false
203+
# GKE_SANDBOX_RUNTIME_CLASS=gvisor
204+
# GKE_SANDBOX_NODE_SELECTOR={}
205+
# GKE_SANDBOX_CUSTOM_TOLERATIONS=[]
206+
147207
# WAN Network Access Configuration
148208
# When enabled, execution containers can access the public internet
149209
# but are blocked from accessing host, other containers, and private networks

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,5 @@ config/local.py
200200

201201
# Hatch auto-generated version file
202202
_version.py
203+
204+
.pdm-python
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
# Redis Cluster with TLS for integration testing
2+
#
3+
# This mimics a production GCP Memorystore Redis Cluster setup:
4+
# - 6-node cluster (3 masters + 3 replicas) with TLS enabled
5+
# - No authentication (no password)
6+
# - Server-side TLS with CA verification (no mutual TLS / no client certs)
7+
# - Accessible on localhost ports 6380-6385 (TLS)
8+
#
9+
# Prerequisites:
10+
# cd tests/tls-certs && ./generate.sh (generates CA + server certificates)
11+
# cd tests/tls-certs && ./cleanup.sh (removes generated certs)
12+
#
13+
# Usage:
14+
# docker compose -f docker-compose.redis-cluster-tls.yml up -d
15+
#
16+
# Test with:
17+
# redis-cli -c -p 6380 --tls --cacert tests/tls-certs/ca.crt CLUSTER INFO
18+
19+
services:
20+
redis-tls-node-0:
21+
image: redis:7-alpine
22+
container_name: redis-tls-cluster-0
23+
ports:
24+
- "127.0.0.1:6380:6380"
25+
- "127.0.0.1:16380:16380"
26+
volumes:
27+
- redis-tls-cluster-0:/data
28+
- ./tests/tls-certs:/tls:ro
29+
command: >
30+
redis-server
31+
--port 0
32+
--tls-port 6380
33+
--tls-cert-file /tls/redis.crt
34+
--tls-key-file /tls/redis.key
35+
--tls-ca-cert-file /tls/ca.crt
36+
--tls-auth-clients no
37+
--tls-replication yes
38+
--cluster-enabled yes
39+
--cluster-config-file nodes.conf
40+
--cluster-node-timeout 5000
41+
--appendonly yes
42+
--bind 0.0.0.0
43+
--protected-mode no
44+
healthcheck:
45+
test: ["CMD", "redis-cli", "-p", "6380", "--tls", "--cert", "/tls/redis.crt", "--key", "/tls/redis.key", "--cacert", "/tls/ca.crt", "ping"]
46+
interval: 5s
47+
timeout: 3s
48+
retries: 10
49+
50+
redis-tls-node-1:
51+
image: redis:7-alpine
52+
container_name: redis-tls-cluster-1
53+
ports:
54+
- "127.0.0.1:6381:6381"
55+
- "127.0.0.1:16381:16381"
56+
volumes:
57+
- redis-tls-cluster-1:/data
58+
- ./tests/tls-certs:/tls:ro
59+
command: >
60+
redis-server
61+
--port 0
62+
--tls-port 6381
63+
--tls-cert-file /tls/redis.crt
64+
--tls-key-file /tls/redis.key
65+
--tls-ca-cert-file /tls/ca.crt
66+
--tls-auth-clients no
67+
--tls-replication yes
68+
--cluster-enabled yes
69+
--cluster-config-file nodes.conf
70+
--cluster-node-timeout 5000
71+
--appendonly yes
72+
--bind 0.0.0.0
73+
--protected-mode no
74+
healthcheck:
75+
test: ["CMD", "redis-cli", "-p", "6381", "--tls", "--cert", "/tls/redis.crt", "--key", "/tls/redis.key", "--cacert", "/tls/ca.crt", "ping"]
76+
interval: 5s
77+
timeout: 3s
78+
retries: 10
79+
80+
redis-tls-node-2:
81+
image: redis:7-alpine
82+
container_name: redis-tls-cluster-2
83+
ports:
84+
- "127.0.0.1:6382:6382"
85+
- "127.0.0.1:16382:16382"
86+
volumes:
87+
- redis-tls-cluster-2:/data
88+
- ./tests/tls-certs:/tls:ro
89+
command: >
90+
redis-server
91+
--port 0
92+
--tls-port 6382
93+
--tls-cert-file /tls/redis.crt
94+
--tls-key-file /tls/redis.key
95+
--tls-ca-cert-file /tls/ca.crt
96+
--tls-auth-clients no
97+
--tls-replication yes
98+
--cluster-enabled yes
99+
--cluster-config-file nodes.conf
100+
--cluster-node-timeout 5000
101+
--appendonly yes
102+
--bind 0.0.0.0
103+
--protected-mode no
104+
healthcheck:
105+
test: ["CMD", "redis-cli", "-p", "6382", "--tls", "--cert", "/tls/redis.crt", "--key", "/tls/redis.key", "--cacert", "/tls/ca.crt", "ping"]
106+
interval: 5s
107+
timeout: 3s
108+
retries: 10
109+
110+
redis-tls-node-3:
111+
image: redis:7-alpine
112+
container_name: redis-tls-cluster-3
113+
ports:
114+
- "127.0.0.1:6383:6383"
115+
- "127.0.0.1:16383:16383"
116+
volumes:
117+
- redis-tls-cluster-3:/data
118+
- ./tests/tls-certs:/tls:ro
119+
command: >
120+
redis-server
121+
--port 0
122+
--tls-port 6383
123+
--tls-cert-file /tls/redis.crt
124+
--tls-key-file /tls/redis.key
125+
--tls-ca-cert-file /tls/ca.crt
126+
--tls-auth-clients no
127+
--tls-replication yes
128+
--cluster-enabled yes
129+
--cluster-config-file nodes.conf
130+
--cluster-node-timeout 5000
131+
--appendonly yes
132+
--bind 0.0.0.0
133+
--protected-mode no
134+
healthcheck:
135+
test: ["CMD", "redis-cli", "-p", "6383", "--tls", "--cert", "/tls/redis.crt", "--key", "/tls/redis.key", "--cacert", "/tls/ca.crt", "ping"]
136+
interval: 5s
137+
timeout: 3s
138+
retries: 10
139+
140+
redis-tls-node-4:
141+
image: redis:7-alpine
142+
container_name: redis-tls-cluster-4
143+
ports:
144+
- "127.0.0.1:6384:6384"
145+
- "127.0.0.1:16384:16384"
146+
volumes:
147+
- redis-tls-cluster-4:/data
148+
- ./tests/tls-certs:/tls:ro
149+
command: >
150+
redis-server
151+
--port 0
152+
--tls-port 6384
153+
--tls-cert-file /tls/redis.crt
154+
--tls-key-file /tls/redis.key
155+
--tls-ca-cert-file /tls/ca.crt
156+
--tls-auth-clients no
157+
--tls-replication yes
158+
--cluster-enabled yes
159+
--cluster-config-file nodes.conf
160+
--cluster-node-timeout 5000
161+
--appendonly yes
162+
--bind 0.0.0.0
163+
--protected-mode no
164+
healthcheck:
165+
test: ["CMD", "redis-cli", "-p", "6384", "--tls", "--cert", "/tls/redis.crt", "--key", "/tls/redis.key", "--cacert", "/tls/ca.crt", "ping"]
166+
interval: 5s
167+
timeout: 3s
168+
retries: 10
169+
170+
redis-tls-node-5:
171+
image: redis:7-alpine
172+
container_name: redis-tls-cluster-5
173+
ports:
174+
- "127.0.0.1:6385:6385"
175+
- "127.0.0.1:16385:16385"
176+
volumes:
177+
- redis-tls-cluster-5:/data
178+
- ./tests/tls-certs:/tls:ro
179+
command: >
180+
redis-server
181+
--port 0
182+
--tls-port 6385
183+
--tls-cert-file /tls/redis.crt
184+
--tls-key-file /tls/redis.key
185+
--tls-ca-cert-file /tls/ca.crt
186+
--tls-auth-clients no
187+
--tls-replication yes
188+
--cluster-enabled yes
189+
--cluster-config-file nodes.conf
190+
--cluster-node-timeout 5000
191+
--appendonly yes
192+
--bind 0.0.0.0
193+
--protected-mode no
194+
healthcheck:
195+
test: ["CMD", "redis-cli", "-p", "6385", "--tls", "--cert", "/tls/redis.crt", "--key", "/tls/redis.key", "--cacert", "/tls/ca.crt", "ping"]
196+
interval: 5s
197+
timeout: 3s
198+
retries: 10
199+
200+
# Initializer: creates TLS cluster from the 6 nodes
201+
redis-tls-cluster-init:
202+
image: redis:7-alpine
203+
container_name: redis-tls-cluster-init
204+
volumes:
205+
- ./tests/tls-certs:/tls:ro
206+
depends_on:
207+
redis-tls-node-0:
208+
condition: service_healthy
209+
redis-tls-node-1:
210+
condition: service_healthy
211+
redis-tls-node-2:
212+
condition: service_healthy
213+
redis-tls-node-3:
214+
condition: service_healthy
215+
redis-tls-node-4:
216+
condition: service_healthy
217+
redis-tls-node-5:
218+
condition: service_healthy
219+
restart: "no"
220+
entrypoint:
221+
- sh
222+
- -c
223+
- |
224+
echo 'Creating Redis TLS Cluster...' &&
225+
redis-cli --cluster create redis-tls-node-0:6380 redis-tls-node-1:6381 redis-tls-node-2:6382 redis-tls-node-3:6383 redis-tls-node-4:6384 redis-tls-node-5:6385 --cluster-replicas 1 --cluster-yes --tls --cert /tls/redis.crt --key /tls/redis.key --cacert /tls/ca.crt &&
226+
echo 'Redis TLS Cluster created successfully' &&
227+
redis-cli -h redis-tls-node-0 -p 6380 --tls --cert /tls/redis.crt --key /tls/redis.key --cacert /tls/ca.crt CLUSTER INFO
228+
229+
volumes:
230+
redis-tls-cluster-0:
231+
redis-tls-cluster-1:
232+
redis-tls-cluster-2:
233+
redis-tls-cluster-3:
234+
redis-tls-cluster-4:
235+
redis-tls-cluster-5:

0 commit comments

Comments
 (0)