Add --insecure to config fetch-measurement (#1879)

* cli: add --insecure to fetch-measurements

* cli: rename fake to stub

* ci: upload measurements for debug images

* fix cli docs
This commit is contained in:
3u13r 2023-06-06 10:32:22 +02:00 committed by GitHub
parent f7f11c32f8
commit 7c07e3be18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 85 additions and 77 deletions

View file

@ -36,6 +36,7 @@ func newConfigFetchMeasurementsCmd() *cobra.Command {
}
cmd.Flags().StringP("url", "u", "", "alternative URL to fetch measurements from")
cmd.Flags().StringP("signature-url", "s", "", "alternative URL to fetch measurements' signature from")
cmd.Flags().Bool("insecure", false, "skip the measurement signature verification")
return cmd
}
@ -43,6 +44,7 @@ func newConfigFetchMeasurementsCmd() *cobra.Command {
type fetchMeasurementsFlags struct {
measurementsURL *url.URL
signatureURL *url.URL
insecure bool
configPath string
force bool
}
@ -115,25 +117,44 @@ func (cfm *configFetchMeasurementsCmd) configFetchMeasurements(
}
var fetchedMeasurements measurements.M
hash, err := fetchedMeasurements.FetchAndVerify(
ctx, client, cosign,
flags.measurementsURL,
flags.signatureURL,
imageVersion,
conf.GetProvider(),
conf.GetAttestationConfig().GetVariant(),
)
if err != nil {
return err
var hash string
if flags.insecure {
if err := fetchedMeasurements.FetchNoVerify(
ctx,
client,
flags.measurementsURL,
imageVersion,
conf.GetProvider(),
conf.GetAttestationConfig().GetVariant(),
); err != nil {
return fmt.Errorf("fetching measurements without verification: %w", err)
}
cfm.log.Debugf("Fetched measurements without verification")
} else {
hash, err = fetchedMeasurements.FetchAndVerify(
ctx,
client,
cosign,
flags.measurementsURL,
flags.signatureURL,
imageVersion,
conf.GetProvider(),
conf.GetAttestationConfig().GetVariant(),
)
if err != nil {
return fmt.Errorf("fetching and verifying measurements: %w", err)
}
cfm.log.Debugf("Fetched and verified measurements, hash is %s", hash)
if err := sigstore.VerifyWithRekor(cmd.Context(), imageVersion, rekor, hash); err != nil {
cmd.PrintErrf("Ignoring Rekor related error: %v\n", err)
cmd.PrintErrln("Make sure the downloaded measurements are trustworthy!")
}
cfm.log.Debugf("Verified measurements with Rekor")
}
cfm.log.Debugf("Fetched and verified measurements, hash is %s", hash)
if err := sigstore.VerifyWithRekor(cmd.Context(), imageVersion, rekor, hash); err != nil {
cmd.PrintErrf("Ignoring Rekor related error: %v\n", err)
cmd.PrintErrln("Make sure the downloaded measurements are trustworthy!")
}
cfm.log.Debugf("Verified measurements with Rekor, updating measurements in configuration")
cfm.log.Debugf("Updating measurements in configuration")
conf.UpdateMeasurements(fetchedMeasurements)
if err := fileHandler.WriteYAML(flags.configPath, conf, file.OptOverwrite); err != nil {
return err
@ -170,6 +191,12 @@ func (cfm *configFetchMeasurementsCmd) parseFetchMeasurementsFlags(cmd *cobra.Co
}
cfm.log.Debugf("Parsed measurements signature URL as %v", measurementsSignatureURL)
insecure, err := cmd.Flags().GetBool("insecure")
if err != nil {
return &fetchMeasurementsFlags{}, fmt.Errorf("parsing insecure argument: %w", err)
}
cfm.log.Debugf("Insecure flag is %v", insecure)
config, err := cmd.Flags().GetString("config")
if err != nil {
return &fetchMeasurementsFlags{}, fmt.Errorf("parsing config path argument: %w", err)
@ -184,6 +211,7 @@ func (cfm *configFetchMeasurementsCmd) parseFetchMeasurementsFlags(cmd *cobra.Co
return &fetchMeasurementsFlags{
measurementsURL: measurementsURL,
signatureURL: measurementsSignatureURL,
insecure: insecure,
configPath: config,
force: force,
}, nil

View file

@ -9,11 +9,11 @@ package cmd
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"testing"
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfig"
@ -233,31 +233,39 @@ func TestConfigFetchMeasurements(t *testing.T) {
})
testCases := map[string]struct {
cosign cosignVerifier
rekor rekorVerifier
wantErr bool
cosign cosignVerifier
rekor rekorVerifier
insecureFlag bool
wantErr bool
}{
"success": {
cosign: &stubCosignVerifier{},
rekor: singleUUIDVerifier(),
},
"success without cosign": {
insecureFlag: true,
cosign: &stubCosignVerifier{
verifyError: assert.AnError,
},
rekor: singleUUIDVerifier(),
},
"failing search should not result in error": {
cosign: &stubCosignVerifier{},
rekor: &stubRekorVerifier{
SearchByHashUUIDs: []string{},
SearchByHashError: errors.New("some error"),
SearchByHashError: assert.AnError,
},
},
"failing verify should not result in error": {
cosign: &stubCosignVerifier{},
rekor: &stubRekorVerifier{
SearchByHashUUIDs: []string{"11111111111111111111111111111111111111111111111111111111111111111111111111111111"},
VerifyEntryError: errors.New("some error"),
VerifyEntryError: assert.AnError,
},
},
"signature verification failure": {
cosign: &stubCosignVerifier{
verifyError: errors.New("some error"),
verifyError: assert.AnError,
},
rekor: singleUUIDVerifier(),
wantErr: true,
@ -272,6 +280,7 @@ func TestConfigFetchMeasurements(t *testing.T) {
cmd := newConfigFetchMeasurementsCmd()
cmd.Flags().String("config", constants.ConfigFilename, "") // register persistent flag manually
cmd.Flags().Bool("force", true, "") // register persistent flag manually
require.NoError(cmd.Flags().Set("insecure", strconv.FormatBool(tc.insecureFlag)))
fileHandler := file.NewHandler(afero.NewMemMapFs())
gcpConfig := defaultConfigWithExpectedMeasurements(t, config.Default(), cloudprovider.GCP)
@ -281,7 +290,7 @@ func TestConfigFetchMeasurements(t *testing.T) {
require.NoError(err)
cfm := &configFetchMeasurementsCmd{canFetchMeasurements: true, log: logger.NewTest(t)}
err = cfm.configFetchMeasurements(cmd, tc.cosign, tc.rekor, fileHandler, fakeAttestationFetcher{}, client)
err = cfm.configFetchMeasurements(cmd, tc.cosign, tc.rekor, fileHandler, stubAttestationFetcher{}, client)
if tc.wantErr {
assert.Error(err)
return
@ -291,21 +300,21 @@ func TestConfigFetchMeasurements(t *testing.T) {
}
}
type fakeAttestationFetcher struct{}
type stubAttestationFetcher struct{}
func (f fakeAttestationFetcher) FetchAzureSEVSNPVersionList(_ context.Context, _ attestationconfig.AzureSEVSNPVersionList) (attestationconfig.AzureSEVSNPVersionList, error) {
func (f stubAttestationFetcher) FetchAzureSEVSNPVersionList(_ context.Context, _ attestationconfig.AzureSEVSNPVersionList) (attestationconfig.AzureSEVSNPVersionList, error) {
return attestationconfig.AzureSEVSNPVersionList(
[]string{},
), nil
}
func (f fakeAttestationFetcher) FetchAzureSEVSNPVersion(_ context.Context, _ attestationconfig.AzureSEVSNPVersionAPI) (attestationconfig.AzureSEVSNPVersionAPI, error) {
func (f stubAttestationFetcher) FetchAzureSEVSNPVersion(_ context.Context, _ attestationconfig.AzureSEVSNPVersionAPI) (attestationconfig.AzureSEVSNPVersionAPI, error) {
return attestationconfig.AzureSEVSNPVersionAPI{
AzureSEVSNPVersion: testCfg,
}, nil
}
func (f fakeAttestationFetcher) FetchAzureSEVSNPVersionLatest(_ context.Context) (attestationconfig.AzureSEVSNPVersionAPI, error) {
func (f stubAttestationFetcher) FetchAzureSEVSNPVersionLatest(_ context.Context) (attestationconfig.AzureSEVSNPVersionAPI, error) {
return attestationconfig.AzureSEVSNPVersionAPI{
AzureSEVSNPVersion: testCfg,
}, nil

View file

@ -202,7 +202,7 @@ func TestCreate(t *testing.T) {
fileHandler := file.NewHandler(tc.setupFs(require, tc.provider))
c := &createCmd{log: logger.NewTest(t)}
err := c.create(cmd, tc.creator, fileHandler, &nopSpinner{}, fakeAttestationFetcher{})
err := c.create(cmd, tc.creator, fileHandler, &nopSpinner{}, stubAttestationFetcher{})
if tc.wantErr {
assert.Error(err)

View file

@ -175,7 +175,7 @@ func TestInitialize(t *testing.T) {
defer cancel()
cmd.SetContext(ctx)
i := &initCmd{log: logger.NewTest(t), spinner: &nopSpinner{}}
err := i.initialize(cmd, newDialer, fileHandler, &stubLicenseClient{}, fakeAttestationFetcher{})
err := i.initialize(cmd, newDialer, fileHandler, &stubLicenseClient{}, stubAttestationFetcher{})
if tc.wantErr {
assert.Error(err)
@ -519,7 +519,7 @@ func TestAttestation(t *testing.T) {
cmd.SetContext(ctx)
i := &initCmd{log: logger.NewTest(t), spinner: &nopSpinner{}}
err := i.initialize(cmd, newDialer, fileHandler, &stubLicenseClient{}, fakeAttestationFetcher{})
err := i.initialize(cmd, newDialer, fileHandler, &stubLicenseClient{}, stubAttestationFetcher{})
assert.Error(err)
// make sure the error is actually a TLS handshake error
assert.Contains(err.Error(), "transport: authentication handshake failed")

View file

@ -163,7 +163,7 @@ func TestRecover(t *testing.T) {
))
newDialer := func(atls.Validator) *dialer.Dialer { return nil }
r := &recoverCmd{log: logger.NewTest(t), configFetcher: fakeAttestationFetcher{}}
r := &recoverCmd{log: logger.NewTest(t), configFetcher: stubAttestationFetcher{}}
err := r.recover(cmd, fileHandler, time.Millisecond, tc.doer, newDialer)
if tc.wantErr {
assert.Error(err)

View file

@ -142,7 +142,7 @@ func TestUpgradeApply(t *testing.T) {
require.NoError(handler.WriteYAML(constants.ConfigFilename, cfg))
require.NoError(handler.WriteJSON(constants.ClusterIDsFileName, clusterid.File{}))
upgrader := upgradeApplyCmd{upgrader: tc.upgrader, log: logger.NewTest(t), imageFetcher: tc.fetcher, configFetcher: fakeAttestationFetcher{}}
upgrader := upgradeApplyCmd{upgrader: tc.upgrader, log: logger.NewTest(t), imageFetcher: tc.fetcher, configFetcher: stubAttestationFetcher{}}
err := upgrader.upgradeApply(cmd, handler)
if tc.wantErr {
assert.Error(err)

View file

@ -271,7 +271,7 @@ func TestUpgradeCheck(t *testing.T) {
cmd := newUpgradeCheckCmd()
err := checkCmd.upgradeCheck(cmd, fileHandler, fakeAttestationFetcher{}, tc.flags)
err := checkCmd.upgradeCheck(cmd, fileHandler, stubAttestationFetcher{}, tc.flags)
if tc.wantError {
assert.Error(err)
return

View file

@ -190,7 +190,7 @@ func TestVerify(t *testing.T) {
}
v := &verifyCmd{log: logger.NewTest(t)}
err := v.verify(cmd, fileHandler, tc.protoClient, tc.formatter, fakeAttestationFetcher{})
err := v.verify(cmd, fileHandler, tc.protoClient, tc.formatter, stubAttestationFetcher{})
if tc.wantErr {
assert.Error(err)