This is a TLS/SSL security scanner that runs as a Kubernetes Job in OpenShift/CRC clusters. It:
- Scans pods in the cluster for open ports using
nmap - Detects TLS/SSL cipher suites and protocols
- Identifies processes listening on ports using
lsof - Outputs results in JSON, CSV, and log formats
Critical Context:
- Scanner runs inside the cluster as a privileged pod
- Container image size: ~1.4 GB
- CRC environment has limited disk space (~4-5GB available)
- Artifacts are stored in ephemeral storage and must be copied before pod exits
crc cleanup # DESTROYS entire CRC VM, all data, all configs
crc delete # Removes the CRC instance completely
crc stop --force # Force stops CRC (may corrupt data)oc delete namespace <name> # Deletes entire namespace and all resources
oc delete job --all # Deletes all jobs in namespace
oc adm prune images --confirm # May delete images still in use
podman system prune -af # Deletes all local images/containersALWAYS ask the user before running any of these commands!
Symptoms:
- Pods show status
EvictedorFailed - Pod description shows: "The node was low on resource: ephemeral-storage"
- Available disk space < 5GB
Safe Resolution Steps (in order):
-
Delete failed/evicted pods (safest):
oc delete pods -n default -l job-name=tls-scanner-job --field-selector=status.phase=Failed oc delete pods --field-selector=status.phase=Evicted --all-namespaces
-
Delete completed scanner jobs (keeps current one):
oc delete job tls-scanner-job -n default
-
Check disk space on node (read-only):
oc get nodes oc describe node/crc | grep -A 5 "Allocated resources"
-
If desperate, restart CRC (last resort):
crc stop crc start
This is much better than
crc cleanupas it preserves the VM and configuration.
DO NOT:
- Run
crc cleanup(destroys everything) - Run
crc delete(destroys everything) - Try to SSH into CRC node to manually clean disk (risky)
tls-scanner/
βββ deploy.sh # Main deployment script
βββ scanner-job.yaml.template # Kubernetes Job template
βββ Dockerfile.local # Container image definition
βββ cmd/scanner/ # Main Go application
βββ pkg/ # Scanner logic packages
βββ artifacts/ # Output directory (created by deploy.sh)
βββ results.json # JSON scan results
βββ results.csv # CSV scan results
βββ scan.log # Detailed scan logs
./deploy.sh --local full-deployThis performs:
- Build: Compiles Go binary and builds ~1.4GB container image
- Push: Pushes to OpenShift internal registry
- Deploy: Creates Kubernetes Job with scanner pod
- Wait: Monitors for "Scanner finished" message
- Copy: Copies artifacts from pod (during 300-second sleep window)
- Complete: Waits for job to complete
Scanner flags (in scanner-job.yaml.template):
--all-pods: Scan all pods in cluster (default behavior)--namespace <name>: Scan only specific namespace--limit-ips <N>: Limit scan to first N IPs (use for testing!)--json-file <path>: Output JSON results--csv-file <path>: Output CSV results--log-file <path>: Output detailed logs
Deployment modes:
--local: Use CRC internal registry (most common)- Without
--local: Use external registry (requires SCANNER_IMAGE env var)
To validate the scanner correctly detects TLS configuration changes on the API Server:
./deploy.sh --local test-tls-config- Saves current API Server TLS configuration
- Applies restrictive TLS 1.2 config with single cipher (ECDHE-RSA-AES128-GCM-SHA256)
- Waits for cluster to stabilize (~10 minutes by default)
- Runs scanner against API server pods (openshift-kube-apiserver, openshift-apiserver)
- Verifies scan detects TLS 1.2 and the configured cipher
- Restores original configuration
- Reports pass/fail with detailed results
Note: TLS 1.3 cipher suites are not configurable per the TLS 1.3 specification, so the test uses TLS 1.2 which allows cipher customization.
| Variable | Default | Description |
|---|---|---|
TLS_TEST_TIMEOUT |
600 | Timeout in seconds for cluster stabilization |
# Run with default settings (scans openshift-kube-apiserver,openshift-apiserver)
./deploy.sh --local test-tls-config
# Run with custom timeout (15 minutes)
TLS_TEST_TIMEOUT=900 ./deploy.sh --local test-tls-config
# Test a specific namespace only
./deploy.sh --local -n openshift-kube-apiserver test-tls-config
# Test multiple specific namespaces
./deploy.sh --local -n "openshift-apiserver,openshift-oauth-apiserver" test-tls-configResults are saved to ./tls-test-results/custom-tls-scan/:
results.json- Full JSON scan resultsresults.csv- CSV format resultsscan.log- Detailed scan logs
The test passes when the scanner correctly detects:
- TLS Version: TLSv1.2
- Cipher: ECDHE-RSA-AES128-GCM-SHA256 (or IANA equivalent: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
The test fails if:
- Unexpected TLS versions are detected
- Additional/unexpected ciphers are detected
- No TLS information is detected at all
- The cluster doesn't stabilize within the timeout
- This test modifies live cluster configuration and requires cluster-admin privileges
- The test includes automatic restoration of original config on failure or interruption
- Use
Ctrl+Cto abort - original config will still be restored
# Find the scanner pod
oc get pods -n default -l job-name=tls-scanner-job
# View logs (includes full nmap XML output)
oc logs pod/<pod-name> -n default
# Follow logs in real-time
oc logs -f job/tls-scanner-job -n defaultWhat you'll see in logs:
- Full nmap command executed
- Complete XML output from nmap
- TLS cipher suites discovered
- Process names from lsof
- Progress through all IPs
# After successful deployment:
ls -lh ./artifacts/
cat ./artifacts/results.json # JSON format
cat ./artifacts/results.csv # CSV format
cat ./artifacts/scan.log # Same as pod logsNote: Artifacts only available if:
- Scan completed successfully
- Artifacts were copied during the 300-second sleep window
- Pod didn't get evicted due to disk space
Symptoms:
Status: Failed
Reason: Evicted
Message: The node was low on resource: ephemeral-storage
Solution:
- Delete old failed pods (see "Safe Cleanup Procedures")
- Reduce scan scope: Add
--limit-ips 5to scanner-job.yaml.template - Don't run full scans on disk-constrained CRC
Symptoms:
error: cannot exec into a container in a completed pod; current phase is Succeeded
Root Cause:
- Pod already exited;
oc cprequires running pod - Artifacts stored in emptyDir volume (deleted when pod terminates)
Solution:
- This should NOT happen anymore - deploy.sh now copies during sleep window
- If it does happen, artifacts are lost but logs are still available via
oc logs
Symptoms:
Error: tag default-route-openshift-image-registry.apps-crc.testing//tls-scanner:latest: invalid reference format
Root Cause:
- Double slash
//in image name - Registry namespace not set correctly
Solution:
- Check NAMESPACE environment variable
- Ensure
oc projectshows correct namespace - Verify
--localflag is used with deploy.sh
Normal Behavior:
- Each IP takes 15-90 seconds to scan (nmap is thorough)
- Full cluster scan (70 pods) can take 20+ minutes
- Progress visible in logs
If truly stuck:
- Check pod logs:
oc logs -f job/tls-scanner-job - Check pod status:
oc describe pod/<pod-name> - May be blocked by network policies or firewalls
crc status
crc console --credentials # Get admin passwordoc get jobs -n default
oc get pods -n default -l job-name=tls-scanner-job
oc describe job/tls-scanner-job -n default
oc logs job/tls-scanner-job -n defaultoc get pod/<pod-name> -o yaml
oc describe pod/<pod-name>
oc logs pod/<pod-name> --previous # View logs from crashed containeroc get imagestream -n default
oc describe imagestream/tls-scanner -n defaultoc get nodes
oc describe node/crc
oc adm top nodes # Requires metrics server# This takes ~15-20 minutes
crc setup
crc start
# Configure oc client
eval $(crc oc-env)
oc login -u kubeadmin https://api.crc.testing:6443
# Redeploy scanner
cd ~/tls-scanner
./deploy.sh --local full-deployNote: All previous scan data is LOST. Backups are in ./artifacts/ if copied before destruction.
# Get detailed information
oc describe pod/<pod-name>
oc logs pod/<pod-name>
# Common fixes:
# 1. Delete and retry
oc delete job/tls-scanner-job
./deploy.sh --local deploy
# 2. Clean up disk space (see Safe Cleanup Procedures)
# 3. Reduce scan scope
# Edit scanner-job.yaml.template and add: --limit-ips 5The logs contain all scan data!
# Get the pod name
POD=$(oc get pods -n default -l job-name=tls-scanner-job -o jsonpath='{.items[0].metadata.name}')
# Save logs to file
oc logs pod/$POD -n default > scan-output.log
# Logs include:
# - Full nmap XML output for each IP
# - TLS cipher suites
# - Process information
# - Everything needed for analysis- Always check pod logs first - they contain full scan output
- Use
--limit-ipsfor testing - saves time and disk space - Ask before cleanup commands - especially anything with
delete,prune,cleanup - Monitor disk space - CRC has limited resources
- Copy artifacts during sleep window - deploy.sh handles this now
- Read error messages carefully - eviction vs failure have different solutions
- Prefer
oc logsover artifact files - logs are always available
You'll see output like:
Running command: /usr/bin/nmap -Pn -sV --script ssl-enum-ciphers -p 8443 -oX - 10.217.0.10
Command output: <?xml version="1.0" encoding="UTF-8"?>
<nmaprun ...>
<host>
<ports>
<port protocol="tcp" portid="8443">
<service name="https-alt" tunnel="ssl"/>
<script id="ssl-enum-ciphers">
<table key="TLSv1.2">
<table key="ciphers">
<table>
<elem key="name">TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256</elem>
<elem key="strength">A</elem>
</table>
</table>
</table>
</script>
</port>
</ports>
</host>
</nmaprun>
This shows:
- Port: 8443
- Protocol: TLS/SSL over HTTPS
- Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- Strength: A (strong)
-
β Running
crc cleanupto fix disk space (DESTROYS EVERYTHING) β Delete failed pods instead -
β Trying to
oc cpfrom completed pods β Check logs withoc logsinstead -
β Assuming artifacts are the only data source β Pod logs contain full scan output
-
β Running full scans without checking disk space β Use
--limit-ipsfor testing -
β Force-stopping or deleting running scans prematurely β Let scans complete; they take 15-90s per IP
- Nmap SSL Script: https://nmap.org/nsedoc/scripts/ssl-enum-ciphers.html
- OpenShift Jobs: https://docs.openshift.com/container-platform/latest/nodes/jobs/nodes-nodes-jobs.html
- CRC Documentation: https://crc.dev/crc/
- TLS Cipher Suites: https://ciphersuite.info/
| Situation | Command | Notes |
|---|---|---|
| View scan progress | oc logs -f job/tls-scanner-job |
Shows real-time nmap output |
| Pod evicted | Delete failed pods, free disk space | See "Safe Cleanup Procedures" |
| Check artifacts | ls -lh ./artifacts/ |
Only works if copy succeeded |
| Find pod name | oc get pods -l job-name=tls-scanner-job |
Look for scanner pods |
| Redeploy scanner | ./deploy.sh --local full-deploy |
Full build + deploy |
| Quick redeploy | ./deploy.sh --local deploy |
Skip build if image unchanged |
| Test with small scan | Edit template, add --limit-ips 5 |
Faster, uses less space |
| CRC not responding | crc stop && crc start |
NOT crc cleanup! |
| Need admin access | crc console --credentials |
Get kubeadmin password |
Remember: When in doubt, check the logs first. The nmap scan output is always in oc logs, even if artifact copying fails!