Argo
Run runtz scans with Argo Workflows and Argo CD.
Argo
runtz fits Argo naturally: the CLI image entrypoint is the runtz binary, so
a workflow step is just the image plus args — and the container scan pulls
image layers straight from the registry, so no Docker daemon or privileged
sidecar is needed inside the cluster.
Store the credentials
Create a Secret in the namespace where the workflows run (for example
argo):
kubectl create secret generic runtz-credentials -n argo \
--from-literal=RUNTZ_ENDPOINT=https://engine.runtz.dev \
--from-literal=RUNTZ_TOKEN=rtz_live_...Every example below injects it with envFrom, and the CLI reads
RUNTZ_ENDPOINT and RUNTZ_TOKEN from the environment.
Scan the repository (Argo Workflows)
A single parametrized template runs both scans; the checkout comes in as an Argo git artifact:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: runtz-scans-
spec:
entrypoint: security-scans
templates:
- name: security-scans
dag:
tasks:
- name: sca
template: runtz-scan
arguments:
parameters: [{ name: command, value: sca }]
- name: sast
template: runtz-scan
arguments:
parameters: [{ name: command, value: sast }]
- name: runtz-scan
inputs:
parameters:
- name: command
artifacts:
- name: source
path: /src
git:
repo: https://github.com/my-org/my-app.git
revision: main
container:
image: runtzdev/runtz-cli:latest
args:
- "{{inputs.parameters.command}}"
- /src
- --project
- my-app
- --source
- https://github.com/my-org/my-app
envFrom:
- secretRef:
name: runtz-credentialsFor private repositories, add usernameSecret/passwordSecret (or
sshPrivateKeySecret) to the git artifact.
Scan the built image
Add a task after the image is pushed — the scanner reads the layers from the registry directly:
- name: runtz-container
container:
image: runtzdev/runtz-cli:latest
args: ["container", "my-org/my-app:latest"]
envFrom:
- secretRef:
name: runtz-credentialsThe registry pull is anonymous, so this works for public images.
Scheduled scans
A CronWorkflow keeps the platform dashboards fresh even without new
commits — new CVEs are published against existing versions every day:
apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
name: runtz-nightly
spec:
schedule: "0 3 * * *"
workflowSpec:
entrypoint: container-scan
templates:
- name: container-scan
container:
image: runtzdev/runtz-cli:latest
args: ["container", "my-org/my-app:latest"]
envFrom:
- secretRef:
name: runtz-credentialsPost-deploy cluster scan (Argo CD)
An Argo CD PostSync hook runs runtz k8s against the live cluster after
every successful sync, so each deploy is followed by a posture scan.
The live-cluster scanner shells out to kubectl, which the minimal CLI image
does not ship — an init container copies the binary in. Add these manifests to
the Argo CD application:
apiVersion: v1
kind: ServiceAccount
metadata:
name: runtz-scan
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: runtz-scan
rules:
- apiGroups: [""]
resources: [pods, services]
verbs: [get, list]
- apiGroups: [apps]
resources: [deployments, daemonsets, statefulsets]
verbs: [get, list]
- apiGroups: [batch]
resources: [jobs, cronjobs]
verbs: [get, list]
- apiGroups: [networking.k8s.io]
resources: [ingresses]
verbs: [get, list]
- apiGroups: [rbac.authorization.k8s.io]
resources: [roles, rolebindings, clusterroles, clusterrolebindings]
verbs: [get, list]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: runtz-scan
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: runtz-scan
subjects:
- kind: ServiceAccount
name: runtz-scan
namespace: my-app
---
apiVersion: batch/v1
kind: Job
metadata:
name: runtz-k8s-scan
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
serviceAccountName: runtz-scan
restartPolicy: Never
initContainers:
- name: kubectl
image: bitnami/kubectl:1.31
command: ["cp", "/opt/bitnami/kubectl/bin/kubectl", "/tools/kubectl"]
volumeMounts:
- name: tools
mountPath: /tools
containers:
- name: runtz
image: runtzdev/runtz-cli:latest
args:
- k8s
- --kubectl
- /tools/kubectl
- --target
- production
envFrom:
- secretRef:
name: runtz-credentials
volumeMounts:
- name: tools
mountPath: /tools
volumes:
- name: tools
emptyDir: {}Inside the cluster, kubectl authenticates automatically with the pod's
ServiceAccount — the ClusterRole grants read access to exactly the resources
the scanner inspects. hook-delete-policy: HookSucceeded removes the Job
after a successful scan.
To scan only the application's namespace instead of the whole cluster, add
--namespace my-app (and a Role/RoleBinding is then enough, except for
the clusterroles/clusterrolebindings checks).
Notes
- Pin a release tag (
runtzdev/runtz-cli:v0.4.0) for reproducible workflows. - Scans exit non-zero only on execution errors, so a scan with findings does not fail the workflow or the Argo CD sync — results are reviewed in the platform.
- Kubernetes manifests in the repository can also be posture-checked without
any cluster access:
runtz k8s /src/deployin a workflow step.