Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor identity monitoring into separate function #483

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions pkg/identity/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,20 @@ func CreateMonitoredIdentities(inputIdentityEntries []RekorLogEntry, monitoredId

return parsedMonitoredIdentities
}

// MonitoredValuesExist checks if there are monitored values in an input and returns accordingly.
func MonitoredValuesExist(mvs MonitoredValues) bool {
if len(mvs.CertificateIdentities) > 0 {
return true
}
if len(mvs.Fingerprints) > 0 {
return true
}
if len(mvs.OIDMatchers) > 0 {
return true
}
if len(mvs.Subjects) > 0 {
return true
}
return false
}
56 changes: 56 additions & 0 deletions pkg/identity/identity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
package identity

import (
"encoding/asn1"
"reflect"
"sort"
"strings"
"testing"

"github.com/sigstore/rekor-monitor/pkg/fulcio/extensions"
)

// Test RekorLogEntry.String()
Expand Down Expand Up @@ -217,3 +220,56 @@ func TestPrintMonitoredIdentities(t *testing.T) {
t.Errorf("expected parsed monitored identity to equal %s, got %s", expectedParsedMonitoredIdentityOutput, parsedMonitoredIdentityFields)
}
}

func TestMonitoredValuesExist(t *testing.T) {
testCases := map[string]struct {
mvs MonitoredValues
expected bool
}{
"empty case": {
mvs: MonitoredValues{},
expected: false,
},
"fingerprints": {
mvs: MonitoredValues{
Fingerprints: []string{"test fingerprint"},
},
expected: true,
},
"subjects": {
mvs: MonitoredValues{
Subjects: []string{"test subject"},
},
expected: true,
},
"certificate identities": {
mvs: MonitoredValues{
CertificateIdentities: []CertificateIdentity{
{
CertSubject: "test cert subject",
Issuers: []string{"test issuer"},
},
},
},
expected: true,
},
"oid matchers": {
mvs: MonitoredValues{
OIDMatchers: []extensions.OIDMatcher{
{
ObjectIdentifier: asn1.ObjectIdentifier{1},
ExtensionValues: []string{"test extension value"},
},
},
},
expected: true,
},
}
for testCaseName, testCase := range testCases {
result := MonitoredValuesExist(testCase.mvs)
expected := testCase.expected
if result != expected {
t.Errorf("%s failed: expected %t, received %t", testCaseName, result, expected)
}
}
}
41 changes: 40 additions & 1 deletion pkg/rekor/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,24 @@ package rekor

import (
"bytes"
"context"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"errors"
"fmt"
"os"
"regexp"

"github.com/go-openapi/runtime"
"github.com/sigstore/rekor-monitor/pkg/fulcio/extensions"
"github.com/sigstore/rekor-monitor/pkg/identity"
"github.com/sigstore/rekor-monitor/pkg/util/file"
"github.com/sigstore/rekor/pkg/generated/client"
"github.com/sigstore/rekor/pkg/generated/models"
"github.com/sigstore/rekor/pkg/pki"
"github.com/sigstore/rekor/pkg/types"
"github.com/sigstore/rekor/pkg/util"
"github.com/sigstore/sigstore/pkg/cryptoutils"

// required imports to call init methods
Expand Down Expand Up @@ -146,7 +151,7 @@ func MatchedIndices(logEntries []models.LogEntry, mvs identity.MonitoredValues)

// verifyMonitoredValues checks that monitored values are valid
func verifyMonitoredValues(mvs identity.MonitoredValues) error {
if len(mvs.CertificateIdentities) == 0 && len(mvs.Fingerprints) == 0 && len(mvs.Subjects) == 0 && len(mvs.OIDMatchers) == 0 {
if !identity.MonitoredValuesExist(mvs) {
return errors.New("no identities provided to monitor")
}
for _, certID := range mvs.CertificateIdentities {
Expand Down Expand Up @@ -335,3 +340,37 @@ func oidMatchesPolicy(cert *x509.Certificate, oid asn1.ObjectIdentifier, extensi

return false, nil, "", nil
}

// writeIdentitiesBetweenCheckpoints monitors for given identities between two checkpoints and writes any found identities to file.
func writeIdentitiesBetweenCheckpoints(logInfo *models.LogInfo, prevCheckpoint *util.SignedCheckpoint, checkpoint *util.SignedCheckpoint, monitoredValues identity.MonitoredValues, rekorClient *client.Rekor, outputIdentitiesFile *string) error {
// Get log size of inactive shards
totalSize := 0
for _, s := range logInfo.InactiveShards {
totalSize += int(*s.TreeSize)
}
startIndex := int(prevCheckpoint.Size) + totalSize - 1 //nolint: gosec // G115, log will never be large enough to overflow
endIndex := int(checkpoint.Size) + totalSize - 1 //nolint: gosec // G115

// Search for identities in the log range
if identity.MonitoredValuesExist(monitoredValues) {
entries, err := GetEntriesByIndexRange(context.Background(), rekorClient, startIndex, endIndex)
if err != nil {
return fmt.Errorf("error getting entries by index range: %v", err)
}
idEntries, err := MatchedIndices(entries, monitoredValues)
if err != nil {
return fmt.Errorf("error finding log indices: %v", err)
}

if len(idEntries) > 0 {
for _, idEntry := range idEntries {
fmt.Fprintf(os.Stderr, "Found %s\n", idEntry.String())

if err := file.WriteIdentity(*outputIdentitiesFile, idEntry); err != nil {
return fmt.Errorf("failed to write entry: %v", err)
}
}
}
}
return nil
}
35 changes: 6 additions & 29 deletions pkg/rekor/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,39 +118,16 @@ func RunConsistencyCheck(interval *time.Duration, rekorClient *client.Rekor, ver
// Write if there was no stored checkpoint or the sizes differ
if prevCheckpoint == nil || prevCheckpoint.Size != checkpoint.Size {
if err := file.WriteCheckpoint(checkpoint, *logInfoFile); err != nil {
return fmt.Errorf("failed to write checkpoint: %v", err)
// TODO: Once the consistency check and identity search are split into separate tasks, this should hard fail.
// Temporarily skipping this to allow this job to succeed, remediating the issue noted here: https://github.com/sigstore/rekor-monitor/issues/271
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue is more about handling failures for in writeIdentitiesBetweenCheckpoints where processing a single entry throws an error. Gracefully handling this would mean skipping the index and logging it somewhere.
This has to be fixed deeper in the stack, around MatchedIndices where we return both successfully matched indices and failures.

fmt.Fprintf(os.Stderr, "failed to write checkpoint: %v", err)
}
}

if prevCheckpoint != nil && prevCheckpoint.Size != checkpoint.Size {
// Get log size of inactive shards
totalSize := 0
for _, s := range logInfo.InactiveShards {
totalSize += int(*s.TreeSize)
}
startIndex := int(prevCheckpoint.Size) + totalSize - 1 //nolint: gosec // G115, log will never be large enough to overflow
endIndex := int(checkpoint.Size) + totalSize - 1 //nolint: gosec // G115

// Search for identities in the log range
if len(mvs.CertificateIdentities) > 0 || len(mvs.Fingerprints) > 0 || len(mvs.Subjects) > 0 {
entries, err := GetEntriesByIndexRange(context.Background(), rekorClient, startIndex, endIndex)
if err != nil {
return fmt.Errorf("error getting entries by index range: %v", err)
}
idEntries, err := MatchedIndices(entries, mvs)
if err != nil {
return fmt.Errorf("error finding log indices: %v", err)
}

if len(idEntries) > 0 {
for _, idEntry := range idEntries {
fmt.Fprintf(os.Stderr, "Found %s\n", idEntry.String())

if err := file.WriteIdentity(*outputIdentitiesFile, idEntry); err != nil {
return fmt.Errorf("failed to write entry: %v", err)
}
}
}
err = writeIdentitiesBetweenCheckpoints(logInfo, prevCheckpoint, checkpoint, mvs, rekorClient, outputIdentitiesFile)
if err != nil {
return fmt.Errorf("failed to monitor identities: %v", err)
}
}

Expand Down
Loading