Skip to content

Commit

Permalink
refactor verifier workflow
Browse files Browse the repository at this point in the history
Signed-off-by: linus-sun <[email protected]>
  • Loading branch information
linus-sun committed Oct 30, 2024
1 parent c8635a5 commit 4a8fc06
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 49 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/reusable_monitoring.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ on:
required: false
type: number
default: 14
identities:
description: 'multiline yaml of certificate subjects and issuers, key subjects, and fingerprints. For certificates, if no issuers are specified, match any OIDC provider'
config:
description: 'multiline yaml of workflow configuration settings, including rekor server URL, identities including certificate subjects and issuers, key subjects, and fingerprints. For certificates, if no issuers are specified, match any OIDC provider'
required: false
type: string

Expand Down Expand Up @@ -76,7 +76,7 @@ jobs:
run: cat ${{ env.LOG_FILE }}
# Skip on first run
continue-on-error: true
- run: go run ./cmd/verifier --file ${{ env.LOG_FILE }} --once --monitored-values "${{ inputs.identities }}" --user-agent "${{ format('{0}/{1}/{2}', needs.detect-workflow.outputs.repository, needs.detect-workflow.outputs.ref, github.run_id) }}"
- run: go run ./cmd/consistency --file ${{ env.LOG_FILE }} --once --config-string "${{ inputs.config }}" --user-agent "${{ format('{0}/{1}/{2}', needs.detect-workflow.outputs.repository, needs.detect-workflow.outputs.ref, github.run_id) }}"
- name: Upload checkpoint
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
Expand Down
41 changes: 21 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,26 +66,27 @@ jobs:
with:
file_issue: true # Strongly recommended: Files an issue on monitoring failure
artifact_retention_days: 14 # Optional, default is 14: Must be longer than the cron job frequency
identities: |
certIdentities:
- certSubject: user@domain\.com
- certSubject: otheruser@domain\.com
issuers:
- https://accounts\.google\.com
- https://github\.com/login
- certSubject: https://github\.com/actions/starter-workflows/blob/main/\.github/workflows/lint\.yaml@.*
issuers:
- https://token\.actions\.githubusercontent\.com
subjects:
- subject@domain\.com
fingerprints:
- A0B1C2D3E4F5
fulcioExtensions:
build-config-uri:
- https://example.com/owner/repository/build-config.yml
customExtensions:
- objectIdentifier: 1.3.6.1.4.1.57264.1.9
extensionValues: https://github.com/slsa-framework/slsa-github-generator/.github/workflows/[email protected]
config: |
monitoredValues: |
certIdentities:
- certSubject: user@domain\.com
- certSubject: otheruser@domain\.com
issuers:
- https://accounts\.google\.com
- https://github\.com/login
- certSubject: https://github\.com/actions/starter-workflows/blob/main/\.github/workflows/lint\.yaml@.*
issuers:
- https://token\.actions\.githubusercontent\.com
subjects:
- subject@domain\.com
fingerprints:
- A0B1C2D3E4F5
fulcioExtensions:
build-config-uri:
- https://example.com/owner/repository/build-config.yml
customExtensions:
- objectIdentifier: 1.3.6.1.4.1.57264.1.9
extensionValues: https://github.com/slsa-framework/slsa-github-generator/.github/workflows/[email protected]
```

In this example, the monitor will log:
Expand Down
29 changes: 29 additions & 0 deletions cmd/verifier/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Copyright 2024 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"time"

"github.com/sigstore/rekor-monitor/pkg/identity"
)

type ConsistencyCheckConfiguration struct {
ServerURL string `yaml:"serverURL"`
Interval *time.Duration `yaml:"interval"`
OutputIdentitiesFile string `yaml:"outputIdentitiesFile"`
MonitoredValues identity.MonitoredValues `yaml:"monitoredValues"`
}
89 changes: 63 additions & 26 deletions cmd/verifier/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ import (
"flag"
"fmt"
"log"
"os"
"runtime"
"strings"
"time"

"github.com/sigstore/rekor-monitor/pkg/identity"
"github.com/sigstore/rekor-monitor/pkg/rekor"
"github.com/sigstore/rekor/pkg/client"
"gopkg.in/yaml.v3"
"gopkg.in/yaml.v2"

"sigs.k8s.io/release-utils/version"
)
Expand All @@ -44,36 +44,57 @@ const (
// indefinitely to perform consistency check for every time interval that was specified.
func main() {
// Command-line flags that are parameters to the verifier job
serverURL := flag.String("url", publicRekorServerURL, "URL to the rekor server that is to be monitored")
interval := flag.Duration("interval", 5*time.Minute, "Length of interval between each periodical consistency check")
logInfoFile := flag.String("file", logInfoFileName, "Name of the file containing initial merkle tree information")
configFilePath := flag.String("config-file", "", "Name of the file containing the consistency check workflow configuration settings")
configString := flag.String("config-string", "", "Consistency check workflow configuration settings input as a string")
once := flag.Bool("once", false, "Perform consistency check once and exit")
monitoredValsInput := flag.String("monitored-values", "", "yaml of certificate subjects and issuers, key subjects, "+
"and fingerprints. For certificates, if no issuers are specified, match any OIDC provider.")
outputIdentitiesFile := flag.String("output-identities", outputIdentitiesFileName,
"Name of the file containing indices and identities found in the log. Format is \"subject issuer index uuid\"")
logInfoFile := flag.String("file", "", "path to log info file")
userAgentString := flag.String("user-agent", "", "details to include in the user agent string")
flag.Parse()

var monitoredVals identity.MonitoredValues
if err := yaml.Unmarshal([]byte(*monitoredValsInput), &monitoredVals); err != nil {
log.Fatalf("error parsing identities: %v", err)
if *configFilePath == "" && *configString == "" {
log.Fatalf("empty configuration input")
}
for _, certID := range monitoredVals.CertificateIdentities {
if len(certID.Issuers) == 0 {
fmt.Printf("Monitoring certificate subject %s\n", certID.CertSubject)
} else {
fmt.Printf("Monitoring certificate subject %s for issuer(s) %s\n", certID.CertSubject, strings.Join(certID.Issuers, ","))

if *configFilePath != "" && *configString != "" {
log.Fatalf("only input one of --config-file or --config-string")
}

var config ConsistencyCheckConfiguration
if *configString != "" {
if err := yaml.Unmarshal([]byte(*configString), &config); err != nil {
log.Fatalf("error parsing identities: %v", err)
}
}

if *configFilePath != "" {
readConfig, err := os.ReadFile(*configFilePath)
if err != nil {
log.Fatalf("error reading from identity monitor configuration file: %v", err)
}
if err := yaml.Unmarshal([]byte(readConfig), &config); err != nil {
log.Fatalf("error parsing identities: %v", err)
}
}
for _, fp := range monitoredVals.Fingerprints {
fmt.Printf("Monitoring fingerprint %s\n", fp)

if config.ServerURL == "" {
config.ServerURL = publicRekorServerURL
}
for _, sub := range monitoredVals.Subjects {
fmt.Printf("Monitoring subject %s\n", sub)

if config.Interval == nil {
defaultInterval := time.Hour
config.Interval = &defaultInterval
}

rekorClient, err := client.GetRekorClient(*serverURL, client.WithUserAgent(strings.TrimSpace(fmt.Sprintf("rekor-monitor/%s (%s; %s) %s", version.GetVersionInfo().GitVersion, runtime.GOOS, runtime.GOARCH, *userAgentString))))
if config.OutputIdentitiesFile == "" {
config.OutputIdentitiesFile = outputIdentitiesFileName
}

if logInfoFile == nil {
defaultLogInfoFile := logInfoFileName
logInfoFile = &defaultLogInfoFile
}

rekorClient, err := client.GetRekorClient(config.ServerURL, client.WithUserAgent(strings.TrimSpace(fmt.Sprintf("rekor-monitor/%s (%s; %s) %s", version.GetVersionInfo().GitVersion, runtime.GOOS, runtime.GOARCH, *userAgentString))))
if err != nil {
log.Fatalf("getting Rekor client: %v", err)
}
Expand All @@ -83,13 +104,29 @@ func main() {
log.Fatal(err)
}

err = rekor.VerifyConsistencyCheckInputs(interval, logInfoFile, outputIdentitiesFile, once)
err = rekor.VerifyConsistencyCheckInputs(config.Interval, logInfoFile, &config.OutputIdentitiesFile, once)
if err != nil {
log.Fatal(err)
}

err = rekor.RunConsistencyCheck(*interval, rekorClient, verifier, *logInfoFile, monitoredVals, *outputIdentitiesFile, *once)
if err != nil {
log.Fatalf("%v", err)
ticker := time.NewTicker(*config.Interval)
defer ticker.Stop()

// Loop will:
// 1. Fetch latest checkpoint and verify
// 2. If old checkpoint is present, verify consistency proof
// 3. Write latest checkpoint to file

// To get an immediate first tick
for ; ; <-ticker.C {
err = rekor.RunConsistencyCheck(*config.Interval, rekorClient, verifier, *logInfoFile, config.MonitoredValues, config.OutputIdentitiesFile, *once)
if err != nil {
fmt.Fprintf(os.Stderr, "error running consistency check: %v", err)
return
}

if *once {
return
}
}
}

0 comments on commit 4a8fc06

Please sign in to comment.