TES Implementations
Task Execution Service (or TES) is a GA4GH standard for executing tasks. Details about its schema can be found here.
There are a few implementations of the TES standard, including:
-
TES-K: A Kubernetes-native TES implementation where each job runs as a Kubernetes pod. This makes it straightforward to enforce pod-level security policies via Kubernetes admission controller. However, TESK has the operational overhead of running a Kubernetes cluster. The director-wfs from Swansea University Medical School can help mitigate this by providing a full-stack deployment of TESK on KIND (Kubernetes IN Docker), with hardening enforced by Gatekeeper admission control, runtime detection via Falco, network policies, monitoring, and ingress management all active by default. A single bootstrap script stands up the whole cluster on macOS or Ubuntu.
-
Funnel is a Go implementation of TES that translates task messages directly into
docker runcommands. It comprises a server, worker, and a collection of compute, storage, and database backends, making it a TES compatible execution backend. Given a task description, Funnel will locate a worker to carry out the task, download inputs, launch a number of (Docker) containers, upload outputs, record logs, and monitor the entire process.
Below is a comparison between Funnel (default Docker backend) and TESK as deployed via director-wfs. TRE operators considering TESK for production should be aware that director-wfs is one possible deployment pattern - TESK itself supports any Kubernetes cluster. This comparison is best understood as a demonstration of what a security-conscious TESK deployment can look like in practice.
Comparison between TES-K and Funnel
Below is a comparison between TES-K and Funnel. The purpose of this comparison is to help TRE operators decide which implementation to use for their production TRE.
| Category | Funnel (default Docker backend) | TESK via director-wfs |
|---|---|---|
| Implementation language | Go | Java (tesk-api) + Python (tesk-core) |
| Underlying runtime | Docker (direct docker run) | Kubernetes pods (via KIND on a single host) |
| Deployment complexity | Low — single binary, runs anywhere Docker is available | Higher — full KIND cluster, but bootstrapped via a single script |
| Horizontal scalability | Yes (also supports K8s backend) | No — director-wfs targets single-server deployments only |
| Host OS support | Any Docker host | macOS or Ubuntu (per director-wfs bootstrap) |
| Container root filesystem | Read-only, with a writable /tmp provided by Funnel | Read-only, enforced by Gatekeeper admission control |
/tmp writability | Writable (Funnel mounts a host dir), so diagnostic socket creates fine, for example. | Read-only — can break runtimes that write to /tmp at startup. So DOTNET_EnableDiagnostics=0 needs to be set in the task payload, for example. |
| Container user | Whatever the image specifies (usually root) | Non-root by default, enforced by Gatekeeper |
| Linux capabilities | Docker’s full default set granted | All dropped by default, enforced by Gatekeeper |
| Privileged containers | Possible if worker config permits | Rejected by Gatekeeper before they run |
| Host filesystem access | Whatever volumes the worker is configured to mount | Restricted to a single storage path, enforced by Gatekeeper |
| Host Docker socket exposure | Required by the Funnel worker (root-equivalent reach on host) | Not used |
| Security enforcement model | Relies entirely on correct operator configuration | Enforced at cluster level — insecure pod specs are rejected |
| Hardening defaults | None — --user, --cap-drop, --security-opt, user-namespace flags absent by default | Hardened by default via Gatekeeper policies |
| Runtime threat monitoring | None by default | Falco watches container activity at runtime |
| Network policies | None built-in | Active by default |
| Admission control | None | Gatekeeper (OPA) |
| Container ENTRYPOINT behaviour | Honoured — command passed as args to image ENTRYPOINT. This is diverging from spec of TES schema. | Ignored — command[0] is exec’d directly; full command must be in the task payload, per the TES/argv spec |
| Migration impact | Tolerant of images that rely on ENTRYPOINT | Requires TES payloads to include program name as command[0] |
| Logging | All logs in one place (simple) | Per-pod/job logs via kubectl |
| Ingress / TLS | Operator-managed | Managed by director-wfs; SSL can be disabled for private networks |
| Storage backend (tested) | Operator-defined | MinIO (S3-compatible), configured at install time |
| Operator burden | High — all hardening must be configured deliberately per deployment | Low — secure defaults enforced; operator configures exceptions, not rules |