mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-05-02 14:26:23 -04:00
AB#2644 Fetch measurements from CDN (#653)
* Fetch measurements from CDN * Perform metadata validation on fetched measurements * Remove deprecated public bucket Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
c978329839
commit
d52f3db2a3
16 changed files with 406 additions and 144 deletions
|
@ -11,13 +11,15 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/image"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -49,10 +51,13 @@ func runConfigFetchMeasurements(cmd *cobra.Command, args []string) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("constructing Rekor client: %w", err)
|
||||
}
|
||||
return configFetchMeasurements(cmd, rekor, fileHandler, http.DefaultClient, image.New())
|
||||
return configFetchMeasurements(cmd, rekor, []byte(constants.CosignPublicKey), fileHandler, http.DefaultClient)
|
||||
}
|
||||
|
||||
func configFetchMeasurements(cmd *cobra.Command, verifier rekorVerifier, fileHandler file.Handler, client *http.Client, img imageFetcher) error {
|
||||
func configFetchMeasurements(
|
||||
cmd *cobra.Command, verifier rekorVerifier, cosignPublicKey []byte,
|
||||
fileHandler file.Handler, client *http.Client,
|
||||
) error {
|
||||
flags, err := parseFetchMeasurementsFlags(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -70,12 +75,21 @@ func configFetchMeasurements(cmd *cobra.Command, verifier rekorVerifier, fileHan
|
|||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
if err := flags.updateURLs(ctx, conf, img); err != nil {
|
||||
if err := flags.updateURLs(conf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fetchedMeasurements measurements.M
|
||||
hash, err := fetchedMeasurements.FetchAndVerify(ctx, client, flags.measurementsURL, flags.signatureURL, []byte(constants.CosignPublicKey))
|
||||
hash, err := fetchedMeasurements.FetchAndVerify(
|
||||
ctx, client,
|
||||
flags.measurementsURL,
|
||||
flags.signatureURL,
|
||||
cosignPublicKey,
|
||||
measurements.WithMetadata{
|
||||
CSP: conf.GetProvider(),
|
||||
Image: conf.Image,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -129,31 +143,31 @@ func parseFetchMeasurementsFlags(cmd *cobra.Command) (*fetchMeasurementsFlags, e
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (f *fetchMeasurementsFlags) updateURLs(ctx context.Context, conf *config.Config, img imageFetcher) error {
|
||||
imageRef, err := img.FetchReference(ctx, conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *fetchMeasurementsFlags) updateURLs(conf *config.Config) error {
|
||||
if f.measurementsURL == nil {
|
||||
// TODO(AB#2644): resolve image version to reference
|
||||
parsedURL, err := url.Parse(constants.S3PublicBucket + imageRef + "/measurements.json")
|
||||
url, err := measurementURL(conf.GetProvider(), conf.Image, "measurements.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.measurementsURL = parsedURL
|
||||
f.measurementsURL = url
|
||||
}
|
||||
|
||||
if f.signatureURL == nil {
|
||||
parsedURL, err := url.Parse(constants.S3PublicBucket + imageRef + "/measurements.json.sig")
|
||||
url, err := measurementURL(conf.GetProvider(), conf.Image, "measurements.json.sig")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.signatureURL = parsedURL
|
||||
f.signatureURL = url
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type imageFetcher interface {
|
||||
FetchReference(ctx context.Context, config *config.Config) (string, error)
|
||||
func measurementURL(provider cloudprovider.Provider, image, file string) (*url.URL, error) {
|
||||
url, err := url.Parse(constants.CDNRepositoryURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing image version repository URL: %w", err)
|
||||
}
|
||||
url.Path = path.Join(constants.CDNMeasurementsPath, image, strings.ToLower(provider.String()), file)
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ package cmd
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -109,8 +109,8 @@ func TestUpdateURLs(t *testing.T) {
|
|||
},
|
||||
},
|
||||
flags: &fetchMeasurementsFlags{},
|
||||
wantMeasurementsURL: constants.S3PublicBucket + "some/image/path/image-123456/measurements.json",
|
||||
wantMeasurementsSigURL: constants.S3PublicBucket + "some/image/path/image-123456/measurements.json.sig",
|
||||
wantMeasurementsURL: constants.CDNRepositoryURL + "/" + constants.CDNMeasurementsPath + "/someImageVersion/gcp/measurements.json",
|
||||
wantMeasurementsSigURL: constants.CDNRepositoryURL + "/" + constants.CDNMeasurementsPath + "/someImageVersion/gcp/measurements.json.sig",
|
||||
},
|
||||
"both set by user": {
|
||||
conf: &config.Config{},
|
||||
|
@ -127,9 +127,7 @@ func TestUpdateURLs(t *testing.T) {
|
|||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
err := tc.flags.updateURLs(context.Background(), tc.conf, &stubImageFetcher{
|
||||
reference: "some/image/path/image-123456",
|
||||
})
|
||||
err := tc.flags.updateURLs(tc.conf)
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.wantMeasurementsURL, tc.flags.measurementsURL.String())
|
||||
})
|
||||
|
@ -152,32 +150,57 @@ func newTestClient(fn roundTripFunc) *http.Client {
|
|||
}
|
||||
|
||||
func TestConfigFetchMeasurements(t *testing.T) {
|
||||
measurements := `1: fPRxd3lV3uybnSVhcBmM6XLzcvMitXW78G0RRuQxYGc=
|
||||
2: PUWM/lXMA+ofRD8VYr7sjfUcdeFKn8+acjShPxmOeWk=
|
||||
3: PUWM/lXMA+ofRD8VYr7sjfUcdeFKn8+acjShPxmOeWk=
|
||||
4: HaV5ivUAGzMxmKkfKjcG3wmW08MRUWr+vsfIMVQpOH0=
|
||||
5: PemdXV59WnLLzPz0F4GGCTKm8KbHskPRvon1dtNw7oY=
|
||||
7: 8dI/6SUmQ5sd8+bulPDpJ8ghs0UX0+fgLlW8kutAYKw=
|
||||
8: XJ5IBWy6b6vqojkTsk/GLOWyfNUB2qaf58+JjMYiAB4=
|
||||
9: Gw5gq8D1WXfz46sF/OKiWbkBssyt4ayGybzNyV9cUCQ=
|
||||
// Cosign private key used to sign the measurements.
|
||||
// Generated with: cosign generate-key-pair
|
||||
// Password left empty.
|
||||
//
|
||||
// -----BEGIN ENCRYPTED COSIGN PRIVATE KEY-----
|
||||
// eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6
|
||||
// OCwicCI6MX0sInNhbHQiOiJlRHVYMWRQMGtIWVRnK0xkbjcxM0tjbFVJaU92eFVX
|
||||
// VXgvNi9BbitFVk5BPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94
|
||||
// Iiwibm9uY2UiOiJwaWhLL2txNmFXa2hqSVVHR3RVUzhTVkdHTDNIWWp4TCJ9LCJj
|
||||
// aXBoZXJ0ZXh0Ijoidm81SHVWRVFWcUZ2WFlQTTVPaTVaWHM5a255bndZU2dvcyth
|
||||
// VklIeHcrOGFPamNZNEtvVjVmL3lHRHR0K3BHV2toanJPR1FLOWdBbmtsazFpQ0c5
|
||||
// a2czUXpPQTZsU2JRaHgvZlowRVRZQ0hLeElncEdPRVRyTDlDenZDemhPZXVSOXJ6
|
||||
// TDcvRjBBVy9vUDVqZXR3dmJMNmQxOEhjck9kWE8yVmYxY2w0YzNLZjVRcnFSZzlN
|
||||
// dlRxQWFsNXJCNHNpY1JaMVhpUUJjb0YwNHc9PSJ9
|
||||
// -----END ENCRYPTED COSIGN PRIVATE KEY-----
|
||||
|
||||
cosignPublicKey := []byte("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEu78QgxOOcao6U91CSzEXxrKhvFTt\nJHNy+eX6EMePtDm8CnDF9HSwnTlD0itGJ/XHPQA5YX10fJAqI1y+ehlFMw==\n-----END PUBLIC KEY-----")
|
||||
|
||||
measurements := `{
|
||||
"csp": "gcp",
|
||||
"image": "v999.999.999",
|
||||
"measurements": {
|
||||
"0": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"1": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"2": "2222222222222222222222222222222222222222222222222222222222222222",
|
||||
"3": "3333333333333333333333333333333333333333333333333333333333333333",
|
||||
"4": "4444444444444444444444444444444444444444444444444444444444444444",
|
||||
"5": "5555555555555555555555555555555555555555555555555555555555555555",
|
||||
"6": "6666666666666666666666666666666666666666666666666666666666666666"
|
||||
}
|
||||
}
|
||||
`
|
||||
signature := "MEUCIFdJ5dH6HDywxQWTUh9Bw77wMrq0mNCUjMQGYP+6QsVmAiEAmazj/L7rFGA4/Gz8y+kI5h5E5cDgc3brihvXBKF6qZA="
|
||||
signature := "MEYCIQDRAQNK2NjHJBGrnw3HQAyBsXMCmVCptBdgA6VZ3IlyiAIhAPG42waF1aFZq7dnjP3b2jsMNUtaKYDQQSazW1AX8jgF"
|
||||
|
||||
client := newTestClient(func(req *http.Request) *http.Response {
|
||||
if req.URL.String() == "https://public-edgeless-constellation.s3.us-east-2.amazonaws.com/someImage/measurements.json" {
|
||||
if req.URL.String() == "https://cdn.confidential.cloud/constellation/v1/measurements/v999.999.999/gcp/measurements.json" {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewBufferString(measurements)),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
if req.URL.String() == "https://public-edgeless-constellation.s3.us-east-2.amazonaws.com/someImage/measurements.json.sig" {
|
||||
if req.URL.String() == "https://cdn.confidential.cloud/constellation/v1/measurements/v999.999.999/gcp/measurements.json.sig" {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewBufferString(signature)),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("unexpected request", req.URL.String())
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusNotFound,
|
||||
Body: io.NopCloser(bytes.NewBufferString("Not found.")),
|
||||
|
@ -215,23 +238,12 @@ func TestConfigFetchMeasurements(t *testing.T) {
|
|||
fileHandler := file.NewHandler(afero.NewMemMapFs())
|
||||
|
||||
gcpConfig := defaultConfigWithExpectedMeasurements(t, config.Default(), cloudprovider.GCP)
|
||||
gcpConfig.Image = "someImage"
|
||||
gcpConfig.Image = "v999.999.999"
|
||||
|
||||
err := fileHandler.WriteYAML(constants.ConfigFilename, gcpConfig, file.OptMkdirAll)
|
||||
require.NoError(err)
|
||||
|
||||
assert.NoError(configFetchMeasurements(cmd, tc.verifier, fileHandler, client, &stubImageFetcher{
|
||||
reference: "someImage",
|
||||
}))
|
||||
assert.NoError(configFetchMeasurements(cmd, tc.verifier, cosignPublicKey, fileHandler, client))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type stubImageFetcher struct {
|
||||
reference string
|
||||
fetchReferenceErr error
|
||||
}
|
||||
|
||||
func (f *stubImageFetcher) FetchReference(_ context.Context, _ *config.Config) (string, error) {
|
||||
return f.reference, f.fetchReferenceErr
|
||||
}
|
||||
|
|
|
@ -13,10 +13,12 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
|
@ -163,14 +165,20 @@ func getCompatibleImages(csp cloudprovider.Provider, currentVersion string, imag
|
|||
case cloudprovider.Azure:
|
||||
for imgVersion, image := range images {
|
||||
if semver.Compare(currentVersion, imgVersion) < 0 {
|
||||
compatibleImages[imgVersion] = config.UpgradeConfig{Image: image.AzureImage}
|
||||
compatibleImages[imgVersion] = config.UpgradeConfig{
|
||||
Image: image.AzureImage,
|
||||
CSP: cloudprovider.Azure,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case cloudprovider.GCP:
|
||||
for imgVersion, image := range images {
|
||||
if semver.Compare(currentVersion, imgVersion) < 0 {
|
||||
compatibleImages[imgVersion] = config.UpgradeConfig{Image: image.GCPImage}
|
||||
compatibleImages[imgVersion] = config.UpgradeConfig{
|
||||
Image: image.GCPImage,
|
||||
CSP: cloudprovider.GCP,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,17 +189,26 @@ func getCompatibleImages(csp cloudprovider.Provider, currentVersion string, imag
|
|||
// getCompatibleImageMeasurements retrieves the expected measurements for each image.
|
||||
func getCompatibleImageMeasurements(ctx context.Context, cmd *cobra.Command, client *http.Client, rekor rekorVerifier, pubK []byte, images map[string]config.UpgradeConfig) error {
|
||||
for idx, img := range images {
|
||||
measurementsURL, err := url.Parse(constants.S3PublicBucket + strings.ToLower(img.Image) + "/measurements.json")
|
||||
measurementsURL, err := url.Parse(constants.CDNRepositoryURL + "/" + path.Join(img.Image, strings.ToLower(img.CSP.String()), "measurements.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
signatureURL, err := url.Parse(constants.S3PublicBucket + strings.ToLower(img.Image) + "/measurements.json.sig")
|
||||
signatureURL, err := url.Parse(constants.CDNRepositoryURL + "/" + path.Join(img.Image, strings.ToLower(img.CSP.String()), "measurements.json.sig"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hash, err := img.Measurements.FetchAndVerify(ctx, client, measurementsURL, signatureURL, pubK)
|
||||
hash, err := img.Measurements.FetchAndVerify(
|
||||
ctx, client,
|
||||
measurementsURL,
|
||||
signatureURL,
|
||||
pubK,
|
||||
measurements.WithMetadata{
|
||||
Image: img.Image,
|
||||
CSP: img.CSP,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -192,12 +192,15 @@ func TestGetCompatibleImages(t *testing.T) {
|
|||
wantImages: map[string]config.UpgradeConfig{
|
||||
"v1.0.1": {
|
||||
Image: "azure-v1.0.1",
|
||||
CSP: cloudprovider.Azure,
|
||||
},
|
||||
"v1.0.2": {
|
||||
Image: "azure-v1.0.2",
|
||||
CSP: cloudprovider.Azure,
|
||||
},
|
||||
"v1.1.0": {
|
||||
Image: "azure-v1.1.0",
|
||||
CSP: cloudprovider.Azure,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -208,12 +211,15 @@ func TestGetCompatibleImages(t *testing.T) {
|
|||
wantImages: map[string]config.UpgradeConfig{
|
||||
"v1.0.1": {
|
||||
Image: "gcp-v1.0.1",
|
||||
CSP: cloudprovider.GCP,
|
||||
},
|
||||
"v1.0.2": {
|
||||
Image: "gcp-v1.0.2",
|
||||
CSP: cloudprovider.GCP,
|
||||
},
|
||||
"v1.1.0": {
|
||||
Image: "gcp-v1.1.0",
|
||||
CSP: cloudprovider.GCP,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -240,25 +246,42 @@ func TestGetCompatibleImageMeasurements(t *testing.T) {
|
|||
|
||||
testImages := map[string]config.UpgradeConfig{
|
||||
"v0.0.0": {
|
||||
Image: "azure-v0.0.0",
|
||||
Image: "v0.0.0",
|
||||
CSP: cloudprovider.Azure,
|
||||
},
|
||||
"v1.0.0": {
|
||||
Image: "azure-v1.0.0",
|
||||
Image: "v1.0.0",
|
||||
CSP: cloudprovider.Azure,
|
||||
},
|
||||
}
|
||||
|
||||
client := newTestClient(func(req *http.Request) *http.Response {
|
||||
if strings.HasSuffix(req.URL.String(), "/measurements.json") {
|
||||
if strings.HasSuffix(req.URL.String(), "v0.0.0/azure/measurements.json") {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(strings.NewReader("0: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n")),
|
||||
Body: io.NopCloser(strings.NewReader(`{"csp":"azure","image":"v0.0.0","measurements":{"0":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false}}}`)),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(req.URL.String(), "/measurements.json.sig") {
|
||||
if strings.HasSuffix(req.URL.String(), "v0.0.0/azure/measurements.json.sig") {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(strings.NewReader("MEUCIBs1g2/n0FsgPfJ+0uLD5TaunGhxwDcQcUGBroejKvg3AiEAzZtcLU9O6IiVhxB8tBS+ty6MXoPNwL8WRWMzyr35eKI=")),
|
||||
Body: io.NopCloser(strings.NewReader("MEQCIGRR7RaSMs892Ta06/Tz7LqPUxI05X4wQcP+nFFmZtmaAiBNl9X8mUKmUBfxg13LQBfmmpw6JwYQor5hOwM3NFVPAg==")),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(req.URL.String(), "v1.0.0/azure/measurements.json") {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(strings.NewReader(`{"csp":"azure","image":"v1.0.0","measurements":{"0":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false}}}`)),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(req.URL.String(), "v1.0.0/azure/measurements.json.sig") {
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(strings.NewReader("MEQCIFh8CVELp/Da2U2Jt404OXsUeDfqtrf3pqGRuvxnxhI8AiBTHF9tHEPwFedYG3Jgn2ELOxss+Ybc6135vEtClBrbpg==")),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +293,7 @@ func TestGetCompatibleImageMeasurements(t *testing.T) {
|
|||
}
|
||||
})
|
||||
|
||||
pubK := []byte("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----")
|
||||
pubK := []byte("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEu78QgxOOcao6U91CSzEXxrKhvFTt\nJHNy+eX6EMePtDm8CnDF9HSwnTlD0itGJ/XHPQA5YX10fJAqI1y+ehlFMw==\n-----END PUBLIC KEY-----")
|
||||
|
||||
err := getCompatibleImageMeasurements(context.Background(), &cobra.Command{}, client, singleUUIDVerifier(), pubK, testImages)
|
||||
assert.NoError(err)
|
||||
|
@ -283,15 +306,28 @@ func TestGetCompatibleImageMeasurements(t *testing.T) {
|
|||
func TestUpgradePlan(t *testing.T) {
|
||||
testImages := map[string]imageManifest{
|
||||
"v1.0.0": {
|
||||
AzureImage: "azure-v1.0.0",
|
||||
GCPImage: "gcp-v1.0.0",
|
||||
},
|
||||
"v2.0.0": {
|
||||
AzureImage: "azure-v2.0.0",
|
||||
GCPImage: "gcp-v2.0.0",
|
||||
AzureImage: "v1.0.0",
|
||||
GCPImage: "v1.0.0",
|
||||
},
|
||||
}
|
||||
|
||||
// Cosign private key used to sign the measurements.
|
||||
// Generated with: cosign generate-key-pair
|
||||
// Password left empty.
|
||||
//
|
||||
// -----BEGIN ENCRYPTED COSIGN PRIVATE KEY-----
|
||||
// eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6
|
||||
// OCwicCI6MX0sInNhbHQiOiJlRHVYMWRQMGtIWVRnK0xkbjcxM0tjbFVJaU92eFVX
|
||||
// VXgvNi9BbitFVk5BPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94
|
||||
// Iiwibm9uY2UiOiJwaWhLL2txNmFXa2hqSVVHR3RVUzhTVkdHTDNIWWp4TCJ9LCJj
|
||||
// aXBoZXJ0ZXh0Ijoidm81SHVWRVFWcUZ2WFlQTTVPaTVaWHM5a255bndZU2dvcyth
|
||||
// VklIeHcrOGFPamNZNEtvVjVmL3lHRHR0K3BHV2toanJPR1FLOWdBbmtsazFpQ0c5
|
||||
// a2czUXpPQTZsU2JRaHgvZlowRVRZQ0hLeElncEdPRVRyTDlDenZDemhPZXVSOXJ6
|
||||
// TDcvRjBBVy9vUDVqZXR3dmJMNmQxOEhjck9kWE8yVmYxY2w0YzNLZjVRcnFSZzlN
|
||||
// dlRxQWFsNXJCNHNpY1JaMVhpUUJjb0YwNHc9PSJ9
|
||||
// -----END ENCRYPTED COSIGN PRIVATE KEY-----
|
||||
pubK := "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEu78QgxOOcao6U91CSzEXxrKhvFTt\nJHNy+eX6EMePtDm8CnDF9HSwnTlD0itGJ/XHPQA5YX10fJAqI1y+ehlFMw==\n-----END PUBLIC KEY-----"
|
||||
|
||||
testCases := map[string]struct {
|
||||
planner stubUpgradePlanner
|
||||
flags upgradePlanFlags
|
||||
|
@ -311,7 +347,7 @@ func TestUpgradePlan(t *testing.T) {
|
|||
flags: upgradePlanFlags{
|
||||
configPath: constants.ConfigFilename,
|
||||
filePath: "upgrade-plan.yaml",
|
||||
cosignPubKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----",
|
||||
cosignPubKey: pubK,
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
verifier: singleUUIDVerifier(),
|
||||
|
@ -319,14 +355,14 @@ func TestUpgradePlan(t *testing.T) {
|
|||
},
|
||||
"upgrades gcp": {
|
||||
planner: stubUpgradePlanner{
|
||||
image: "projects/constellation-images/global/images/constellation-v1-0-0",
|
||||
image: "projects/constellation-images/global/images/constellation-v0-0-0",
|
||||
},
|
||||
imageFetchStatus: http.StatusOK,
|
||||
measurementsFetchStatus: http.StatusOK,
|
||||
flags: upgradePlanFlags{
|
||||
configPath: constants.ConfigFilename,
|
||||
filePath: "upgrade-plan.yaml",
|
||||
cosignPubKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----",
|
||||
cosignPubKey: pubK,
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
verifier: singleUUIDVerifier(),
|
||||
|
@ -341,7 +377,7 @@ func TestUpgradePlan(t *testing.T) {
|
|||
flags: upgradePlanFlags{
|
||||
configPath: constants.ConfigFilename,
|
||||
filePath: "upgrade-plan.yaml",
|
||||
cosignPubKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----",
|
||||
cosignPubKey: pubK,
|
||||
},
|
||||
csp: cloudprovider.Azure,
|
||||
verifier: singleUUIDVerifier(),
|
||||
|
@ -349,14 +385,14 @@ func TestUpgradePlan(t *testing.T) {
|
|||
},
|
||||
"upgrade to stdout": {
|
||||
planner: stubUpgradePlanner{
|
||||
image: "projects/constellation-images/global/images/constellation-v1-0-0",
|
||||
image: "projects/constellation-images/global/images/constellation-v0-0-0",
|
||||
},
|
||||
imageFetchStatus: http.StatusOK,
|
||||
measurementsFetchStatus: http.StatusOK,
|
||||
flags: upgradePlanFlags{
|
||||
configPath: constants.ConfigFilename,
|
||||
filePath: "-",
|
||||
cosignPubKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----",
|
||||
cosignPubKey: pubK,
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
verifier: singleUUIDVerifier(),
|
||||
|
@ -371,7 +407,7 @@ func TestUpgradePlan(t *testing.T) {
|
|||
flags: upgradePlanFlags{
|
||||
configPath: constants.ConfigFilename,
|
||||
filePath: "upgrade-plan.yaml",
|
||||
cosignPubKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----",
|
||||
cosignPubKey: pubK,
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
verifier: singleUUIDVerifier(),
|
||||
|
@ -379,14 +415,14 @@ func TestUpgradePlan(t *testing.T) {
|
|||
},
|
||||
"image fetch error": {
|
||||
planner: stubUpgradePlanner{
|
||||
image: "projects/constellation-images/global/images/constellation-v1-0-0",
|
||||
image: "projects/constellation-images/global/images/constellation-v0-0-0",
|
||||
},
|
||||
imageFetchStatus: http.StatusInternalServerError,
|
||||
measurementsFetchStatus: http.StatusOK,
|
||||
flags: upgradePlanFlags{
|
||||
configPath: constants.ConfigFilename,
|
||||
filePath: "upgrade-plan.yaml",
|
||||
cosignPubKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----",
|
||||
cosignPubKey: pubK,
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
verifier: singleUUIDVerifier(),
|
||||
|
@ -394,14 +430,14 @@ func TestUpgradePlan(t *testing.T) {
|
|||
},
|
||||
"measurements fetch error": {
|
||||
planner: stubUpgradePlanner{
|
||||
image: "projects/constellation-images/global/images/constellation-v1-0-0",
|
||||
image: "projects/constellation-images/global/images/constellation-v0-0-0",
|
||||
},
|
||||
imageFetchStatus: http.StatusOK,
|
||||
measurementsFetchStatus: http.StatusInternalServerError,
|
||||
flags: upgradePlanFlags{
|
||||
configPath: constants.ConfigFilename,
|
||||
filePath: "upgrade-plan.yaml",
|
||||
cosignPubKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----",
|
||||
cosignPubKey: pubK,
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
verifier: singleUUIDVerifier(),
|
||||
|
@ -409,14 +445,14 @@ func TestUpgradePlan(t *testing.T) {
|
|||
},
|
||||
"failing search should not result in error": {
|
||||
planner: stubUpgradePlanner{
|
||||
image: "projects/constellation-images/global/images/constellation-v1-0-0",
|
||||
image: "projects/constellation-images/global/images/constellation-v0-0-0",
|
||||
},
|
||||
imageFetchStatus: http.StatusOK,
|
||||
measurementsFetchStatus: http.StatusOK,
|
||||
flags: upgradePlanFlags{
|
||||
configPath: constants.ConfigFilename,
|
||||
filePath: "upgrade-plan.yaml",
|
||||
cosignPubKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----",
|
||||
cosignPubKey: pubK,
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
verifier: &stubRekorVerifier{
|
||||
|
@ -427,14 +463,14 @@ func TestUpgradePlan(t *testing.T) {
|
|||
},
|
||||
"failing verify should not result in error": {
|
||||
planner: stubUpgradePlanner{
|
||||
image: "projects/constellation-images/global/images/constellation-v1-0-0",
|
||||
image: "projects/constellation-images/global/images/constellation-v0-0-0",
|
||||
},
|
||||
imageFetchStatus: http.StatusOK,
|
||||
measurementsFetchStatus: http.StatusOK,
|
||||
flags: upgradePlanFlags{
|
||||
configPath: constants.ConfigFilename,
|
||||
filePath: "upgrade-plan.yaml",
|
||||
cosignPubKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUs5fDUIz9aiwrfr8BK4VjN7jE6sl\ngz7UuXsOin8+dB0SGrbNHy7TJToa2fAiIKPVLTOfvY75DqRAtffhO1fpBA==\n-----END PUBLIC KEY-----",
|
||||
cosignPubKey: pubK,
|
||||
},
|
||||
csp: cloudprovider.GCP,
|
||||
verifier: &stubRekorVerifier{
|
||||
|
@ -470,17 +506,32 @@ func TestUpgradePlan(t *testing.T) {
|
|||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(req.URL.String(), "/measurements.json") {
|
||||
if strings.HasSuffix(req.URL.String(), "azure/measurements.json") {
|
||||
return &http.Response{
|
||||
StatusCode: tc.measurementsFetchStatus,
|
||||
Body: io.NopCloser(strings.NewReader("0: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n")),
|
||||
Body: io.NopCloser(strings.NewReader(`{"csp":"azure","image":"v1.0.0","measurements":{"0":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false}}}`)),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(req.URL.String(), "/measurements.json.sig") {
|
||||
if strings.HasSuffix(req.URL.String(), "azure/measurements.json.sig") {
|
||||
return &http.Response{
|
||||
StatusCode: tc.measurementsFetchStatus,
|
||||
Body: io.NopCloser(strings.NewReader("MEUCIBs1g2/n0FsgPfJ+0uLD5TaunGhxwDcQcUGBroejKvg3AiEAzZtcLU9O6IiVhxB8tBS+ty6MXoPNwL8WRWMzyr35eKI=")),
|
||||
Body: io.NopCloser(strings.NewReader("MEQCIFh8CVELp/Da2U2Jt404OXsUeDfqtrf3pqGRuvxnxhI8AiBTHF9tHEPwFedYG3Jgn2ELOxss+Ybc6135vEtClBrbpg==")),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(req.URL.String(), "gcp/measurements.json") {
|
||||
return &http.Response{
|
||||
StatusCode: tc.measurementsFetchStatus,
|
||||
Body: io.NopCloser(strings.NewReader(`{"csp":"gcp","image":"v1.0.0","measurements":{"0":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false}}}`)),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(req.URL.String(), "gcp/measurements.json.sig") {
|
||||
return &http.Response{
|
||||
StatusCode: tc.measurementsFetchStatus,
|
||||
Body: io.NopCloser(strings.NewReader("MEYCIQCr/gDGjj11mR5OeImwOLjxnBqMbBmqoK7yXqy0cXR3HQIhALpVDdYwR9VNJnWwtl8bTfrezyJbc7UNZJO4PJe+stFP")),
|
||||
Header: make(http.Header),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue