Skip to content

Commit d887e80

Browse files
committed
Add k8s test: init container can reach HTTPS endpoints (CA trust store)
Companion to DataDog/libdatadog-build#235 (init images busybox -> scratch + dash/toybox/curl). Asserts the init image can complete a TLS-verified HTTPS request via a throwaway probe pod, guarding the CA trust store against regression on the base-image change.
1 parent c82fffe commit d887e80

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

tests/k8s_lib_injection/test_k8s_lib_injection.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from utils import scenarios, features, context, bug, logger
2-
from tests.k8s_lib_injection.utils import get_dev_agent_traces, get_cluster_info
2+
from tests.k8s_lib_injection.utils import get_dev_agent_traces, get_cluster_info, run_https_probe_pod
33
from utils.onboarding.weblog_interface import make_get_request, warmup_weblog
44
from utils.onboarding.backend_interface import wait_backend_trace_id
55
from utils.onboarding.wait_for_tcp_port import wait_for_port
@@ -19,6 +19,20 @@ def test_k8s_lib_injection(self):
1919
traces_json = get_dev_agent_traces(get_cluster_info())
2020
assert len(traces_json) > 0, "No traces found"
2121

22+
def test_k8s_init_container_https_egress(self):
23+
"""The init image must be able to complete a TLS-verified HTTPS request.
24+
25+
The init container ships a CA trust store so admission-controller wrappers that dial
26+
HTTPS from inside it (e.g. bank-vaults' vault-env) keep working. This runs a throwaway
27+
pod from the init image doing `curl -fsS https://...` (verification on) and asserts it
28+
succeeds; a missing or broken cert store makes curl exit non-zero.
29+
"""
30+
image = context.scenario.test_weblog.library_init_image
31+
phase, logs = run_https_probe_pod(get_cluster_info(), image, "https://app.datadoghq.com")
32+
if phase != "Succeeded":
33+
logger.error(f"[HTTPS probe] init image {image} failed HTTPS egress; pod logs:\n{logs}")
34+
assert phase == "Succeeded", f"init image could not complete a verified HTTPS request (pod phase: {phase})"
35+
2236

2337
@features.k8s_admission_controller
2438
@scenarios.k8s_lib_injection_operator

tests/k8s_lib_injection/utils.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import time
22

33
import requests
4+
from kubernetes import client
5+
46
from utils import logger, context
57
from utils.k8s_lib_injection.k8s_cluster_provider import K8sClusterInfo
68
from utils._context._scenarios.k8s_lib_injection import K8sScenarioWithClusterProvider
@@ -24,3 +26,51 @@ def get_cluster_info() -> K8sClusterInfo:
2426
assert isinstance(context.scenario, K8sScenarioWithClusterProvider)
2527

2628
return context.scenario.k8s_cluster_provider.get_cluster_info()
29+
30+
31+
def run_https_probe_pod(
32+
k8s_cluster_info: K8sClusterInfo, image: str, url: str, *, namespace: str = "default", timeout: int = 120
33+
) -> tuple[str | None, str]:
34+
"""Run a one-shot pod from `image` performing a TLS-verified HTTPS GET to `url`.
35+
36+
Uses the image's curl with verification on (no -k), so a missing or invalid CA trust
37+
store makes curl exit non-zero. Returns (pod_phase, logs); phase "Succeeded" means the
38+
image completed a verified HTTPS request. The probe pod is always cleaned up.
39+
"""
40+
api = k8s_cluster_info.core_v1_api()
41+
name = "init-https-probe"
42+
pod = client.V1Pod(
43+
metadata=client.V1ObjectMeta(name=name),
44+
spec=client.V1PodSpec(
45+
restart_policy="Never",
46+
containers=[
47+
client.V1Container(
48+
name="probe",
49+
image=image,
50+
image_pull_policy="Always",
51+
command=["/usr/bin/curl", "-fsS", "-o", "/dev/null", "--max-time", "15", url],
52+
)
53+
],
54+
),
55+
)
56+
logger.info(f"[HTTPS probe] running {image} -> curl {url}")
57+
api.create_namespaced_pod(namespace=namespace, body=pod)
58+
try:
59+
phase: str | None = None
60+
deadline = time.time() + timeout
61+
while time.time() < deadline:
62+
phase = api.read_namespaced_pod_status(name=name, namespace=namespace).status.phase
63+
if phase in ("Succeeded", "Failed"):
64+
break
65+
time.sleep(2)
66+
logs = ""
67+
try:
68+
logs = api.read_namespaced_pod_log(name=name, namespace=namespace)
69+
except Exception as e: # noqa: BLE001
70+
logger.warning(f"[HTTPS probe] could not read probe pod logs: {e}")
71+
return phase, logs
72+
finally:
73+
try:
74+
api.delete_namespaced_pod(name=name, namespace=namespace)
75+
except Exception as e: # noqa: BLE001
76+
logger.warning(f"[HTTPS probe] could not delete probe pod: {e}")

0 commit comments

Comments
 (0)