Kubernetes CronJob monitoring
Monitor your Kubernetes CronJobs without changing your job images. A Helm chart ships a shared Secret of ping keys plus template macros you paste into your own CronJob spec — an init container injects the agent into a shared emptyDir and the main container runs through it. No operator. No CRD. No code changes to your existing jobs.
1. Create a Kubernetes monitor
In the dashboard, click New monitor and pick the Kubernetes CronJob tile. The post-create panel will generate the exact helm installcommand below with your monitor's UUID embedded — copy it straight from there.
2. Install the chart
helm install crond-agent \
oci://ghcr.io/platops-security/crond-io/charts/crond-agent \
--version 0.2.0 \
--namespace my-jobs --create-namespace \
--set pingKeys.PING_KEY_BACKUP=<your-uuid>Each entry under pingKeys becomes one key in the chart-owned Secret <release>-pingkeys. You can install per-namespace and pass multiple keys for multiple monitors.
3. Wrap your CronJob
The chart provides a Helm template macro you call from inside your own CronJob spec. Most users embed this in their own umbrella Helm chart that depends on crond-agent:
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-backup
namespace: my-jobs # same namespace as the chart install
spec:
schedule: "0 2 * * *" # must match your crond.io monitor schedule
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
{{- include "crond-agent.wrap" (dict
"context" $
"envKey" "PING_KEY_BACKUP"
"image" "myco/backup:1.0"
"command" (list "/opt/backup.sh"))
| nindent 10 }}The macro expands to: an emptyDir volume, an init container that copies the agent binary in via its own install subcommand, and a job container running crond-agent exec around your original command. Stdout still flows through to kubectl logs.
4. Verify
Apply the CronJob, then trigger a manual job:
kubectl apply -f your-cronjob.yaml
kubectl create job --from=cronjob/nightly-backup test-1 -n my-jobs
kubectl logs job/test-1 -n my-jobs -fWithin ~30 seconds the monitor should flip from new to up with the first ping recorded.
Privacy: redact or drop captured output
By default the agent ships the wrapped command's stdout/stderr in the ping payload alongside the exit code and duration. Two chart values control that, applied to the wrapped job container only:
# values.yaml override:
agent:
captureOutput: true # default
redactPatterns:
- 'Bearer [A-Za-z0-9._-]+'
- 'postgres://[^@]+@[^/[:space:]]+'When values diverge from defaults the chart sets CROND_CAPTURE_OUTPUT / CROND_REDACT_PATTERNS on the job container. At defaults the chart emits zero CROND_* env vars — clean opt-in.
The passthrough to kubectl logs stays raw — redaction only filters the cross-network payload. See Security for the threat model.
Alternative: pre-baked image
If you control your job image, you can bake the agent in and skip the init container entirely:
FROM ghcr.io/platops-security/crond-io/agent:0.2.0 AS agent
FROM alpine:3.20
COPY --from=agent /crond-agent /usr/local/bin/crond-agent
COPY backup.sh /opt/backup.sh
ENTRYPOINT ["/opt/backup.sh"]Your CronJob then invokes crond-agent exec directly. The chart still owns the Secret; you only need its envFromSecret macro.
The agent image manifest is multi-arch (amd64+arm64) and signed with a keyless cosign certificate bound to the release workflow — see Security for the verification command.
Limitations (V1)
- Manual UUID registration — no auto-discovery of CronJobs.
- No mutating admission webhook — wrap each CronJob explicitly.
- CronJob schedule and crond.io monitor schedule are independent — set both to the same expression and grace window.
- K8s
Job(one-shot) is out of scope —CronJobonly.
Tracked for V2: a mutating webhook for opt-in auto-injection, an operator/CRD for declarative monitor management, and AWS / GCP / Azure scheduler support.
Engineer reference
Full chart values, troubleshooting matrix, and pre-baked image recipe live in the in-repo chart README on GitHub: