Skip to content

Commit c3e15bb

Browse files
committed
feat: add flexible OCI storage format configuration
Add storage.oci.format configuration supporting three storage strategies for OCI signatures and attestations: - "legacy": Tag-based storage with DSSE format (default) - "referrers-api": OCI 1.1 referrers API with DSSE format - "protobuf-bundle": OCI 1.1 referrers API with protobuf bundle format Implementation includes: - Configuration layer with format validation and defaults - Format-based routing in AttestationStorer and SimpleStorer - Three storage implementations per storer type - Legacy backend integration with format-aware storers - Comprehensive test coverage for all three formats Enables adoption of OCI 1.1 referrers API while maintaining backward compatibility with existing tag-based storage. All formats also work correctly with both certificate-based and x509 key configurations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: arewm <[email protected]> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
1 parent e3469c5 commit c3e15bb

File tree

16 files changed

+1203
-32
lines changed

16 files changed

+1203
-32
lines changed

docs/config.md

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Supported keys include:
6666
|:-------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|
6767
| `storage.gcs.bucket` | The GCS bucket for storage | | |
6868
| `storage.oci.repository` | The OCI repo to store OCI signatures and attestation in | If left undefined _and_ one of `artifacts.{oci,taskrun}.storage` includes `oci` storage, attestations will be stored alongside the stored OCI artifact itself. ([example on GCP](../images/attestations-in-artifact-registry.png)) Defining this value results in the OCI bundle stored in the designated location _instead of_ alongside the image. See [cosign documentation](https://github.com/sigstore/cosign#specifying-registry) for additional information. | |
69+
| `storage.oci.format` | Storage format for OCI signatures and attestations. Controls both the storage mechanism and serialization format used for storing cryptographic artifacts. | `legacy` - Tag-based storage with DSSE format for full backward compatibility<br/>`referrers-api` - OCI 1.1 referrers API with DSSE format for reduced tag proliferation<br/>`protobuf-bundle` - OCI 1.1 referrers API with protobuf bundle format for experimental cosign features | `legacy` |
6970
| `storage.docdb.url` | The go-cloud URI reference to a docstore collection | `firestore://projects/[PROJECT]/databases/(default)/documents/[COLLECTION]?name_field=name` | |
7071
| `storage.docdb.mongo-server-url` (optional) | The value of MONGO_SERVER_URL env var with the MongoDB connection URI | Example: `mongodb://[USER]:[PASSWORD]@[HOST]:[PORT]/[DATABASE]` | |
7172
| `storage.docdb.mongo-server-url-dir` (optional) | The path of the directory that contains the file named MONGO_SERVER_URL that stores the value of MONGO_SERVER_URL env var | If the file `/mnt/mongo-creds-secret/MONGO_SERVER_URL` has the value of MONGO_SERVER_URL, then set `storage.docdb.mongo-server-url-dir: /mnt/mongo-creds-secret` | |
@@ -75,6 +76,77 @@ Supported keys include:
7576
| `storage.grafeas.notehint` (optional) | This field is used to set the [human_readable_name](https://github.com/grafeas/grafeas/blob/cd23d4dc1bef740d6d6d90d5007db5c9a2431c41/proto/v1/attestation.proto#L49) field in the Grafeas ATTESTATION note. If it is not provided, the default `This attestation note was generated by Tekton Chains` will be used. | | |
7677
| `storage.archivista.url` | The URL endpoint for the Archivista service. | A valid HTTPS URL pointing to your Archivista instance (e.g. `https://archivista.testifysec.io`). | None |
7778

79+
#### OCI Storage Formats
80+
81+
The `storage.oci.format` configuration supports three distinct storage formats, each designed for different use cases:
82+
83+
##### Legacy Format (`legacy`)
84+
- **Storage Mechanism**: Tag-based storage using `<image>:sha256-<digest>.sig` and `<image>:sha256-<digest>.att` tags
85+
- **Serialization Format**: DSSE (Dead Simple Signing Envelope) format
86+
- **Compatibility**: Full backward compatibility with existing tooling and deployments
87+
- **Registry Impact**: Creates additional tags in the registry for each signature and attestation
88+
- **Use Case**: Production deployments requiring maximum compatibility
89+
90+
**Example Configuration:**
91+
```yaml
92+
apiVersion: v1
93+
kind: ConfigMap
94+
metadata:
95+
name: chains-config
96+
namespace: tekton-chains
97+
data:
98+
storage.oci.format: "legacy"
99+
```
100+
101+
##### Referrers API Format (`referrers-api`)
102+
- **Storage Mechanism**: OCI 1.1 Referrers API for artifact relationships
103+
- **Serialization Format**: DSSE (Dead Simple Signing Envelope) format - same as legacy
104+
- **Compatibility**: Compatible with OCI 1.1 registries and DSSE-aware tooling
105+
- **Registry Impact**: Uses referrers API, significantly reducing tag proliferation
106+
- **Use Case**: Modern OCI 1.1 registries where tag reduction is desired while maintaining DSSE compatibility
107+
108+
**Example Configuration:**
109+
```yaml
110+
apiVersion: v1
111+
kind: ConfigMap
112+
metadata:
113+
name: chains-config
114+
namespace: tekton-chains
115+
data:
116+
storage.oci.format: "referrers-api"
117+
```
118+
119+
##### Protobuf Bundle Format (`protobuf-bundle`)
120+
- **Storage Mechanism**: OCI 1.1 Referrers API for artifact relationships
121+
- **Serialization Format**: Protobuf bundle format for experimental cosign features
122+
- **Compatibility**: Requires cosign experimental features and latest tooling
123+
- **Registry Impact**: Uses referrers API with experimental serialization
124+
- **Use Case**: Testing new cosign features and experimental workflows
125+
126+
**Example Configuration:**
127+
```yaml
128+
apiVersion: v1
129+
kind: ConfigMap
130+
metadata:
131+
name: chains-config
132+
namespace: tekton-chains
133+
data:
134+
storage.oci.format: "protobuf-bundle"
135+
```
136+
137+
**Important Notes:**
138+
- The default format is `legacy` to ensure backward compatibility
139+
- Referrers API formats (`referrers-api` and `protobuf-bundle`) require OCI 1.1 compatible registries
140+
- Format changes affect both signatures and attestations
141+
- The `protobuf-bundle` format is experimental and may change in future releases
142+
143+
**Migration from Deprecated Configuration:**
144+
The deprecated `storage.oci.referrers-api` boolean configuration is automatically migrated:
145+
- `storage.oci.referrers-api: false` → `storage.oci.format: "legacy"`
146+
- `storage.oci.referrers-api: true` → `storage.oci.format: "protobuf-bundle"`
147+
148+
See the [OCI Format Migration Guide](oci-format-migration.md) for detailed migration instructions.
149+
78150
#### docstore
79151

80152
You can read about the go-cloud docstore URI format [here](https://gocloud.dev/howto/docstore/). Tekton Chains supports the following docstore services:
@@ -189,4 +261,4 @@ To restrict the controller to the dev and test namespaces, you would start the c
189261
```shell
190262
--namespace=dev,test
191263
```
192-
In this example, the controller will only monitor resources (pipelinesruns and taskruns) within the dev and test namespaces.
264+
In this example, the controller will only monitor resources (pipelinesruns and taskruns) within the dev and test namespaces.

pkg/chains/signing.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,21 @@ func (o *ObjectSigner) Sign(ctx context.Context, tektonObj objects.TektonObject)
196196
continue
197197
}
198198

199+
// Extract public key from signer for storage backends that need it
200+
pubKey, err := signer.PublicKey()
201+
if err != nil {
202+
logger.Errorf("Failed to extract public key from signer: %v", err)
203+
o.recordError(ctx, signableType.Type(), metrics.SigningError)
204+
merr = multierror.Append(merr, err)
205+
continue
206+
}
207+
199208
storageOpts := config.StorageOpts{
200209
ShortKey: signableType.ShortKey(obj),
201210
FullKey: signableType.FullKey(obj),
202211
Cert: signer.Cert(),
203212
Chain: signer.Chain(),
213+
PublicKey: pubKey,
204214
PayloadFormat: payloadFormat,
205215
}
206216
if err := b.StorePayload(ctx, tektonObj, rawPayload, string(signature), storageOpts); err != nil {

pkg/chains/signing/iface.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ limitations under the License.
1414
package signing
1515

1616
import (
17+
"crypto"
18+
1719
"github.com/sigstore/sigstore/pkg/signature"
1820
)
1921

@@ -41,4 +43,6 @@ type Bundle struct {
4143
Cert []byte
4244
// Cert is an optional PEM encoded x509 certificate chain, if one was used for signing.
4345
Chain []byte
46+
// PublicKey is the public key from the signer, available for storage backends that need it.
47+
PublicKey crypto.PublicKey
4448
}

pkg/chains/storage/gcs/gcs.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func (b *Backend) StorePayload(ctx context.Context, obj objects.TektonObject, ra
8181
Signature: []byte(signature),
8282
Cert: []byte(opts.Cert),
8383
Chain: []byte(opts.Chain),
84+
PublicKey: opts.PublicKey,
8485
},
8586
}); err != nil {
8687
logger.Errorf("error writing to GCS: %w", err)
@@ -101,6 +102,7 @@ func (b *Backend) StorePayload(ctx context.Context, obj objects.TektonObject, ra
101102
Signature: []byte(signature),
102103
Cert: []byte(opts.Cert),
103104
Chain: []byte(opts.Chain),
105+
PublicKey: opts.PublicKey,
104106
},
105107
}); err != nil {
106108
logger.Errorf("error writing to GCS: %w", err)

0 commit comments

Comments
 (0)