cosign_piv-tool_set-puk Documentation

Official TypeScript developer resources and documentation for sigstore/cosign_piv-tool_set-puk. Verified technical context for AI.

0 stars TypeScript TypeScript 1 file ยท ~14,217 tokens
RAW Doc

1. Project Overview & Quickstart (sigstore/cosign_piv-tool_set-puk)

Technical Documentation: sigstore/cosign_piv-tool_set-puk

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

cosign_piv-tool_set-puk

Agent Skills & Rules

  • Discovered 21 agent rule(s) and prompt configurations.

--- METRICS ---

2. Official Technical Reference & Guides (sigstore/docs)

File: archetypes/docs/lorem/ipsum/index.md


title: "Ipsum"
lead: ""
date: 2022-01-25T14:41:39+01:00
lastmod: 2022-01-25T14:41:39+01:00
draft: false
images: []
type: docs
menu:
{{ .Section }}:
parent: "lorem"
identifier: "{{ .Name }}-{{ delimit (shuffle (split (md5 .Name) "" )) "" }}"
weight: 100

toc: true


File: archetypes/docs/lorem/_index.md


title: "Lorem" lead: "" date: 2022-01-25T14:41:21+01:00 lastmod: 2022-01-25T14:41:21+01:00 draft: false images: [] type: docs


File: archetypes/docs/_index.md


title: "Docs" lead: "" date: 2022-01-25T14:40:56+01:00 lastmod: 2022-01-25T14:40:56+01:00 draft: false images: [] type: docs


File: content/en/logging/CLI.md


type: docs category: Transparency Log title: CLI weight: 1825

The following guide is targeted towards developers / software maintainers who would like to make a provenance entry into the Rekor transparency log.

The steps outlined below will show how to sign your software and use the Rekor CLI to make and verify an entry. It uses GPG to demonstrate, but other types are outlined in the [Signing and Uploading Other Types]({{< relref "logging/sign-upload">}}) page.

Prerequisites

You need to have Rekor CLI installed. See the [Installation]({{< relref "logging/installation">}}) page for instructions.

Sign your release

Before using Rekor, you are required to sign your release. The following example illustrates this using GPG.

You may use either armored or plain binary:

bash
gpg --armor -u [email protected] --output mysignature.asc --detach-sig myrelease.tar.gz

You will also need to export your public key

bash
gpg --export --armor "[email protected]" > mypublickey.key

Upload an entry to Rekor

The upload command sends your public key / signature and artifact URL to the Rekor transparency log.

bash
rekor-cli upload --rekor_server https://rekor.sigstore.dev --signature <artifact_signature> --public-key <your_public_key> --artifact <url_to_artifact>|<local_path_artifact>

The Rekor command will first verify your public key and signature and download a local copy of the artifact. Then it will validate the artifact signing (no access to your private key is required).

If the validations above pass correctly, the entry will be made to Rekor and an entry URL will be returned:

bash
Created entry at: https://rekor.sigstore.dev/api/v1/log/entries/b08416d417acdb0610d4a030d8f697f9d0a718024681a00fa0b9ba67072a38b5

This URL contains the UUID entry / merkle tree hash (in the above case b08416d417acdb0610d4a030d8f697f9d0a718024681a00fa0b9ba67072a38b5).

Verify Proof of Entry

The verify command allows you to send a public key / signature and artifact to the Rekor transparency log for verification of entry.

You would typically use this command as a means to verify an 'inclusion proof' showing that your artifact is stored within the transparency log.

bash
rekor-cli verify --rekor_server <rekor_url> --signature <artifact-signature> --public-key <your_public_key> --artifact <url_to_artifact>|<local_path_artifact>

Note that alternatively you can use a local artifact path with --artifact.

Get Entry

An entry in the log can be retrieved by using the get command with either the log index or the artifact UUID:

bash
rekor-cli get --rekor_server https://rekor.sigstore.dev --log-index <log-index>
bash
rekor-cli get --rekor_server https://rekor.sigstore.dev --uuid <uuid>

Log Info

The loginfo command retrieves the public key of the transparency log (unless already declared within the client ~/.rekor/rekor.yaml) and then uses this public key to verify the signature on the signed tree head.

bash
rekor-cli loginfo --rekor_server https://rekor.sigstore.dev

If running a redis instance within Rekor, the search command performs a redis lookup using a file or a public key.

This command requires one of an artifact, a public key, or a SHA hash (should be prefixed by sha256:).

bash
rekor-cli search --rekor_server https://rekor.sigstore.dev --[artifact|public-key|sha]

For example:

bash
rekor-cli search --rekor_server https://rekor.sigstore.dev --sha sha256:e2e90d1a25f90a3156a27f00f3a4179578e3132ed4f010dc3498d09175b6071a

File: content/en/logging/event_stream.md


type: docs category: Transparency Log menuTitle: Event Stream title: Using the Rekor Event Stream weight: 1850

The public Rekor instance provides an event stream of new entries added to the transparency log using GCP Pub/Sub. This can be used to monitor the log in real-time for events you are interested in.

Pub/Sub details

Important: Pub/Sub usage is not free. Please familiarize yourself with the pricing before proceeding.

Tip: You can avoid paying egress network costs by placing the workload that processes events from the subscription in the same region as the topic.

The details needed to subscribe to the topic are below. Any authenticated GCP principal can create subscriptions to the topic.

Item Value
GCP Project ID project-rekor
Pub/Sub Topic ID new-entry
Pub/Sub Topic Region us-central1

Event format

The events are published in both the JSON and Protobuf formats of the CloudEvents specificaion. The data field is always a serialized TransparencyLogEntry proto message. For JSON formatted events, this follows the JSON serialization specification for Protobufs.

All published events have attributes attached to them. Attributes that are custom to Rekor and not a part of the CloudEvents specification are prefixed by rekor_. You can add server-side filters based on these attributes to automatically acknowledge messages you are not interested in to reduce costs.

Attribute Value
datacontenttype application/json or application/protobuf
id The unique identifier for the entry in the Rekor log.
rekor_entry_kind The kind of the Rekor entry (hashedrekord, intoto, etc.)
rekor_signing_subjects A sorted, comma-delimeted list of the principals that signed the entry.
source /createLogEntry
specversion 1.0
time The timestamp the entry was added to the log.
type dev.sigstore.rekor.events.v1.NewEntry

Example usage

In this example scenario, we want to monitor all log entries added by GitHub Actions CI workers in the Sigstore GitHub org. We do this to verify that all CI runs that upload entries to Rekor are from the main branch only. Uploads from other branches could indicate a GitHub Actions misconfiguration that allowed a malicious actor to submit a pull request which triggered a CI run that allowed them to sign their artifacts using our identity.

Setting up the subscription

Note: To perform the steps below, you will need the gcloud CLI.

First, define some environment variables. You may pick any value you like for SUBSCRIPTION_PROJECT_ID and SUBSCRIPTION_ID. The value for SUBSCRIPTION_PROJECT_ID must be globally unique among all GCP projects.

sh
export SUBSCRIPTION_PROJECT_ID="your-gcp-project-id"
export SUBSCRIPTION_ID="new-entry-subscription"
export SUBSCRIPTION_CONTENT_TYPE="application/protobuf"

If the project does not exist, you can create it with the command below.

sh
gcloud projects create $SUBSCRIPTION_PROJECT_ID

Then, you can create the subscription, filtering on the content type and the signing subjects we want to receive messages about.

sh
export SUBSCRIPTION_FILTER='attributes.datacontenttype = "$SUBSCRIPTION_CONTENT_TYPE" AND hasPrefix(attributes.rekor_signing_subjects, "https://github.com/sigstore/")'
sh
gcloud pubsub subscriptions create \
    $SUBSCRIPTION_ID \
    --project $SUBSCRIPTION_PROJECT_ID \
    --topic new-entry \
    --topic-project project-rekor \
    --message-filter $SUBSCRIPTION_FILTER

The subscription is now set up and we can pull the events

Processing log entries

The first step is to create a program that pulls all messages from the subscription indefinitely. It passes all received messages to a handleMsg function. The code examples below omit imports from Go's standard library for brevity.

go
import (
	"cloud.google.com/go/pubsub"
)

func main() {
	ctx, done := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
	defer done()

	// Bootstrap the PubSub client.
	client, err := pubsub.NewClient(ctx, os.Getenv("SUBSCRIPTION_PROJECT_ID"))
	if err != nil {
		log.Fatal(err)
	}
	sub := client.Subscription(os.Getenv("SUBSCRIPTION_ID"))

	// Continuously read messages into a channel.
	msgs := make(chan *pubsub.Message)
	go func() {
		for {
			err := sub.Receive(ctx, func(_ context.Context, msg *pubsub.Message) {
				msgs <- msg
			})
			if err != nil {
				log.Print(err)
			}
		}
	}()

	// Handle each message received until the process is terminated.
	for {
		select {
		case msg := <-msgs:
			if err := handleMsg(msg); err != nil {
				log.Print(err)
			}
			msg.Ack()
		case <-ctx.Done():
			return
		}
	}
}

The handleMsg function deserializes the event and then checks the signing subjects.

go
import (
	"google.golang.org/protobuf/proto"
	eventspb "github.com/sigstore/protobuf-specs/gen/pb-go/events/v1"
)

func handleMsg(msg *pubsub.Message) error {
	event := new(eventspb.CloudEvent)
	if err := proto.Unmarshal(msg.Data, event); err != nil {
		return fmt.Errorf("unmarshal msg %q: %w", msg.ID, err)
	}

	// In a real implementation, you should verify the entry before proceeding!

	attr, ok := event.Attributes["rekor_signing_subjects"]
	if !ok {
		return fmt.Errorf("entry %q is missing rekor_signing_subjects", event.GetId())
	}
	subjects := strings.Split(attr.GetCeString(), ",")
	for _, subject := range subjects {
		if !strings.HasSuffix(subject, "@refs/heads/main") {
			return fmt.Errorf("entry %q was not run from the main branch: %s", event.GetId(), subject)
		}
	}

	return nil
}

File: content/en/logging/installation.md


type: docs category: Transparency Log title: Installation weight: 1805

There are several ways to install both the rekor-cli and rekor-server.

Using Go install

If you have Go installed, you can use Go to retrieve the rekor-cli binaries

bash
go install -v github.com/sigstore/rekor/cmd/rekor-cli@latest

You may also do the same for rekor-server, but please note that the Rekor server also requires Trillian and a database. (see below for setup instructions).

bash
go install -v github.com/sigstore/rekor/cmd/rekor-server@latest

From the release page

Rekor releases are available on the Release page.

Releases are available for both rekor-server and rekor-cli.

Review [Verifying Binaries]({{< relref "logging/verify-release">}}) for details on how to verify Rekor release binaries.

Build Rekor CLI manually

bash
git clone https://github.com/sigstore/rekor.git rekor-cli
cd rekor-cli
make rekor-cli
cp rekor-cli /usr/local/bin/

Deploy a Rekor Server manually

There are a few ways you can deploy a Rekor Server:

  1. We have a docker-compose file available.
  2. Alternatively, you can build a Rekor server yourself.

Note: The Rekor server manually creates a new Merkle tree (or shard) in the Trillian backend every time it starts up, unless an existing one is specified in via the --trillian_log_server.tlog_id flag. If you are building the server yourself and do not need [sharding]({{< relref "logging/sharding">}}) functionality, you can find the existing tree's TreeID by issuing this client command while the server is running:

CURRENT_TREE_ID=$(rekor-cli loginfo --format json | jq -r .TreeID)

Then pass in this TreeID at the next server startup to tell Rekor to use the same existing tree:

rekor-server serve --trillian_log_server.tlog_id=$CURRENT_TREE_ID

Setting this flag isn't necessary in an environment like docker-compose.

Prerequisites

You will need golang version 1.16 or greater and a $GOPATH set.
You will also need a MySQL compatible database and, if you want to perform fast queries, an instance of redis running.
Otherwise you must pass the --enable_retrieve_api=false flag when running rekor-server in the later steps of this page.

Get Rekor

Grab the Rekor source:

go get -u -t -v github.com/sigstore/rekor/cmd/rekor-server

Should you prefer, you can also git clone https://github.com/sigstore/rekor.git

Create database and populate tables

Rekor requires a database. We use MariaDB for now (others to be explored later). Install and set up MariaDB on your machine.

bash
dnf install mariadb mariadb-server
systemctl start mariadb
systemctl enable mariadb
mysql_secure_installation

The Rekor directory has a scripts/createdb.sh file that will set up a test database (default user: test; default password: zaphod) and populate the needed tables for Trillian. If youโ€™re just trying out Rekor, keep the DB user name and password the same as in the script (test/zaphod). If you change these, you need to make the changes on Trillianโ€™s side (visit the Trillian repo for details).

bash
cd $GOPATH/pkg/mod/github.com/sigstore/[email protected]/scripts/
sh createdb.sh

Build Trillian

You also need to build Trillian, an append-only log:

bash
go get -u -t -v github.com/google/trillian
cd $GOPATH/src/github.com/google/trillian/cmd/trillian_log_server
go build
cp trillian_log_server /usr/local/bin/

cd $GOPATH/src/github.com/google/trillian/cmd/trillian_log_signer
go build
cp trillian_log_signer /usr/local/bin/

cd $GOPATH/src/github.com/google/trillian/cmd/createtree
go build
cp createtree /usr/local/bin/

Next, run the Trillian log server:

bash
trillian_log_server --logtostderr ...

Run the signer:

bash
trillian_log_signer --logtostderr --force_master --rpc_endpoint=localhost:8190 -http_endpoint=localhost:8191  --batch_size=1000 --sequencer_guard_window=0 --sequencer_interval=200ms

Note: you can log both to files and to stderr using --alsologtostderr

Create the tree:

bash
createtree --admin_server=localhost:8090

Build the Rekor Server

With Trillian and MariaDB set up, you can now build the Rekor Server:

bash
cd $GOPATH/pkg/mod/github.com/sigstore/[email protected]/cmd/rekor-server
go build -v -o rekor-server
cp rekor-server /usr/local/bin/

Start the Rekor Server

bash
rekor-server serve --enable_retrieve_api=false

2020-09-12T16:32:22.705+0100  INFO  cmd/root.go:87  Using config file: /Users/lukehinds/go/src/github.com/sigstore/rekor-server/rekor-server.yaml
2020-09-12T16:32:22.705+0100  INFO  app/server.go:55  Starting server...
2020-09-12T16:32:22.705+0100  INFO  app/server.go:61  Listening on 127.0.0.1:3000

If you have a redis server running to enable searching your Rekor server, remove the enable_reprieve_api flag

Next Steps

Congratulations! Your local Rekor server is now running. You can interact with it using the [Rekor CLI]({{< relref "logging/cli">}}).


File: content/en/logging/overview.md


type: docs category: Transparency Log menuTitle: Overview title: Rekor weight: 1800

Rekor aims to provide an immutable, tamper-resistant ledger of metadata generated within a software projectโ€™s supply chain.

It enables software maintainers and build systems to record signed metadata to an immutable record. Other parties can then query this metadata, enabling them to make informed decisions on trust and non-repudiation of an objectโ€™s lifecycle.

The Rekor project provides a restful API-based server for validation, and a transparency log for storage. A CLI application is available to make and verify entries, query the log for inclusion proof, integrity verification of the log or retrieval of entries (either by a public key or an artifact).

Rekor fulfils the signature transparency role of Sigstoreโ€™s software signing infrastructure. It can also be run on its own, and itโ€™s designed to be extendable to working with different manifest schemas and PKI tooling.

Usage and installation

You can download and setup the Rekor Server and Rekor CLI by following the instructions on the [Installation]({{< relref "logging/installation">}}) page.

A public instance of Rekor can be found at rekor.sigstore.dev. The public instance offers an SLO of 99.5% availability and is monitored by an oncall team.

Auditing the Public Instance

Rekor is built on top of a verifiable data structure. Auditors can monitor the log for consistency, meaning that the log remains append-only and entries are never mutated or removed.
Verifiers can also monitor the log for their identities.
Learn more about transparency logs here, and about binary transparency here.

There are few options for auditing and monitoring the Rekor log. We've built a monitor that runs on GitHub Actions,
Rekor monitor. Follow the instructions to set up a new repository and use the provided reusable workflow to audit the log. You can also monitor the log for specified identities, though this feature is a work in progress and supports a limited set of identities and entry types.

You can also run omniwitness to
audit the log, built by the team who created Trillian, which provides Rekor's verifiable log.


File: content/en/logging/pluggable-types.md


type: docs category: Transparency Log title: Pluggable Types weight: 1830

Rekor supports pluggable types (aka different schemas) for entries stored in the transparency log. This will allow you to develop your own manifest type in your preferred formatting style (json|yaml|xml).

Currently supported types

The list of currently supported types and their schema is maintained in the repository.

Base schema

The base schema for all types is modeled off of the schema used by Kubernetes and can be found in openapi.yaml as #/definitions/ProposedEntry:

bash
definitions:
  ProposedEntry:
    type: object
    discriminator: kind
    properties:
      kind:
        type: string
    required:
      - kind

The kind property is a discriminator that is used to differentiate between different pluggable types. Types can have one or more versions of the schema supported concurrently by the same Rekor instance; an example implementation can be seen in rekord.go.

Adding support for a new type

To add a new type (called newType in this example):

  1. Add a new definition in openapi.yaml that is a derived type of ProposedEntry (expressed in the allOf list seen below); for example:

    yaml
    newType:
      type: object
      description: newType object
      allOf:
        - $ref: "#/definitions/ProposedEntry"
        - properties:
            version:
              type: string
            metadata:
              type: object
              additionalProperties: true
            data:
              type: object
              $ref: "pkg/types/newType/newType_schema.json"
          required:
            - version
            - data
          additionalProperties: false

    Note: the $ref feature can be used to refer to an externally defined JSON schema document; however it is also permitted to describe the entirety of the type in valid Swagger (aka OpenAPI) v2 format within openapi.yaml.

  2. Create a subdirectory under pkg/types/ with your type name (e.g. newType) as a new Go package

  3. In this new Go package, define a struct that implements the TypeImpl interface as defined in pkg/types/types.go:

    go
    type TypeImpl interface {
      CreateProposedEntry(context.Context, version string, ArtifactProperties) (models.ProposedEntry, error)
        DefaultVersion() string
        SupportedVersions() []string
        IsSupportedVersion(version string) bool
        UnmarshalEntry(pe models.ProposedEntry) (EntryImpl, error)
    }
    • CreateProposedEntry creates an instance of a proposed entry based on the specified API version and the provided artifact properties
    • DefaultVersion returns the default API version string across all types (to be used if a caller does not specify an explicit version)
    • SupportedVersions returns the list of all API version strings that can currently be inserted into the log.
    • IsSupportedVersion returns a boolean denoting whether the specified version could be inserted into the log
    • UnmarshalEntry will be called with a pointer to a struct that was automatically generated for the type defined in openapi.yaml by the go-swagger tool used by Rekor
      • This struct will be defined in the generated file at pkg/generated/models/newType.go (where newType is replaced with the name of the type you are adding)
      • This method should return a pointer to an instance of a struct that implements the EntryImpl interface as defined in pkg/types/types.go, or a nil pointer with an error specified

    Also, the Kind constant must return the exact same string as you named your new type in openapi.yaml (e.g. "newType")

  4. Also in this Go package, provide an implementation of the EntryImpl interface as defined in pkg/types/entries.go:

    go
    type EntryImpl interface {
      APIVersion() string                                 // the supported versions for this implementation
        IndexKeys() ([]string, error)                     // the keys that should be added to the external index for this entry
        Canonicalize(ctx context.Context) ([]byte, error) // marshal the canonical entry to be put into the tlog
        Unmarshal(e models.ProposedEntry) error           // unmarshal the abstract entry into the specific struct for this versioned type
        CreateFromArtifactProperties(context.Context, ArtifactProperties) (models.ProposedEntry, error)
        Verifier() (pki.PublicKey, error)
        Insertable() (bool, error) // denotes whether the entry that was unmarshalled has the writeOnly fields required to validate and insert into the log
    }
    • APIVersion should return a version string that identifies the version of the type supported by the Rekor server
    • IndexKeys should return a []string containing the keys that are stored in the search index that should map to this log entry's ID.
    • Canonicalize should return a []byte containing the canonicalized contents representing the entry. The canonicalization of contents is important as we should have one record per unique signed object in the transparency log.
    • Unmarshal will be called with a pointer to a struct that was automatically generated for the type defined in openapi.yaml by the go-swagger tool used by Rekor
      • This method should validate the contents of the struct to ensure any string or cross-field dependencies are met to successfully insert an entry of this type into the transparency log
    • CreateFromArtifactProperties returns a proposed entry of this specific entry implementation given the provided artifact properties
    • Verifier returns the verification material that was used to verify the digital signature
    • Insertable introspects the entry and determines if the object is sufficiently hydrated to make a new entry into the log. Entry instances that are created by reading the contents stored in the log may not be sufficiently hydrated.
  5. In the Go package you have created for the new type, be sure to add an entry in the TypeMap in github.com/sigstore/rekor/pkg/types for your new type in the init method for your package. The key for the map is the unique string used to define your type in openapi.yaml (e.g. newType), and the value for the map is the name of a factory function for an instance of TypeImpl.

    go
    func init() {
        types.TypeMap.Set("newType", NewEntry)
    }
  6. Add an entry to pluggableTypeMap in cmd/server/app/serve.go that provides a reference to your package. This ensures that the init function of your type (and optionally, your version implementation) will be called before the server starts to process incoming requests and therefore will be added to the map that is used to route request processing for different types.

  7. After adding sufficient unit & integration tests, submit a pull request to sigstore/rekor for review and addition to the codebase.

Adding a new version of the `Rekord` type

To add new version of the default Rekord type:

  1. Create a new subdirectory under pkg/types/rekord/ for the new version

  2. If there are changes to the Rekord schema for this version, create a new JSON schema document and add a reference to it within the oneOf clause in rekord_schema.json. If there are no changes, skip this step.

  3. Provide an implementation of the EntryImpl interface as defined in pkg/types/types.go for the new version.

  4. In your package's init method, ensure there is a call to SemVerToFacFnMap.Set() which provides the link between the valid semver ranges that your package can successfully process and the factory function that creates an instance of a struct for your new version.

  5. Add an entry to pluggableTypeMap in cmd/server/app/serve.go that provides a reference to the Go package implementing the new version. This ensures that the init function will be called before the server starts to process incoming requests and therefore will be added to the map that is used to route request processing for different types.

  6. After adding sufficient unit & integration tests, submit a pull request to sigstore/rekor for review and addition to the codebase.


File: content/en/logging/sharding.md


type: docs category: Transparency Log title: Sharding weight: 1820

NOTE: The suggestions on this page are no longer recommended. This page only covers Rekor v1, aka rekor.sigstore.dev.
New Rekor deployments should use Rekor v2 only. We recommend creating
new log instances periodically depending on the growth of the log. Each log instance should be accessible via a unique
URL.

For the public infrastructure, we aim to create a new log every year, publishing the new log's URL in the
TUF-distributed signing configuration file
and its key in the trusted root file.


This document covers what Rekor log sharding is and how to shard the log.

What is sharding?

When Rekor is started for the first time, its backend is a transparency log built on a single Merkle Tree.
This log can grow indefinitely as entries are added, which can present issues over time.
To resolve some of these issues the log can be "sharded" into multiple Merkle Trees.

Why do we shard the log?

Sharding the log allows for:

  • Freezing the current log and rotating signing keys if needed
  • Easier and faster querying for entries from the tree
  • Easier scaling and platform migrations

How does this impact user experience?

It shouldn't!
End users shouldn't notice any difference in their experience.
They can still query via UUID, and Rekor will find the correct entry from whichever shard it's in.
Querying by log index works as well, since log indices are distinct and increase across shards.

More Details

For more details around sharding, see the original design doc!

Note: You'll need to join the [email protected] Google group for access to the doc.

How do I shard the Rekor log?

Sharding the Rekor log will require some downtime in your Rekor service.
This is necessary because you'll need the length of the current shard later on, so new entries can't be added while sharding is in progress.

Follow these steps to shard the log:

  1. Stop all traffic to Rekor so new entries can't be added to the log

  2. Store the tree ID and length of the current active shard:

    bash
    CURRENT_TREE_ID=$(rekor-cli loginfo --format json | jq -r .TreeID)
    CURRENT_SHARD_LENGTH=$(rekor-cli loginfo --format json | jq -r .ActiveTreeSize)
  3. Connect to the production cluster. Port-forward the running trillian_logserver container and run the createtree script.
    This will create a new Merkle Tree which will become the new active shard.

    bash
    kubectl port-forward -n trillian-system deploy/trillian-log-server 8090:8090
    # This is the Tree ID of the new active shard
    NEW_TREE_ID=$(createtree --admin_server localhost:8090)

    Note: Sigstore Helm Charts use port 8091 for gRPC

  4. Update the Rekor sharding-config ConfigMap with details of the inactive shard:

    bash
    kubectl edit configmap sharding-config -n rekor-system

    Append the following onto the sharding-config.yaml key (it will be empty if this is the first shard):

    yaml
    - treeID: $CURRENT_TREE_ID
      treeLength: $CURRENT_SHARD_LENGTH
  5. In your rekor-server Deployment, update the --trillian_log_server.tlog_id flag to point to the new Tree ID.

    bash
    "--trillian_log_server.tlog_id=$NEW_TREE_ID",
  6. Redeploy Rekor to the cluster with these changes.

  7. Restart traffic to your Rekor service.

  8. Congratulations, you've successfully sharded the log!

Identifier Definitions: EntryID, UUID, LogID, Log Index

An EntryID is the unique identifier for an artifact in Rekor. It is made up of two parts, the TreeID and UUID:

EntryID = TreeID (8 byte hex) + UUID (32 byte hex)

The TreeID refers to the specific trillian tree (also known as log or shard) where the artifact can be found. Rekor uses Trillian to implement each transparency log.

The UUID refers to the specific artifact within a specified tree.

The LogIndex of an artifact identifies the index or order in which the artifact was entered into a specific tree.


File: content/en/logging/sign-upload.md


type: docs category: Transparency Log title: Signing and Uploading Other Types weight: 1835

This documentation contains information on how to sign and upload data in different [pluggable types]({{< relref "logging/pluggable-types">}}).

The following are covered:

Minisign

Create a keypair with something like:

console
$ minisign -G
Please enter a password to protect the secret key.

Password:
Password (one more time):
Deriving a key from the password in order to encrypt the secret key... done

The secret key was saved as /Users/dlorenc/.minisign/minisign.key - Keep it secret!
The public key was saved as minisign.pub - That one can be public.

Files signed using this key pair can be verified with the following command:

minisign -Vm <file> -P RWSzQI7+S6M0c4yReOwcDZ2petL8pAZsrNfkdyqr0V7j/HGafpjdKZQm

Sign a file:

console
$ minisign -S -m README.md
Password:
Deriving a key from the password and decrypting the secret key... done

Upload to Rekor:

console
$ rekor-cli upload --artifact README.md --signature README.md.minisig --pki-format=minisign --public-key=minisign.pub
Created entry at index 5895, available at: https://rekor.sigstore.dev/api/v1/log/entries/008bfbbaa8f473a0b17cba5f8078d2c08410bca55f01d2ec71860795ef823b36

Look at the entry with:

console
$ ./rekor-cli get --uuid=008bfbbaa8f473a0b17cba5f8078d2c08410bca55f01d2ec71860795ef823b36
LogID: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
Index: 5895
IntegratedTime: 2021-07-14T01:39:50Z
UUID: 008bfbbaa8f473a0b17cba5f8078d2c08410bca55f01d2ec71860795ef823b36
Body: {
  "RekordObj": {
    "data": {
      "hash": {
        "algorithm": "sha256",
        "value": "3d80236772ca7c5405e398a4d685e715859260a8733070b86de7322e233c68d2"
      }
    },
    "signature": {
      "content": "dW50cnVzdGVkIGNvbW1lbnQ6ClJXU3pRSTcrUzZNMGMrNUcxbVZzcmw2dmgvYi91VjlxclJySWpxd21abDFKYjZhTGJ2U1NWUzdObDNvUmpVTUdHUWpLVlEyd2JnMnJxNDZxdDdPTHE3L1c3Z2liMlo5Rzh3az0=",
      "format": "minisign",
      "publicKey": {
        "content": "akpGNDdCd05uYWw2MHZ5a0JteXMxK1IzS3F2Ulh1UDhjWnArbU4wcGxDWT0="
      }
    }
  }
}

SSH

Generate a keypair with:

console
$ ssh-keygen -C [email protected] -t ed25519 -f id_ed25519
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in id_ed25519.
Your public key has been saved in id_ed25519.pub.
The key fingerprint is:
SHA256:73u0etmm2h7BehcLbjrwXqXe193k5R5Uz0Lnl83nTt4 [email protected]
The key's randomart image is:
+--[ED25519 256]--+
|                 |
|                 |
|              . o|
|           . . ==|
|        S   + +oO|
|        .. o.=.==|
|         oo.B+o=B|
|         .oB=+o+X|
|         .BO=o.oE|
+----[SHA256]-----+

Sign a file with:

console
$ ssh-keygen -Y sign -n file -f id_ed25519 README.md
Enter passphrase:
Signing file README.md
Write signature to README.md.sig

Upload it to Rekor with:

console
$ rekor-cli upload --artifact README.md --signature README.md.sig --pki-format=ssh --public-key=id_ed25519.pub
Created entry at index 5896, available at: https://rekor.sigstore.dev/api/v1/log/entries/0e81b4d9299e2609e45b5c453a4c0e7820ac74e02c4935a8b830d104632fd2d

Look at the entry with:

console
$ rekor-cli get --uuid=0e81b4d9299e2609e45b5c453a4c0e7820ac74e02c4935a8b830d104632fd2d1
LogID: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
Index: 5896
IntegratedTime: 2021-07-14T01:45:06Z
UUID: 0e81b4d9299e2609e45b5c453a4c0e7820ac74e02c4935a8b830d104632fd2d1
Body: {
  "RekordObj": {
    "data": {
      "hash": {
        "algorithm": "sha256",
        "value": "3d80236772ca7c5405e398a4d685e715859260a8733070b86de7322e233c68d2"
      }
    },
    "signature": {
      "content": "LS0t...",
      "format": "ssh",
      "publicKey": {
        "content": "c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUkrc1RWNmxiVVQ2R3pZY2ZUTElKc1FvbDltZTAxOGdNTmc3NHV5T2UrMjUK"
      }
    }
  }
}

PKIX/X509

Generate a keypair with:

console
$ openssl ecparam -genkey -name prime256v1 > ec_private.pem
$ openssl ec -in ec_private.pem -pubout > ec_public.pem
read EC key
writing EC key

Sign the file with:

console
openssl dgst -sha256 -sign ec_private.pem -out README.md.sig README.md

Upload it to Rekor with:

console
$ ./rekor-cli upload --artifact README.md --signature README.md.sig --pki-format=x509 --public-key=ec_public.pem
Created entry at index 5897, available at: https://rekor.sigstore.dev/api/v1/log/entries/31a51c1bc20da83b66b2f24899184b85dbf8261c2de8571479165619ad87cd5d

View the entry with:

console
$ rekor-cli get --uuid=31a51c1bc20da83b66b2f24899184b85dbf8261c2de8571479165619ad87cd5d
LogID: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d
Index: 5897
IntegratedTime: 2021-07-14T01:49:54Z
UUID: 31a51c1bc20da83b66b2f24899184b85dbf8261c2de8571479165619ad87cd5d
Body: {
  "RekordObj": {
    "data": {
      "hash": {
        "algorithm": "sha256",
        "value": "3d80236772ca7c5405e398a4d685e715859260a8733070b86de7322e233c68d2"
      }
    },
    "signature": {
      "content": "MEUCICwZpVU/3fnWSZkejA8R2j/t5futtl5Co3CDj7k6J6PwAiEA75Cn2txgpg/KjsOitSKsydL3D6cQIf7NQJtsmvsRTRQ=",
      "format": "x509",
      "publicKey": {
        "content": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFYzJKUkJZbS9OQVo5ZHhhUnNWV05mdTcxV3B5TAo2cGx4L1hsZnNVTlM2SmcrWEhEVmpsaVNBNHV2ZEQ4ZW5XdUhNdWQybS9WdEVQaDZYT0M3bjR0aCtnPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg=="
      }
    }
  }
}

RPM

TODO

Alpine

TODO

RPM

TODO

TSR

TODO

TUF

Generate a TUF repository (for example, with the Python reference implementation or go-tuf).

With go-tuf:

console
tuf init
tuf gen-key root
tuf gen-key targets
tuf gen-key snapshot
tuf gen-key timestamp
tuf add path/to/some/target.txt
tuf snapshot
tuf timestamp
tuf commit

You will find the signed metadata in your TUF repository/ directory:

console
$ tree .
.
โ”œโ”€โ”€ keys
โ”‚   โ”œโ”€โ”€ snapshot.json
โ”‚   โ”œโ”€โ”€ targets.json
โ”‚   โ””โ”€โ”€ timestamp.json
โ”œโ”€โ”€ repository
โ”‚   โ”œโ”€โ”€ root.json
โ”‚   โ”œโ”€โ”€ snapshot.json
โ”‚   โ”œโ”€โ”€ targets
โ”‚   โ”‚   โ””โ”€โ”€ foo
โ”‚   โ”‚       โ””โ”€โ”€ bar
โ”‚   โ”‚           โ””โ”€โ”€ baz.txt
โ”‚   โ”œโ”€โ”€ targets.json
โ”‚   โ””โ”€โ”€ timestamp.json
โ””โ”€โ”€ staged

Upload any TUF manifest to Rekor by using the root.json as the public key:

console
$ ./rekor-cli upload --artifact repository/timestamp.json --type tuf --public-key repository/root.json
Created entry at index 0, available at: https://rekor.sigstore.dev/api/v1/log/entries/6ed8fa5e9f0aa31b6cdfd2cc6877692f5afba52edd7ff5774eebfb22228e8847

View the entry with:

console
$ rekor-cli get --uuid=31a51c1bc20da83b66b2f24899184b85dbf8261c2de8571479165619ad87cd5d
LogID: 5c4ceffb024e0d0b50bb9e03bc308ce83a76353f1003f8e57a21c51f74cc1e0e
Index: 0
IntegratedTime: 2021-08-13T19:17:33Z
UUID: 6ed8fa5e9f0aa31b6cdfd2cc6877692f5afba52edd7ff5774eebfb22228e8847
Body: {
  "TufObj": {
    "manifest": {
      "expires": "2021-12-18 13:28:12.99008 -0600 CST",
      "signed": {
        "content": [...]
      },
      "version": 1
    },
    "root": {
      "expires": "2021-12-18 13:28:12.99008 -0600 CST",
      "signed": {
        "content": [...]
      },
      "version": 1
    }
  }
}

File: content/en/logging/verify-release.md


type: docs category: Transparency Log title: Verifying Binaries weight: 1840

๐Ÿ““ We will refine this process over time to be more streamlined with a higher consensus threshold
as well as an implementation of a TUF style policy. For now this is quite a
multi step process. We will also deep dive a fair amount here, as its a good opporuntity to pull the covers aside
and see how this all works.

Rekor releases are currently signed and verified using Fulcio OpenID Connect based on short lived signing certificates.

Rekor release signing artifacts are also stored within the public Rekor instance.

Here we will show you how to verify a release, but also take the opportunity to dig down into Sigstore's signing implementation and process.

How to verify a release

Head over to the release page and select the correct release for your systems architecture. Alongside downloading the main binary, also download the signature and signing certificate from the same release.

For example, with binary rekor-cli-linux-amd64, also retrieve rekor-cli-linux-amd64_cert.pem and rekor-cli-linux-amd64_signature.sig.

  • rekor-cli-linux-amd64: The binary itself.
  • rekor-cli-linux-amd64_cert.pem: The signing certificate. This is an X509 certificate generated by the Sigstore root CA, with the email of a project maintainer embedded as a X509v3 Subject Alternative Name. This provides a guarantee that the binary was signed by the individual with access to that account (the email comes from an OpenID provider). In turn, this information is recorded into the transparency log so that the account can be monitored for misuse or compromise.
  • rekor-cli-linux-amd64_signature.sig: This is the signature generated as a result of the signing event.

Basic verify

With the above three files, we can now perform a rudimentary verification.

We grab the public key from the signing cert:

sh
openssl x509 -pubkey -noout -in rekor-cli-linux-amd64_cert.pem > rekor-cli-linux-amd64_cert_public.pem

And then we verify:

sh
$ openssl dgst -sha256 -verify rekor-cli-linux-amd64_cert_public.pem -signature rekor-cli-linux-amd64_signature.sig rekor-cli-linux-amd64
Verified OK

Verify the certificate chain

We should check the trust chain against Sigstore's Root CA.

The root CA for Fulcio is currently:

bash
-----BEGIN CERTIFICATE-----
MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq
MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx
MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu
ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy
A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas
taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm
MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE
FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u
Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx
Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup
Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==
-----END CERTIFICATE-----

Save this locally to your machine as fulcio-root.pem

๐Ÿ““ We are looking at leveraging other trust stores for our Root CA, so consider getting the root CA from here, a temporary approach.

Let's now validate the certificate chain:

sh
$ openssl verify -verbose -no_check_time -CAfile fulcio-root.pem rekor-cli-linux-amd64_cert.pem
rekor-cli-linux-amd64_cert.pem: OK

๐Ÿ““ We use -no_check_time as Fulcio certificates are short-lived (so they always will be expired by design!)

Verify the signing identity

However, how do we know we can trust that public key is from a maintainer at Sigstore?

Let's look at mapping this to an identity:

sh
$ openssl x509 -in rekor-cli-linux-amd64_cert.pem -noout -text |grep email
email:[email protected]

OK, so we can see that a Fulcio-generated certificate, with a chain to the root certificate has the email identity of a Sigstore maintainer (in this instance, our own release manager the awesome Carlos).

Verify the entry is in the transparency log

On the release page you will see some URLs, these are the Rekor entries of the signing events.

This is the link for the binary and signing materials we have been working with throughout this guide

https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33

Let's dig into this:

sh
$ curl -X GET "https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33"  | jq

{
  "b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33": {
    "attestation": {},
    "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJzcGVjIjp7ImRhdGEiOnsiaGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6ImNlOWE3YzgyZjMyMTk0OTk1ODg4NzU4Y2YxMDdlZjBjYzUyZTBiOGNkY2U3M2I0MjQwNjU4ZWU5ZTczNzgzY2IifX0sInNpZ25hdHVyZSI6eyJjb250ZW50IjoiTUdVQ01EM29LemdzR25QQWtKRVhlZ0RJc2RsaDRCRkNRYk02am5nNFN5M2F4WS8rMnRsSzk3b2UvQ2t4YWJUMVpYVXFDQUl4QUpEcSt6TGZSWlpFSkQ1RHZhS2hGRXUrSm0rakQ0VVhjM0NhWnAyTVNhamlyYWxtdGFsQTZmU0dDWGp3R2ZVek93PT0iLCJmb3JtYXQiOiJ4NTA5IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VOcmFrTkRRV2hwWjBGM1NVSkJaMGxWUVUwckswZFlSRk41YlVOUFNXODJZbXhNTUc1RVpuZ3hiMjFuZDBObldVbExiMXBKZW1vd1JVRjNUWGNLUzJwRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5Va1YzUkhkWlJGWlJVVVJGZDJoNllWZGtlbVJIT1hsYVZFRmxSbmN3ZVFwTlZFRXpUV3BuZDA5RVRUTk9SRXBoUm5jd2VVMVVRVE5OYW1kM1QwUlZNMDVFUm1GTlFVRjNaR3BCVVVKblkzRm9hMnBQVUZGSlFrSm5WWEpuVVZGQkNrbG5UbWxCUVZKak1ETXJVVTR2VEhCck9HcHFVRlF3VG1WNWEwMXVjbTltTW5wWlVrSnhObTA1ZWk5VE1YaFJTemR1Wm5aaFUzZ3JSalVyVEV0d04zZ0tSMkV4YkhZMlNXTnZSWGR3VUhBMk1VZHNZbmQ1UzBWUVZXSkxkekpyWW5KeVJWcFBNbmhLVjNreGIwVkVVSEJZTWxKcWNUQllTMFJaY0VGNVppOW1Rd295WnpKalNuVnRhbWRuUlc1TlNVbENTWHBCVDBKblRsWklVVGhDUVdZNFJVSkJUVU5DTkVGM1JYZFpSRlpTTUd4Q1FYZDNRMmRaU1V0M1dVSkNVVlZJQ2tGM1RYZEVRVmxFVmxJd1ZFRlJTQzlDUVVsM1FVUkJaRUpuVGxaSVVUUkZSbWRSVlRSQlVEaHRUa0k0ZWpoU1pGSnlUVlZMWjFBMk1tMHhVRkVyZDNjS1NIZFpSRlpTTUdwQ1FtZDNSbTlCVlhsTlZXUkJSVWRoU2tOcmVWVlRWSEpFWVRWTE4xVnZSekFyZDNkbldUQkhRME56UjBGUlZVWkNkMFZDUWtsSFFRcE5TRFIzWmtGWlNVdDNXVUpDVVZWSVRVRkxSMk5IYURCa1NFRTJUSGs1ZDJOdGJESlpXRkpzV1RKRmRGa3lPWFZrUjFaMVpFTXdNazFFVG0xYVZHUnNDazU1TUhkTlJFRjNURlJKZVUxcVkzUlpiVmt6VGxNeGJVNUhXVEZhVkdkM1drUkpOVTVVVVhWak0xSjJZMjFHYmxwVE5XNWlNamx1WWtkV2FHTkhiSG9LVEcxT2RtSlRPV3BaVkUweVdWUkdiRTlVV1hsT1JFcHBUMWRhYWxscVJUQk9hVGxxV1ZNMWFtTnVVWGRJWjFsRVZsSXdVa0ZSU0M5Q1FsRjNSVzlGVVFwWk0xSm9Xa2RXTVZGSFpIUlpWMnh6VEcxT2RtSlVRVXRDWjJkeGFHdHFUMUJSVVVSQmQwNXZRVVJDYkVGcVJVRTNUVEp3U3poUlVGUnJTR3MxYnpaMENtZG5hbXBaZGpCTFYxQlVhalJLVVRBd1UzUmpSMHhxYTFnM1NVMWlOQzlIZFhwWVJrUTRjelpET0VkM05tcHdNRUZxUVcxWGEySlJPVFZzTXpsblVHUUtSMnBqVWpCU1FVUmFUMGRZYjBOUFFVUndPRTVsU3poQkwyZEtkV2RuUjBaSU5IWllaMmwxT0RKc1FtNU1PRVpTYzA5alBRb3RMUzB0TFVWT1JDQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENnPT0ifX19LCJraW5kIjoicmVrb3JkIn0=",
    "integratedTime": 1627461494,
    "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d",
    "logIndex": 25579,
    "verification": {
      "inclusionProof": {
        "hashes": [
          "779627efafc2601b0b5c4755d1aa27eb3cf8c1f034960ccc1038b9556b1d78bb",
          "892fffd41824856e3279fb815cdedd28fc76722985e508f6ffdf5af5684f0d84",
          "24259982c90f0e2e8a051c06f4cda83fb7f06c3e47b1307d5bc3e50a625b3dcb",
          "a5d5a5841e65786e0718db2f43d909ff92fbfa19bc90bc3187fc143e7af2eb29",
          "2cba9779511cd8c964ac59e4763ecd5257aa67695b20bfbc957341e326848b60",
          "b269aa60e284ce1f866f5c7abd9da16d8e29bf9ab069c66ce91cfe8d6a852458",
          "8af1c7cd9d0a691984963b643c572c560cee08fe38083e2013763df5131e63b3",
          "e86d56509d6b149df6bf2389e066a4b21516f5a13540b8ef52c790b8ed70efe2",
          "04cfd843e6ee05e78eee3229a1b547a4776a81e651888c09bdbfde866ac38d97",
          "339bd5b9f48f7ecf1116f0b0ec9f9eeb95b84f3d53f27b8081e56facbcd71548",
          "74c9aba66c2704b143e33c3ebc5f12a17be5bda8a8eba055bd471ed57a6fd0b4",
          "43a291f5a7301f1b18bbf76829435251a9189c477aa52633fef3f589e3d47446",
          "73b38c2b7d6eac887dc9f028500b67ede8655f136bc75354f8bfe94515327513",
          "4a33ede5d1c6be306c0362fbee2e9f692522327b4cae78165f810f7dcfaa8dd0"
        ],
        "logIndex": 25579,
        "rootHash": "9ecebec82edb290e54f8b45702b05b94efe1e2a7848d5b5aa2c4bbe188995ca2",
        "treeSize": 27024
      },
      "signedEntryTimestamp": "MEUCIHPlKC5Hh34bdjBrqk++9yuznsFOyolHsoulTTxjM+hGAiEA3MEf6d2zsxFJaiZsGCHIhN8Yvc+NZMmUolIBqUGCps0="
    }
  }
}

Let's focus on the body and decode it from base64:

sh
$ curl -X GET "https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33"  | jq -r '.[].body'| base64 -d | jq -r '.[]'

{
  "data": {
    "hash": {
      "algorithm": "sha256",
      "value": "ce9a7c82f32194995888758cf107ef0cc52e0b8cdce73b4240658ee9e73783cb"
    }
  },
  "signature": {
    "content": "MGUCMD3oKzgsGnPAkJEXegDIsdlh4BFCQbM6jng4Sy3axY/+2tlK97oe/CkxabT1ZXUqCAIxAJDq+zLfRZZEJD5DvaKhFEu+Jm+jD4UXc3CaZp2MSajiralmtalA6fSGCXjwGfUzOw==",
    "format": "x509",
    "publicKey": {
      "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNrakNDQWhpZ0F3SUJBZ0lVQU0rK0dYRFN5bUNPSW82YmxMMG5EZngxb21nd0NnWUlLb1pJemowRUF3TXcKS2pFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUkV3RHdZRFZRUURFd2h6YVdkemRHOXlaVEFlRncweQpNVEEzTWpnd09ETTNOREphRncweU1UQTNNamd3T0RVM05ERmFNQUF3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBCklnTmlBQVJjMDMrUU4vTHBrOGpqUFQwTmV5a01ucm9mMnpZUkJxNm05ei9TMXhRSzduZnZhU3grRjUrTEtwN3gKR2ExbHY2SWNvRXdwUHA2MUdsYnd5S0VQVWJLdzJrYnJyRVpPMnhKV3kxb0VEUHBYMlJqcTBYS0RZcEF5Zi9mQwoyZzJjSnVtamdnRW5NSUlCSXpBT0JnTlZIUThCQWY4RUJBTUNCNEF3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVICkF3TXdEQVlEVlIwVEFRSC9CQUl3QURBZEJnTlZIUTRFRmdRVTRBUDhtTkI4ejhSZFJyTVVLZ1A2Mm0xUFErd3cKSHdZRFZSMGpCQmd3Rm9BVXlNVWRBRUdhSkNreVVTVHJEYTVLN1VvRzArd3dnWTBHQ0NzR0FRVUZCd0VCQklHQQpNSDR3ZkFZSUt3WUJCUVVITUFLR2NHaDBkSEE2THk5d2NtbDJZWFJsWTJFdFkyOXVkR1Z1ZEMwMk1ETm1aVGRsCk55MHdNREF3TFRJeU1qY3RZbVkzTlMxbU5HWTFaVGd3WkRJNU5UUXVjM1J2Y21GblpTNW5iMjluYkdWaGNHbHoKTG1OdmJTOWpZVE0yWVRGbE9UWXlOREppT1daallqRTBOaTlqWVM1amNuUXdIZ1lEVlIwUkFRSC9CQlF3RW9FUQpZM1JoWkdWMVFHZHRZV2xzTG1OdmJUQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqRUE3TTJwSzhRUFRrSGs1bzZ0CmdnampZdjBLV1BUajRKUTAwU3RjR0xqa1g3SU1iNC9HdXpYRkQ4czZDOEd3NmpwMEFqQW1Xa2JROTVsMzlnUGQKR2pjUjBSQURaT0dYb0NPQURwOE5lSzhBL2dKdWdnR0ZINHZYZ2l1ODJsQm5MOEZSc09jPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
    }
  }
}

Ok, now you can see the digest of the artifact that was signed:

sh
$ sha256sum rekor-cli-linux-amd64
ce9a7c82f32194995888758cf107ef0cc52e0b8cdce73b4240658ee9e73783cb  rekor-cli-linux-amd64

We can then grab the signing certificate:

sh
echo LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNrakNDQWhpZ0F3SUJBZ0lVQU0rK0dYRFN5bUNPSW82YmxMMG5EZngxb21nd0NnWUlLb1pJemowRUF3TXcKS2pFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUkV3RHdZRFZRUURFd2h6YVdkemRHOXlaVEFlRncweQpNVEEzTWpnd09ETTNOREphRncweU1UQTNNamd3T0RVM05ERmFNQUF3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBCklnTmlBQVJjMDMrUU4vTHBrOGpqUFQwTmV5a01ucm9mMnpZUkJxNm05ei9TMXhRSzduZnZhU3grRjUrTEtwN3gKR2ExbHY2SWNvRXdwUHA2MUdsYnd5S0VQVWJLdzJrYnJyRVpPMnhKV3kxb0VEUHBYMlJqcTBYS0RZcEF5Zi9mQwoyZzJjSnVtamdnRW5NSUlCSXpBT0JnTlZIUThCQWY4RUJBTUNCNEF3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVICkF3TXdEQVlEVlIwVEFRSC9CQUl3QURBZEJnTlZIUTRFRmdRVTRBUDhtTkI4ejhSZFJyTVVLZ1A2Mm0xUFErd3cKSHdZRFZSMGpCQmd3Rm9BVXlNVWRBRUdhSkNreVVTVHJEYTVLN1VvRzArd3dnWTBHQ0NzR0FRVUZCd0VCQklHQQpNSDR3ZkFZSUt3WUJCUVVITUFLR2NHaDBkSEE2THk5d2NtbDJZWFJsWTJFdFkyOXVkR1Z1ZEMwMk1ETm1aVGRsCk55MHdNREF3TFRJeU1qY3RZbVkzTlMxbU5HWTFaVGd3WkRJNU5UUXVjM1J2Y21GblpTNW5iMjluYkdWaGNHbHoKTG1OdmJTOWpZVE0yWVRGbE9UWXlOREppT1daallqRTBOaTlqWVM1amNuUXdIZ1lEVlIwUkFRSC9CQlF3RW9FUQpZM1JoWkdWMVFHZHRZV2xzTG1OdmJUQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqRUE3TTJwSzhRUFRrSGs1bzZ0CmdnampZdjBLV1BUajRKUTAwU3RjR0xqa1g3SU1iNC9HdXpYRkQ4czZDOEd3NmpwMEFqQW1Xa2JROTVsMzlnUGQKR2pjUjBSQURaT0dYb0NPQURwOE5lSzhBL2dKdWdnR0ZINHZYZ2l1ODJsQm5MOEZSc09jPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==| base64 -d > tlog_signing_cert.pem```

Which is, of course, the same as our signing certificate:

sh
diff tlog_signing_cert.pem rekor-cli-linux-amd64_cert.pem

And the signature can also be retrieved:

sh
echo MGUCMD3oKzgsGnPAkJEXegDIsdlh4BFCQbM6jng4Sy3axY/+2tlK97oe/CkxabT1ZXUqCAIxAJDq+zLfRZZEJD5DvaKhFEu+Jm+jD4UXc3CaZp2MSajiralmtalA6fSGCXjwGfUzOw== | base64 -d > tlog_signing_sig.sig

$ diff tlog_signing_sig.sig rekor-cli-linux-amd64_signature.sig

So we can then do the same verification using just the tlog!

sh
$ openssl x509 -pubkey -noout -in tlog_signing_cert.pem > tlog_signing_cert_public.pem
$ openssl dgst -sha256 -verify tlog_signing_cert_public.pem -signature tlog_signing_sig.sig rekor-cli-linux-amd64
Verified OK

Summarise

So we now know that the binary you downloaded was signed by the individual in control of the OpenID based account.

In turn, this account has 2FA enabled and is monitored for misuse, since records are transparent within the public Rekor transparency log.

There is a lot more we could do well. Using the sha256 digest you could retrieve the signing materials for a release binary, even if you sourced the binary from elsewhere!


File: content/en/language_clients/go.md


type: docs category: Language Clients title: Go weight: 10

sigstore-go is the Go language client library for Sigstore.

sigstore-go is intended as a minimal dependency library for signing and verifying. It's not intended to replace Cosign, which provides a CLI with many features for interacting with Sigstore. Over time, cosign will use sigstore-go for verification.

  • Friendly API for integrating Go code with Sigstore
  • Smaller dependency tree
  • Focuses on newly specified data structures in sigstore/protobuf-specs
  • Perfect for simple signing and verififcation tasks

sigstore-go is currently in beta.

Features

  • Signing and verification of Sigstore bundles
  • Verification of raw Sigstore signatures
  • Signing and verifying with a Timestamp Authority (TSA)
  • Online and offline signing and verifying with Rekor (Artifact Transparency Log)
  • Structured verification results including certificate metadata
  • TUF support
  • Verification support for custom trusted root
  • Basic CLI

Installation

Main CLI installation

sigstore-go requires Go 1.21 or greater. The package is tested with Go 1.23.

To compile/install the CLI, clone sigstore-go and run.

console
make install

Alternatively, you can use go run cmd/sigstore-go/main.go to access the CLI, as show in the example.

Example

CLI example

The following is an example of using the sigstore-go CLI to verify a signature.

console
go run cmd/sigstore-go/main.go \
  -artifact-digest 76176ffa33808b54602c7c35de5c6e9a4deb96066dba6533f50ac234f4f1f4c6b3527515dc17c06fbe2860030f410eee69ea20079bd3a2c6f3dcf3b329b10751 \
  -artifact-digest-algorithm sha512 \
  -expectedIssuer https://token.actions.githubusercontent.com \
  -expectedSAN https://github.com/sigstore/sigstore-js/.github/workflows/release.yml@refs/heads/main \
  examples/bundle-provenance.json
Verification successful!
{
   "version": 20230823,
   "statement": {
      "_type": "https://in-toto.io/Statement/v0.1",
      "predicateType": "https://slsa.dev/provenance/v0.2",
      "subject": ...
    },
    ...
}

Additional examples

Additional examples are available in the project documentation.