Skip to content

Commit 6407ec3

Browse files
committed
feat: add global certificate management with secretRef and extraValueFiles
Implements comprehensive certificate management for ZTVP: Certificate Sources: - Primary custom CA via secretRef (customCA.secretRef) - Additional certificates via extraValueFiles (overrides/values-ztvp-certificates.yaml) - Auto-detected proxy CA from trusted-ca-bundle (openshift-config-managed) - Auto-detected ingress CA from all IngressControllers (not just default) - Auto-detected service CA from openshift-service-ca Features: - Initial Job for immediate certificate extraction on install - CronJob for periodic certificate rotation (daily at 2 AM) - Warning and continue behavior for missing additional certificates - Automatic rollout restart for consuming applications (labeled strategy) - ACM Policy distribution to target namespaces Configuration: - Use extraValueFiles for complex nested structures (additionalCertificates, rollout) - Simple overrides via values-hub.yaml for flat key-value pairs Signed-off-by: Min Zhang <minzhang@redhat.com>
1 parent 6195b0c commit 6407ec3

File tree

14 files changed

+1128
-21
lines changed

14 files changed

+1128
-21
lines changed

.github/workflows/superlinter.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
# These are the validation we disable atm
3535
VALIDATE_ANSIBLE: false
3636
VALIDATE_BASH: false
37+
VALIDATE_BASH_EXEC: false
3738
VALIDATE_CHECKOV: false
3839
VALIDATE_JSCPD: false
3940
VALIDATE_JSON_PRETTIER: false

charts/qtodo/files/spiffe-vault-client.py

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ def __init__(self):
2828
self.credentials_file = os.getenv(
2929
"CREDENTIALS_FILE", "/etc/credentials.properties"
3030
)
31+
# ZTVP trusted CA bundle (preferred)
32+
self.ztvp_ca_bundle = os.getenv(
33+
"ZTVP_CA_BUNDLE",
34+
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
35+
)
36+
# Service CA (fallback for backward compatibility)
3137
self.service_ca_file = os.getenv(
3238
"SERVICE_CA_FILE",
3339
"/run/secrets/kubernetes.io/serviceaccount/service-ca.crt",
@@ -54,6 +60,7 @@ def __init__(self):
5460
logger.info(" VAULT_ROLE: %s", self.vault_role)
5561
logger.info(" DB_USERNAME: %s", self.db_username)
5662
logger.info(" CREDENTIALS_FILE: %s", self.credentials_file)
63+
logger.info(" ZTVP_CA_BUNDLE: %s", self.ztvp_ca_bundle)
5764
logger.info(" SERVICE_CA_FILE: %s", self.service_ca_file)
5865
logger.info(" JWT_TOKEN_FILE: %s", self.jwt_token_file)
5966

@@ -63,10 +70,22 @@ def __init__(self):
6370

6471
# Setup SSL context for CA verification
6572
self.ssl_context = ssl.create_default_context()
66-
if os.path.exists(self.service_ca_file):
73+
74+
# Try ZTVP CA bundle first (contains both ingress and service CAs)
75+
if os.path.exists(self.ztvp_ca_bundle):
76+
self.ssl_context.load_verify_locations(self.ztvp_ca_bundle)
77+
logger.info("Loaded ZTVP trusted CA bundle from: %s", self.ztvp_ca_bundle)
78+
# Fallback to service CA only (for backward compatibility)
79+
elif os.path.exists(self.service_ca_file):
6780
self.ssl_context.load_verify_locations(self.service_ca_file)
81+
logger.info("Loaded service CA from: %s", self.service_ca_file)
6882
else:
69-
logger.warning("Service CA file not found, using default SSL context")
83+
logger.warning(
84+
"No CA certificates found at %s or %s. "
85+
"Using default SSL context. SSL verification may fail.",
86+
self.ztvp_ca_bundle,
87+
self.service_ca_file,
88+
)
7089

7190
def _make_http_request(
7291
self, url, method="GET", data=None, headers=None, timeout=30
@@ -111,11 +130,11 @@ def _make_http_request(
111130
"text": error_data,
112131
"json": lambda: (json.loads(error_data) if error_data else {}),
113132
}
114-
except URLError as e:
115-
logger.error("URL Error: %s", e)
133+
except URLError:
134+
logger.error("URL Error occurred")
116135
raise
117-
except Exception as e:
118-
logger.error("Request error: %s", e)
136+
except Exception:
137+
logger.error("Request error occurred")
119138
raise
120139

121140
def get_spiffe_token(self):
@@ -125,8 +144,8 @@ def get_spiffe_token(self):
125144
jwt_svid = source.read()
126145
logger.info("Successfully retrieved SPIFFE JWT token")
127146
return jwt_svid
128-
except Exception as e:
129-
logger.error("Failed to retrieve SPIFFE token: %s", e)
147+
except Exception:
148+
logger.error("Failed to retrieve SPIFFE token")
130149
raise
131150

132151
def authenticate_with_vault(self):
@@ -167,8 +186,8 @@ def authenticate_with_vault(self):
167186

168187
return True
169188

170-
except Exception as e:
171-
logger.error("Vault authentication error: %s", e)
189+
except Exception:
190+
logger.error("Vault authentication error occurred")
172191
raise
173192

174193
def retrieve_vault_secret(self):
@@ -204,8 +223,8 @@ def retrieve_vault_secret(self):
204223

205224
return secret_data
206225

207-
except Exception as e:
208-
logger.error("Secret retrieval error: %s", e)
226+
except Exception:
227+
logger.error("Secret retrieval error occurred")
209228
raise
210229

211230
def extract_credentials(self, secret_data):
@@ -222,8 +241,8 @@ def extract_credentials(self, secret_data):
222241
credentials["db-username"] = self.db_username
223242
return credentials
224243

225-
except Exception as e:
226-
logger.error("Credential extraction error: %s", e)
244+
except Exception:
245+
logger.error("Credential extraction error occurred")
227246
raise
228247

229248
def write_properties_file(self, credentials):
@@ -243,8 +262,8 @@ def write_properties_file(self, credentials):
243262

244263
logger.info("Credentials written to %s", self.credentials_file)
245264

246-
except Exception as e:
247-
logger.error("Error writing properties file: %s", e)
265+
except Exception:
266+
logger.error("Error writing properties file")
248267
raise
249268

250269
def is_token_renewal_needed(self):
@@ -291,8 +310,8 @@ def renew_vault_token(self):
291310
)
292311
return False
293312

294-
except Exception as e:
295-
logger.warning("Token renewal error: %s. Re-authenticating...", e)
313+
except Exception:
314+
logger.warning("Token renewal error occurred. Re-authenticating...")
296315
return False
297316

298317
def run(self, init=False):
@@ -329,8 +348,8 @@ def run(self, init=False):
329348
except KeyboardInterrupt:
330349
logger.info("Received interrupt signal, shutting down...")
331350
break
332-
except Exception as e:
333-
logger.error("Error in main loop: %s", e)
351+
except Exception:
352+
logger.error("Error in main loop")
334353
logger.info("Retrying in 60 seconds...")
335354
time.sleep(60)
336355

@@ -352,7 +371,7 @@ def main():
352371
manager = VaultCredentialManager()
353372
manager.run(args.init)
354373
except Exception as e:
355-
logger.error("Failed to start credential manager: %s", e)
374+
logger.error("Failed to start credential manager")
356375
raise SystemExit(1) from e
357376

358377

charts/qtodo/templates/app-deployment.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ metadata:
55
argocd.argoproj.io/sync-wave: '20'
66
labels:
77
app: qtodo
8+
ztvp.io/uses-certificates: "true"
89
name: qtodo
910
namespace: qtodo
1011
spec:
@@ -65,13 +66,18 @@ spec:
6566
value: /run/secrets/db-credentials/credentials.properties
6667
- name: JWT_TOKEN_FILE
6768
value: /svids/jwt.token
69+
- name: ZTVP_CA_BUNDLE
70+
value: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
6871
volumeMounts:
6972
- name: svids
7073
mountPath: /svids
7174
- name: db-credentials
7275
mountPath: /run/secrets/db-credentials
7376
- name: spiffe-vault-client
7477
mountPath: /opt/app-root/src
78+
- name: ztvp-trusted-ca
79+
mountPath: /etc/pki/ca-trust/extracted/pem
80+
readOnly: true
7581
{{- end }}
7682
containers:
7783
{{- if and .Values.app.spire.enabled .Values.app.spire.sidecars }}
@@ -113,6 +119,8 @@ spec:
113119
value: /run/secrets/db-credentials/credentials.properties
114120
- name: JWT_TOKEN_FILE
115121
value: /svids/jwt.token
122+
- name: ZTVP_CA_BUNDLE
123+
value: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
116124
volumeMounts:
117125
- name: svids
118126
mountPath: /svids
@@ -122,6 +130,9 @@ spec:
122130
- name: spiffe-vault-client
123131
mountPath: /opt/app-root/src
124132
readOnly: true
133+
- name: ztvp-trusted-ca
134+
mountPath: /etc/pki/ca-trust/extracted/pem
135+
readOnly: true
125136
{{- end }}
126137
- name: qtodo
127138
image: {{ .Values.app.images.main.name }}:{{ .Values.app.images.main.tag }}
@@ -195,4 +206,8 @@ spec:
195206
- name: spiffe-vault-client
196207
configMap:
197208
name: spiffe-vault-client
209+
- name: ztvp-trusted-ca
210+
configMap:
211+
name: ztvp-trusted-ca
212+
defaultMode: 420
198213
{{- end }}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: v2
2+
name: ztvp-certificates
3+
description: Global CA certificate management for ZTVP pattern components
4+
type: application
5+
version: 1.0.0
6+
appVersion: "1.0.0"
7+
keywords:
8+
- certificates
9+
- tls
10+
- ssl
11+
- ca-bundle
12+
- zero-trust
13+
home: https://github.com/validatedpatterns/layered-zero-trust
14+
sources:
15+
- https://github.com/validatedpatterns/layered-zero-trust
16+
maintainers:
17+
- name: Zero Trust Validated Patterns Team
18+
email: ztvp-arch-group@redhat.com
19+

0 commit comments

Comments
 (0)