Coverage for scripts / live_release_validation / checks / internal_pki.py: 100.00%

115 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-10-28 16:19 +0000

1"""Internal PKI checks: every in-cluster TLS hop chains to the one GCO internal CA. 

2 

3The in-cluster HTTPS hops (ALB to the API pods, manifest-processor to 

4cost-monitor, cost-monitor to OpenCost, Prometheus to the service metrics, 

5the Grafana rotator to Grafana, inference-proxy to the model pods, MLflow's 

6gco-jobs clients to the tracking server) verify 

7their peers against a single cert-manager CA: a self-signed bootstrap 

8``ClusterIssuer`` issues the ``cert-manager/gco-internal-ca`` CA Certificate, 

9and the ``gco-internal-ca`` ``ClusterIssuer`` signs every leaf from it. A 

10client that trusts only that CA fails closed, so a leaf that was never 

11issued, or was issued by anything else, is a broken hop rather than a 

12cosmetic difference. 

13 

14On the live cluster this requires, per Region: 

15 

16* the ``gco-internal-ca`` ClusterIssuer ``Ready``; 

17* the CA Certificate ``Ready``, ``isCA``, issued by the bootstrap issuer; 

18* every GCO leaf Certificate the configuration deploys ``Ready`` with 

19 ``spec.issuerRef`` naming the ``gco-internal-ca`` ClusterIssuer (the 

20 cost-monitor and OpenCost leaves only with cost monitoring, the Grafana 

21 leaf and the monitoring trust bundle only with cluster observability, the 

22 MLflow leaf and the trust-manager bundle source only with MLflow); and 

23* the retired per-namespace ``gco-api-selfsigned`` Issuer gone. 

24 

25A missing object, a wrong issuer, or the retired Issuer fails on the first 

26look; a Certificate cert-manager is still issuing is polled to a deadline. 

27Reads use the fully qualified ``*.cert-manager.io`` resources so another 

28controller's ``Certificate`` kind (ACK's ACM controller, for one) can never 

29answer instead. 

30""" 

31 

32from __future__ import annotations 

33 

34import time 

35from dataclasses import dataclass 

36from typing import Any 

37 

38from ..models import RunContext 

39from .cluster import KubectlRunner, kubectl_json 

40from .opencost import _cost_monitoring_configured 

41 

42INTERNAL_CA_ISSUER = "gco-internal-ca" 

43BOOTSTRAP_ISSUER = "gco-internal-ca-bootstrap" 

44CA_CERTIFICATE_NAMESPACE = "cert-manager" 

45CA_CERTIFICATE_NAME = "gco-internal-ca" 

46LEGACY_ISSUER_NAMESPACE = "gco-system" 

47LEGACY_ISSUER_NAME = "gco-api-selfsigned" 

48_CERTIFICATES = "certificates.cert-manager.io" 

49_CLUSTER_ISSUERS = "clusterissuers.cert-manager.io" 

50_ISSUERS = "issuers.cert-manager.io" 

51#: Issuance takes seconds; this covers a renewal that happens to be in flight. 

52_READY_TIMEOUT_SECONDS = 300 

53 

54 

55@dataclass(frozen=True) 

56class LeafCertificate: 

57 """One GCO leaf Certificate and the configuration that deploys it.""" 

58 

59 namespace: str 

60 name: str 

61 #: ``None`` for always; otherwise the cdk.json feature that gates it. 

62 feature: str | None = None 

63 

64 

65LEAF_CERTIFICATES: tuple[LeafCertificate, ...] = ( 

66 LeafCertificate("gco-system", "health-monitor-tls"), 

67 LeafCertificate("gco-system", "manifest-processor-tls"), 

68 LeafCertificate("gco-system", "inference-proxy-tls"), 

69 LeafCertificate("gco-system", "inference-monitor-tls"), 

70 LeafCertificate("gco-system", "cost-monitor-tls", "cost_monitoring"), 

71 LeafCertificate("gco-inference", "gco-inference-tls"), 

72 LeafCertificate("monitoring", "opencost-tls", "cost_monitoring"), 

73 LeafCertificate("monitoring", "grafana-tls", "cluster_observability"), 

74 LeafCertificate("monitoring", "gco-monitoring-trust", "cluster_observability"), 

75 LeafCertificate("monitoring", "mlflow-tls", "mlflow"), 

76 LeafCertificate("trust-manager", "gco-internal-ca-source", "mlflow"), 

77) 

78 

79 

80class InternalPkiValidationError(RuntimeError): 

81 """The live cluster's certificates do not chain to the GCO internal CA.""" 

82 

83 

84def cluster_observability_configured(ctx: RunContext) -> bool: 

85 """Return whether cdk.json keeps cluster observability on (default on).""" 

86 block = ctx.cdk_context.get("cluster_observability") 

87 if isinstance(block, dict) and "enabled" in block: 

88 return bool(block["enabled"]) 

89 return True 

90 

91 

92def mlflow_configured(ctx: RunContext) -> bool: 

93 """Return whether cdk.json deploys MLflow: its own toggle (default on) and observability.""" 

94 if not cluster_observability_configured(ctx): 

95 return False 

96 block = ctx.cdk_context.get("cluster_observability") 

97 mlflow = block.get("mlflow") if isinstance(block, dict) else None 

98 if isinstance(mlflow, dict) and "enabled" in mlflow: 

99 return bool(mlflow["enabled"]) 

100 return True 

101 

102 

103def expected_leaf_certificates( 

104 ctx: RunContext, 

105) -> tuple[list[LeafCertificate], dict[str, str]]: 

106 """Return the leaves this configuration deploys and the skipped ones with reasons.""" 

107 enabled = { 

108 "cost_monitoring": _cost_monitoring_configured(ctx), 

109 "cluster_observability": cluster_observability_configured(ctx), 

110 "mlflow": mlflow_configured(ctx), 

111 } 

112 expected: list[LeafCertificate] = [] 

113 skipped: dict[str, str] = {} 

114 for leaf in LEAF_CERTIFICATES: 

115 if leaf.feature is None or enabled[leaf.feature]: 

116 expected.append(leaf) 

117 else: 

118 skipped[f"{leaf.namespace}/{leaf.name}"] = f"{leaf.feature} is disabled in cdk.json" 

119 return expected, skipped 

120 

121 

122def _dict(value: Any) -> dict[str, Any]: 

123 return value if isinstance(value, dict) else {} 

124 

125 

126def _ready(obj: dict[str, Any]) -> bool: 

127 return any( 

128 _dict(entry).get("type") == "Ready" and _dict(entry).get("status") == "True" 

129 for entry in _dict(obj.get("status")).get("conditions") or [] 

130 ) 

131 

132 

133def _issuer_ref(obj: dict[str, Any]) -> dict[str, Any]: 

134 ref = _dict(_dict(obj.get("spec")).get("issuerRef")) 

135 return { 

136 "name": ref.get("name"), 

137 # cert-manager reads an omitted kind as a namespaced Issuer. 

138 "kind": ref.get("kind") or "Issuer", 

139 "group": ref.get("group") or "cert-manager.io", 

140 } 

141 

142 

143def _cluster_issuer_ref(ref: dict[str, Any], name: str) -> bool: 

144 return ref == {"name": name, "kind": "ClusterIssuer", "group": "cert-manager.io"} 

145 

146 

147def _snapshot( 

148 ctx: RunContext, 

149 kubectl: KubectlRunner, 

150 record: dict[str, Any], 

151 leaves: list[LeafCertificate], 

152) -> dict[str, Any]: 

153 timeout = float(ctx.settings.command_timeout_seconds) 

154 violations: list[str] = [] 

155 pending: list[str] = [] 

156 

157 issuer = kubectl_json( 

158 kubectl, record, "get", _CLUSTER_ISSUERS, INTERNAL_CA_ISSUER, timeout=timeout 

159 ) 

160 issuer_ready = issuer is not None and _ready(issuer) 

161 if issuer is None: 

162 violations.append(f"ClusterIssuer {INTERNAL_CA_ISSUER} is missing") 

163 elif not issuer_ready: 

164 pending.append(f"ClusterIssuer {INTERNAL_CA_ISSUER} is not Ready") 

165 

166 ca = kubectl_json( 

167 kubectl, 

168 record, 

169 "get", 

170 _CERTIFICATES, 

171 CA_CERTIFICATE_NAME, 

172 "--namespace", 

173 CA_CERTIFICATE_NAMESPACE, 

174 timeout=timeout, 

175 ) 

176 ca_label = f"Certificate {CA_CERTIFICATE_NAMESPACE}/{CA_CERTIFICATE_NAME}" 

177 ca_evidence: dict[str, Any] = {"exists": ca is not None} 

178 if ca is None: 

179 violations.append(f"{ca_label} is missing") 

180 else: 

181 ref = _issuer_ref(ca) 

182 ca_evidence.update( 

183 { 

184 "ready": _ready(ca), 

185 "is_ca": _dict(ca.get("spec")).get("isCA") is True, 

186 "issuer": ref["name"], 

187 "issuer_kind": ref["kind"], 

188 } 

189 ) 

190 if not _cluster_issuer_ref(ref, BOOTSTRAP_ISSUER): 

191 violations.append(f"{ca_label} is not issued by ClusterIssuer {BOOTSTRAP_ISSUER}") 

192 if not ca_evidence["is_ca"]: 

193 violations.append(f"{ca_label} is not a CA certificate") 

194 if not ca_evidence["ready"]: 

195 pending.append(f"{ca_label} is not Ready") 

196 

197 certificates: dict[str, Any] = {} 

198 for leaf in leaves: 

199 label = f"{leaf.namespace}/{leaf.name}" 

200 certificate = kubectl_json( 

201 kubectl, 

202 record, 

203 "get", 

204 _CERTIFICATES, 

205 leaf.name, 

206 "--namespace", 

207 leaf.namespace, 

208 timeout=timeout, 

209 ) 

210 if certificate is None: 

211 certificates[label] = {"exists": False} 

212 violations.append(f"Certificate {label} is missing") 

213 continue 

214 ref = _issuer_ref(certificate) 

215 ready = _ready(certificate) 

216 certificates[label] = { 

217 "exists": True, 

218 "ready": ready, 

219 "issuer": ref["name"], 

220 "issuer_kind": ref["kind"], 

221 } 

222 if not _cluster_issuer_ref(ref, INTERNAL_CA_ISSUER): 

223 violations.append( 

224 f"Certificate {label} is issued by {ref['kind']} {ref['name']!r}, " 

225 f"not ClusterIssuer {INTERNAL_CA_ISSUER}" 

226 ) 

227 elif not ready: 

228 pending.append(f"Certificate {label} is not Ready") 

229 

230 legacy = kubectl_json( 

231 kubectl, 

232 record, 

233 "get", 

234 _ISSUERS, 

235 LEGACY_ISSUER_NAME, 

236 "--namespace", 

237 LEGACY_ISSUER_NAMESPACE, 

238 timeout=timeout, 

239 ) 

240 if legacy is not None: 

241 violations.append( 

242 f"retired Issuer {LEGACY_ISSUER_NAMESPACE}/{LEGACY_ISSUER_NAME} still exists" 

243 ) 

244 return { 

245 "cluster_issuer": { 

246 "name": INTERNAL_CA_ISSUER, 

247 "exists": issuer is not None, 

248 "ready": issuer_ready, 

249 }, 

250 "ca_certificate": ca_evidence, 

251 "leaf_certificates": certificates, 

252 "legacy_issuer_present": legacy is not None, 

253 "violations": violations, 

254 "pending": pending, 

255 } 

256 

257 

258def verify_internal_pki(ctx: RunContext, region: str, kubectl: KubectlRunner) -> dict[str, Any]: 

259 """Poll one Region until the internal CA and every expected leaf are Ready. 

260 

261 Returns the settled snapshot; raises ``InternalPkiValidationError`` on the 

262 first snapshot with a violation, or when a Certificate is still not Ready 

263 at the deadline. Every observation is checkpointed under 

264 ``internal_pki.<region>`` first. 

265 """ 

266 leaves, skipped = expected_leaf_certificates(ctx) 

267 with ctx.state_lock: 

268 record: dict[str, Any] = ctx.checkpoint.state.setdefault("internal_pki", {}).setdefault( 

269 region, {} 

270 ) 

271 deadline = time.monotonic() + _READY_TIMEOUT_SECONDS 

272 while True: 

273 snapshot = _snapshot(ctx, kubectl, record, leaves) 

274 snapshot["skipped_certificates"] = skipped 

275 with ctx.state_lock: 

276 record["last_snapshot"] = snapshot 

277 ctx.persist() 

278 if snapshot["violations"]: 

279 raise InternalPkiValidationError( 

280 f"internal PKI in {region} is broken: " + "; ".join(snapshot["violations"]) 

281 ) 

282 if not snapshot["pending"]: 

283 return snapshot 

284 if time.monotonic() >= deadline: 

285 raise InternalPkiValidationError( 

286 f"internal PKI in {region} did not become Ready within " 

287 f"{_READY_TIMEOUT_SECONDS}s: " + "; ".join(snapshot["pending"]) 

288 ) 

289 time.sleep(ctx.settings.poll_interval_seconds)