mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-28 08:59:34 -05:00
api: use new signature type for Azure SNP versions
* Remove signature checks from unittests. Would need to export signature from client/fetcher (unwanted). Can't figure out a better way. e2e test completes in ~4sec and runs automatically. So seems like a acceptable tradeoff. * list object is now signed, but not verified. If we start to verify the list we will have to adapt the e2e test to restore the previous list. Otherwise there could be conflicts between dev and release keys.
This commit is contained in:
parent
2b19632e09
commit
fdaa5aab3c
@ -35,35 +35,6 @@ type AzureSEVSNPVersion struct {
|
||||
Microcode uint8 `json:"microcode"`
|
||||
}
|
||||
|
||||
// AzureSEVSNPVersionSignature is the object to perform CRUD operations on the config api.
|
||||
type AzureSEVSNPVersionSignature struct {
|
||||
Version string `json:"-"`
|
||||
Signature []byte `json:"signature"`
|
||||
}
|
||||
|
||||
// JSONPath returns the path to the JSON file for the request to the config api.
|
||||
func (s AzureSEVSNPVersionSignature) JSONPath() string {
|
||||
return path.Join(attestationURLPath, variant.AzureSEVSNP{}.String(), s.Version+".sig")
|
||||
}
|
||||
|
||||
// URL returns the URL for the request to the config api.
|
||||
func (s AzureSEVSNPVersionSignature) URL() (string, error) {
|
||||
return getURL(s)
|
||||
}
|
||||
|
||||
// ValidateRequest validates the request.
|
||||
func (s AzureSEVSNPVersionSignature) ValidateRequest() error {
|
||||
if !strings.HasSuffix(s.Version, ".json") {
|
||||
return fmt.Errorf("%s version has no .json suffix", s.Version)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate is a No-Op at the moment.
|
||||
func (s AzureSEVSNPVersionSignature) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AzureSEVSNPVersionAPI is the request to get the version information of the specific version in the config api.
|
||||
type AzureSEVSNPVersionAPI struct {
|
||||
Version string `json:"-"`
|
||||
|
@ -7,7 +7,6 @@ package attestationconfigapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@ -45,16 +44,14 @@ func NewClient(ctx context.Context, cfg staticupload.Config, cosignPwd, privateK
|
||||
return repo, clientClose, nil
|
||||
}
|
||||
|
||||
// UploadAzureSEVSNP uploads the latest version numbers of the Azure SEVSNP. Then version name is the UTC timestamp of the date. The /list entry stores the version name + .json suffix.
|
||||
func (a Client) UploadAzureSEVSNP(ctx context.Context, version AzureSEVSNPVersion, date time.Time) error {
|
||||
// UploadAzureSEVSNPVersion uploads the latest version numbers of the Azure SEVSNP. Then version name is the UTC timestamp of the date. The /list entry stores the version name + .json suffix.
|
||||
func (a Client) UploadAzureSEVSNPVersion(ctx context.Context, version AzureSEVSNPVersion, date time.Time) error {
|
||||
versions, err := a.List(ctx, variant.AzureSEVSNP{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("fetch version list: %w", err)
|
||||
}
|
||||
ops, err := a.uploadAzureSEVSNP(version, versions, date)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ops := a.constructUploadCmd(version, versions, date)
|
||||
|
||||
return executeAllCmds(ctx, a.s3Client, ops)
|
||||
}
|
||||
|
||||
@ -91,50 +88,33 @@ func (a Client) deleteAzureSEVSNPVersion(versions AzureSEVSNPVersionList, versio
|
||||
},
|
||||
})
|
||||
|
||||
ops = append(ops, deleteCmd{
|
||||
apiObject: AzureSEVSNPVersionSignature{
|
||||
Version: versionStr,
|
||||
},
|
||||
})
|
||||
|
||||
removedVersions, err := removeVersion(versions, versionStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ops = append(ops, putCmd{
|
||||
apiObject: removedVersions,
|
||||
signer: a.signer,
|
||||
})
|
||||
return ops, nil
|
||||
}
|
||||
|
||||
func (a Client) uploadAzureSEVSNP(versions AzureSEVSNPVersion, versionNames []string, date time.Time) (res []crudCmd, err error) {
|
||||
func (a Client) constructUploadCmd(versions AzureSEVSNPVersion, versionNames []string, date time.Time) []crudCmd {
|
||||
dateStr := date.Format(VersionFormat) + ".json"
|
||||
var res []crudCmd
|
||||
|
||||
res = append(res, putCmd{AzureSEVSNPVersionAPI{Version: dateStr, AzureSEVSNPVersion: versions}})
|
||||
res = append(res, putCmd{
|
||||
apiObject: AzureSEVSNPVersionAPI{Version: dateStr, AzureSEVSNPVersion: versions},
|
||||
signer: a.signer,
|
||||
})
|
||||
|
||||
versionBytes, err := json.Marshal(versions)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
signature, err := a.createSignature(versionBytes, dateStr)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res = append(res, putCmd{signature})
|
||||
newVersions := addVersion(versionNames, dateStr)
|
||||
res = append(res, putCmd{AzureSEVSNPVersionList(newVersions)})
|
||||
return
|
||||
}
|
||||
res = append(res, putCmd{
|
||||
apiObject: AzureSEVSNPVersionList(newVersions),
|
||||
signer: a.signer,
|
||||
})
|
||||
|
||||
func (a Client) createSignature(content []byte, dateStr string) (res AzureSEVSNPVersionSignature, err error) {
|
||||
signature, err := a.signer.Sign(content)
|
||||
if err != nil {
|
||||
return res, fmt.Errorf("sign version file: %w", err)
|
||||
}
|
||||
return AzureSEVSNPVersionSignature{
|
||||
Signature: signature,
|
||||
Version: dateStr,
|
||||
}, nil
|
||||
return res
|
||||
}
|
||||
|
||||
func removeVersion(versions AzureSEVSNPVersionList, versionStr string) (removedVersions AzureSEVSNPVersionList, err error) {
|
||||
@ -160,15 +140,16 @@ type deleteCmd struct {
|
||||
}
|
||||
|
||||
func (d deleteCmd) Execute(ctx context.Context, c *apiclient.Client) error {
|
||||
return apiclient.Delete(ctx, c, d.apiObject)
|
||||
return apiclient.DeleteWithSignature(ctx, c, d.apiObject)
|
||||
}
|
||||
|
||||
type putCmd struct {
|
||||
apiObject apiclient.APIObject
|
||||
signer sigstore.Signer
|
||||
}
|
||||
|
||||
func (p putCmd) Execute(ctx context.Context, c *apiclient.Client) error {
|
||||
return apiclient.Update(ctx, c, p.apiObject)
|
||||
return apiclient.SignAndUpdate(ctx, c, p.apiObject, p.signer)
|
||||
}
|
||||
|
||||
func executeAllCmds(ctx context.Context, client *apiclient.Client, cmds []crudCmd) error {
|
||||
|
@ -19,24 +19,19 @@ func TestUploadAzureSEVSNP(t *testing.T) {
|
||||
}
|
||||
version := AzureSEVSNPVersion{}
|
||||
date := time.Date(2023, 1, 1, 1, 1, 1, 1, time.UTC)
|
||||
ops, err := sut.uploadAzureSEVSNP(version, []string{"2021-01-01-01-01.json", "2019-01-01-01-01.json"}, date)
|
||||
assert := assert.New(t)
|
||||
assert.NoError(err)
|
||||
ops := sut.constructUploadCmd(version, []string{"2021-01-01-01-01.json", "2019-01-01-01-01.json"}, date)
|
||||
dateStr := "2023-01-01-01-01.json"
|
||||
assert := assert.New(t)
|
||||
assert.Contains(ops, putCmd{
|
||||
apiObject: AzureSEVSNPVersionAPI{
|
||||
Version: dateStr,
|
||||
AzureSEVSNPVersion: version,
|
||||
},
|
||||
})
|
||||
assert.Contains(ops, putCmd{
|
||||
apiObject: AzureSEVSNPVersionSignature{
|
||||
Version: dateStr,
|
||||
Signature: []byte("signature"),
|
||||
},
|
||||
signer: fakeSigner{},
|
||||
})
|
||||
assert.Contains(ops, putCmd{
|
||||
apiObject: AzureSEVSNPVersionList([]string{"2023-01-01-01-01.json", "2021-01-01-01-01.json", "2019-01-01-01-01.json"}),
|
||||
signer: fakeSigner{},
|
||||
})
|
||||
}
|
||||
|
||||
@ -55,11 +50,6 @@ func TestDeleteAzureSEVSNPVersions(t *testing.T) {
|
||||
Version: "2021-01-01.json",
|
||||
},
|
||||
})
|
||||
assert.Contains(ops, deleteCmd{
|
||||
apiObject: AzureSEVSNPVersionSignature{
|
||||
Version: "2021-01-01.json",
|
||||
},
|
||||
})
|
||||
|
||||
assert.Contains(ops, putCmd{
|
||||
apiObject: AzureSEVSNPVersionList([]string{"2023-01-01.json", "2019-01-01.json"}),
|
||||
|
@ -8,7 +8,6 @@ package attestationconfigapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@ -57,31 +56,17 @@ func newFetcherWithClientAndVerifier(client apifetcher.HTTPClient, cosignVerifie
|
||||
|
||||
// FetchAzureSEVSNPVersionList fetches the version list information from the config API.
|
||||
func (f *fetcher) FetchAzureSEVSNPVersionList(ctx context.Context, attestation AzureSEVSNPVersionList) (AzureSEVSNPVersionList, error) {
|
||||
// TODO (derpsteb): Replace with FetchAndVerify once we move to v2 of the config API.
|
||||
return apifetcher.Fetch(ctx, f.HTTPClient, attestation)
|
||||
}
|
||||
|
||||
// FetchAzureSEVSNPVersion fetches the version information from the config API.
|
||||
func (f *fetcher) FetchAzureSEVSNPVersion(ctx context.Context, azureVersion AzureSEVSNPVersionAPI) (AzureSEVSNPVersionAPI, error) {
|
||||
fetchedVersion, err := apifetcher.Fetch(ctx, f.HTTPClient, azureVersion)
|
||||
fetchedVersion, err := apifetcher.FetchAndVerify(ctx, f.HTTPClient, azureVersion, f.verifier)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("fetch version %s: %w", fetchedVersion.Version, err)
|
||||
}
|
||||
versionBytes, err := json.Marshal(fetchedVersion)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("marshal version for verify %s: %w", azureVersion.Version, err)
|
||||
}
|
||||
|
||||
signature, err := apifetcher.Fetch(ctx, f.HTTPClient, AzureSEVSNPVersionSignature{
|
||||
Version: azureVersion.Version,
|
||||
})
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("fetch version %s signature: %w", azureVersion.Version, err)
|
||||
}
|
||||
|
||||
err = f.verifier.VerifySignature(versionBytes, signature.Signature)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("verify version %s signature: %w", azureVersion.Version, err)
|
||||
}
|
||||
return fetchedVersion, nil
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,6 @@ type fakeConfigAPIHandler struct {
|
||||
|
||||
// RoundTrip resolves the request and returns a dummy response.
|
||||
func (f *fakeConfigAPIHandler) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
signature := []byte("placeholderSignature")
|
||||
if req.URL.Path == "/constellation/v1/attestation/azure-sev-snp/list" {
|
||||
res := &http.Response{}
|
||||
bt, err := json.Marshal(f.versions)
|
||||
@ -128,30 +127,15 @@ func (f *fakeConfigAPIHandler) RoundTrip(req *http.Request) (*http.Response, err
|
||||
res.Body = io.NopCloser(bytes.NewReader(bt))
|
||||
res.StatusCode = http.StatusOK
|
||||
return res, nil
|
||||
|
||||
} else if req.URL.Path == fmt.Sprintf("/constellation/v1/attestation/azure-sev-snp/%s.sig", f.latestVersion) {
|
||||
res := &http.Response{}
|
||||
obj := AzureSEVSNPVersionSignature{
|
||||
Signature: signature,
|
||||
}
|
||||
bt, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.Body = io.NopCloser(bytes.NewReader(bt))
|
||||
res.Body = io.NopCloser(bytes.NewReader([]byte("null")))
|
||||
res.StatusCode = http.StatusOK
|
||||
return res, nil
|
||||
|
||||
} else if req.URL.Path == fmt.Sprintf("/constellation/v1/attestation/azure-sev-snp/%s.sig", f.olderVersion) {
|
||||
res := &http.Response{}
|
||||
obj := AzureSEVSNPVersionSignature{
|
||||
Signature: signature,
|
||||
}
|
||||
bt, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.Body = io.NopCloser(bytes.NewReader(bt))
|
||||
res.Body = io.NopCloser(bytes.NewReader([]byte("null")))
|
||||
res.StatusCode = http.StatusOK
|
||||
return res, nil
|
||||
|
||||
|
@ -374,5 +374,5 @@ func (s signature) ValidateRequest() error {
|
||||
|
||||
// Validate checks that the signature is base64 encoded.
|
||||
func (s signature) Validate() error {
|
||||
return sigstore.IsBase64([]byte(s.Signature))
|
||||
return sigstore.IsBase64(s.Signature)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user