chainloop
chainloop copied to clipboard
Research how to autodetect Tekton pipelines as runners
Chainloop provides automatic detection of CI/CD environments to ensure attestations are created in the correct context and to capture relevant execution metadata. This capability, known as runner context, is essential for enforcing where attestations can be executed and for maintaining comprehensive audit trails.
The autodetection process is implemented through the DiscoverRunner function. The logic is straightforward but robust:
- Environment Probing: The system iterates through all registered runner factories, instantiating each one and calling its CheckEnv() method. This method performs "duck-typing" checks by looking for specific environment variables that uniquely identify each CI/CD platform.
- Conflict Resolution: If multiple runners are detected simultaneously (an incongruent state), or if no runner is detected, the system defaults to a generic runner type. This ensures the attestation process can always proceed, even in unusual or local development environments.
- Single Detection: When exactly one runner is detected, that runner instance is returned and used for the attestation process.
Supported Platforms
Chainloop currently supports autodetection for seven CI/CD platforms:
- GitHub Actions - Detects GitHub-specific environment variables and can optionally authenticate via OIDC
- GitLab CI - Identifies GitLab pipelines and supports authentication tokens
- Azure Pipelines - Recognizes Azure DevOps build environments
- Jenkins - Detects Jenkins job executions
- CircleCI - Identifies CircleCI build contexts
- Dagger - Detects Dagger pipeline environments
- TeamCity - Recognizes TeamCity build configurations
The goal of this task is to explore how we can achieve a similar functionality for Tekton.
Hello @waveywaves :)
Here's my initial research on how we could potentially detect Tekton workloads. Based on my research here are a few key points:
- Does NOT automatically inject environment variables
- Uses variable substitution:
$(context.taskRun.name) - Users must explicitly define env vars in Task/Pipeline specs
- Has unique filesystem markers:
/tektondirectory structure
Tekton Environment Markers
Filesystem Structure
Every Tekton Task/Pipeline execution creates a /tekton directory with the following verified structure:
/tekton/
├── artifacts/ # Empty directory for artifacts
├── bin/ # Contains 'entrypoint' binary (Tekton's custom entrypoint ~61MB)
├── creds/ # Credentials directory (empty if none configured)
├── downward/ # Kubernetes Downward API mount point
│ └── ready # Symlink to file containing "READY" when step is ready
├── home/ # Home directory (empty, writable)
├── results/ # Task results output directory (PRIMARY DETECTION MARKER)
├── run/ # Runtime status files
│ └── 0/ # Step number (0 for first step)
│ └── status/
│ ├── artifacts/
│ └── results/
├── scripts/ # Generated scripts for each step (e.g., script-0-xxxxx)
├── steps/ # Symlinks to step status (e.g., step-<name> -> /tekton/run/0/status)
└── termination # Empty file used for termination signaling
Detection Method: Check for existence of /tekton/results directory (most reliable, always present).
Downward API
As per the documentation Tekton leverages Kubernetes Downward API to pass information to each step container. The information held there is pretty important for the point of view of Chainloop because it contains information about the Task/Pipeline.
tekton.dev/taskRun="<taskrun-name>"- TaskRun nametekton.dev/pipelineRun="<pipelinerun-name>"- PipelineRun name (if in Pipeline)tekton.dev/pipeline="<pipeline-name>"- Pipeline nametekton.dev/pipelineTask="<task-name>"- Task name in Pipelinetekton.dev/taskRunUID="<uuid>"- TaskRun UIDtekton.dev/pipelineRunUID="<uuid>"- PipelineRun UIDtekton.dev/memberOf="tasks"- Resource type
The problem I have encountered is that I need to manually mount the volume on the template like:
stepTemplate:
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
readOnly: true
As I understood it, that should be injected by Tekton, right? Is Tekton mounting this on a different path?
Kubernetes Service Account
Tekton is also mounting a file with a service account, could potentially that service account be used to query Tekton API?
I would greatly value your feedback on this, as it appears that we can detect the workload is Tekton by examining the tekton tree structure. However, the essential information regarding IDs, Task/Pipeline names, and so on, is quite challenging to obtain. Our objective is to acquire this information transparently without user intervention or modification of their templates.