This is a tool to cache resources like go cache/maven or others on TektonCD pipelines.
This tool supports uploading the cache to an OCI registry and plans to support S3, GCS and other storage backends.
It uses the new StepActions feature of TektonCD Pipelines but can be as well used without it.
See the StepActions in the tekton/ directory.
This is an example of a build pipeline for a go application caching and reusing
the go cache. If the go.mod and go.sum are changed the cache is invalidated and
rebuilt.
- You need a recent TektonCD pipelines installed with the StepActions feature-flags enabled.
kubectl patch configmap -n tekton-pipelines --type merge -p '{"data":{"enable-step-actions": "true"}}' feature-flags- A registry to push the images to. Example: docker.io/loginname. Make sure you have setup tekton to be able to push/fetch from that registry, see the TektonCD pipelines documentation
Create the go pipeline example from the examples directory:
kubectl create -f pipeline-go.yamlStart it with the tkn cli (change the value as needed):
tkn pipeline start pipeline-go --param repo_url=https://github.com/vdemeester/go-helloworld-app --param revision=main --param registry=docker.io/username -w name=source,emptyDir= --use-param-defaultsor with a PipelineRun yaml object:
kind: PipelineRun
metadata:
name: build-go-application-with-caching-run
spec:
pipelineRef:
name: pipeline-go
params:
- name: repo_url
value: https://github.com/vdemeester/go-helloworld-app
- name: revision
value: main
- name: registry
value: docker.io/username
workspaces:
- name: source
emptyDir: { }- you can as well redefine the
buildCommandwhich by default do ago build -v ./with thebuildCommandparameter, for example if you want instead to run the tests on a repo with caching:
tkn pipeline start pipeline-go --param repo_url=https://github.com/chmouel/gosmee \
--param revision=main --param registry=docker.io/username \
--param=buildCommand="make test" -w name=source,emptyDir= --use-param-defaults --showlog- You can as well force the upload of the cache with param
FORCE_CACHE_UPLOAD=true(default: false) - You can provide your own image with the param
image(default to the latest docker.iogolangimage) - You can provide your own patterns for the hash to computer with the
cachePatternsarray parameter (default togo.mod,go.sum)
In order to use the StepAction with GCS, the parameter googleCredentialsPath needs to be specified. It should point
to the google service account json file — which usually comes from a secret.
For example, let's assume a secret name gcs-secret is populated with the content of the google service account, key
gcs-sa.json (a json file, be it with or without support for Google Workload Identity). One could use a workspace or
a volume to mount that secret somewhere and set the path to the StepAction.
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
generateName: my-taskrun-
spec:
params:
- name: serviceAccountName
value: gcs-sa.json
taskSpec:
params:
- name: serviceAccountName
type: string
default: ""
workspaces:
- name: source
- name: google-credentials
optional: true
- name: bound-sa-token
mountPath: /var/run/secrets/openshift/serviceaccount
optional: true
steps:
- # […] git clone, …
- name: cache-fetch
ref:
name: cache-fetch
# or using http resolver with https://raw.githubusercontent.com/openshift-pipelines/tekton-caches/main/tekton/cache-fetch.yaml
params:
- name: PATTERNS
value: [ "go.mod", "go.sum" ]
- name: SOURCE
value: gs://my-bucket/some/folder
- name: CACHE_PATH
value: $(workspace.source.path)/cache
- name: WORKING_DIR
value: $(worksoaces.source.path)/repo
- name: GOOGLE_APPLICATION_CREDENTIALS
value: $(workspace.google-credentials.path)/$(params.serviceAccountName)
- # […] something else like go build
- # […] and then same thing with cache-upload
workspaces:
- name: source
emptyDir: { }
- name: google-credentials
secret:
secretName: gcs-secret
- name: bound-sa-token
projected:
sources:
- serviceAccountToken:
audience: openshift
expirationSeconds: 3600
path: token
defaultMode: 420bound-sa-token workspace isn't required if Workload Identity federation isn't setup. Here we assumed an OIDC is
configured in OpenShift.
The {{hash}} used in SOURCE and TARGET is a SHA-256 computed over, in order:
- a fixed domain separator;
- the namespace the step runs in;
- the number of matched files;
- the files matched by
PATTERNS, sorted by their path relative toWORKING_DIR, each contributing its relative path, its size and the SHA-256 of its content.
The domain separator, namespace and each relative path are length-prefixed before being hashed. The file count and file sizes use fixed-width integers, and each content digest has a fixed width. These encodings make field boundaries unambiguous. Relative paths, sizes and file contents all contribute to the key; only the checkout location and match order are ignored.
The StepActions read the TaskRun namespace from the downward API (metadata.namespace), so the same matched files
produce different keys in differently named namespaces. A SOURCE or TARGET is scoped by that key only when it
contains {{hash}}. This is defense in depth against unintended cache sharing, not an access-control boundary:
direct CLI callers can choose --namespace, literal references bypass hash substitution, and namespace names can
repeat across clusters. Backend credentials and policies must enforce tenant isolation.
To deliberately share generated entries across namespaces, retain {{hash}} and invoke the cache binary with the
same explicit, non-empty --namespace value.
Note
The key format changed to fix collisions between different file layouts. Hash-templated references will miss entries created with the previous format. A successful upload creates a new entry; old objects remain until the backend's retention policy removes them.
Here is the list of params being used in cache step actions.
These parameters are supported in both cache-fetch and cache-upload step-action
| Name | Type | Optional | Description | Default Value |
|---|---|---|---|---|
PATTERNS |
array |
NO | Regular expression to select files to include to compute the hash. For example, in the case of a Go project, you can use go.mod for this, so the value would be "**/go.sum" (to work with possible sub go modules as well). |
None |
CACHE_PATH |
string |
NO | Path where to extract the cache content. It can refer any folder, backed by a workspace or a volume, or nothing. |
None |
WORKING_DIR |
string |
NO | The working dir from where the files patterns needs to be taken | None |
INSECURE |
string |
YES | Whether to use insecure mode for fetching the cache | false |
GOOGLE_APPLICATION_CREDENTIALS |
string |
YES | The path where to find the google credentials. If left empty, it is ignored. | "" |
AWS_CONFIG_FILE |
string |
YES | The path to the aws config file. If left empty, it is ignored. | "" |
AWS_SHARED_CREDENTIALS_FILE |
string |
YES | The path to find the aws credentials file. If left empty, it is ignored. | "" |
BLOB_QUERY_PARAMS |
string |
YES | Extra query parameters (URL encoded, e.g. region=us-east-1&accelerate=true) passed to the s3/gcs blob driver. This is optional unless some additional features of storage providers are required like s3 acceleration, fips, pathstyle, etc. Only the parameters listed in Allowed blob query parameters are accepted. |
"" |
Query parameters are validated against an allow list before the bucket is opened, whether they come from
BLOB_QUERY_PARAMS or are already present in the SOURCE/TARGET URL. BLOB_QUERY_PARAMS may optionally start with
? or & for compatibility. Each logical parameter may be specified only once across both sources. Any other or
repeated parameter makes the step fail with a security policy violation error.
| Parameter | Provider | Description |
|---|---|---|
region |
S3 | AWS region of the bucket |
s3ForcePathStyle |
S3 | Legacy alias for path-style addressing |
use_path_style |
S3 | Use path-style addressing |
accelerate |
S3 | Use the S3 transfer acceleration endpoint |
fips |
S3 | Use the FIPS endpoint |
ssetype |
S3 | Server side encryption type |
anonymous |
S3, GCS | Access the bucket without credentials |
access_id |
GCS | Service account email used for signing |
Parameter names are matched case insensitively and normalized to the spelling the driver expects, so
s3forcepathstyle and S3ForcePathStyle are both accepted.
The GCS private_key_path and universe_domain parameters are deliberately not allowed: the first one reads an
arbitrary file from the local filesystem and the second one redirects the client to another GCP universe. The S3
kmskeyid parameter is also excluded; configure the default KMS key on the bucket so callers cannot select a different
encryption key through cache parameters.
In particular, endpoint is blocked by default: it lets untrusted configuration redirect the cache to an arbitrary
host, so it is deliberately not on the allow list. Deployments that legitimately need a custom endpoint, such as MinIO
or another S3 compatible store, can still set one through the AWS configuration file pointed at by the
AWS_CONFIG_FILE param, which the SDK reads directly:
[default]
region = us-east-1
endpoint_url = http://127.0.0.1:<port>This allow list is defense in depth for Pipelines that keep the SOURCE/TARGET authority, AWS_CONFIG_FILE, mounted
configuration, and credentials trusted. If callers can change those inputs or their files, the allow list does not
prevent endpoint redirection.
| Name | Type | Optional | Description | Default Value |
|---|---|---|---|---|
SOURCE |
string |
NO | The source from where the cache should be fetched. It's a URI with the scheme defining the "provider". In addition, one can add a {{hash}} variable to use the computed hash in the reference (oci image tags, path in s3, …) Currently supported:
|
None |
| Name | Type | Optional | Description | Default Value |
|---|---|---|---|---|
TARGET |
string |
NO | The target from where the cache should be uploaded. It's a URI with the scheme defining the "provider". In addition, one can add a {{hash}} variable to use the computed hash in the reference (oci image tags, path in s3, …) Currently supported:
|
None |