mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04: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"`
|
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.
|
// AzureSEVSNPVersionAPI is the request to get the version information of the specific version in the config api.
|
||||||
type AzureSEVSNPVersionAPI struct {
|
type AzureSEVSNPVersionAPI struct {
|
||||||
Version string `json:"-"`
|
Version string `json:"-"`
|
||||||
|
@ -7,7 +7,6 @@ package attestationconfigapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -45,16 +44,14 @@ func NewClient(ctx context.Context, cfg staticupload.Config, cosignPwd, privateK
|
|||||||
return repo, clientClose, nil
|
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.
|
// 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) UploadAzureSEVSNP(ctx context.Context, version AzureSEVSNPVersion, date time.Time) error {
|
func (a Client) UploadAzureSEVSNPVersion(ctx context.Context, version AzureSEVSNPVersion, date time.Time) error {
|
||||||
versions, err := a.List(ctx, variant.AzureSEVSNP{})
|
versions, err := a.List(ctx, variant.AzureSEVSNP{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("fetch version list: %w", err)
|
return fmt.Errorf("fetch version list: %w", err)
|
||||||
}
|
}
|
||||||
ops, err := a.uploadAzureSEVSNP(version, versions, date)
|
ops := a.constructUploadCmd(version, versions, date)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return executeAllCmds(ctx, a.s3Client, ops)
|
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)
|
removedVersions, err := removeVersion(versions, versionStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ops = append(ops, putCmd{
|
ops = append(ops, putCmd{
|
||||||
apiObject: removedVersions,
|
apiObject: removedVersions,
|
||||||
|
signer: a.signer,
|
||||||
})
|
})
|
||||||
return ops, nil
|
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"
|
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)
|
newVersions := addVersion(versionNames, dateStr)
|
||||||
res = append(res, putCmd{AzureSEVSNPVersionList(newVersions)})
|
res = append(res, putCmd{
|
||||||
return
|
apiObject: AzureSEVSNPVersionList(newVersions),
|
||||||
}
|
signer: a.signer,
|
||||||
|
})
|
||||||
|
|
||||||
func (a Client) createSignature(content []byte, dateStr string) (res AzureSEVSNPVersionSignature, err error) {
|
return res
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeVersion(versions AzureSEVSNPVersionList, versionStr string) (removedVersions AzureSEVSNPVersionList, err error) {
|
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 {
|
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 {
|
type putCmd struct {
|
||||||
apiObject apiclient.APIObject
|
apiObject apiclient.APIObject
|
||||||
|
signer sigstore.Signer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p putCmd) Execute(ctx context.Context, c *apiclient.Client) error {
|
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 {
|
func executeAllCmds(ctx context.Context, client *apiclient.Client, cmds []crudCmd) error {
|
||||||
|
@ -19,24 +19,19 @@ func TestUploadAzureSEVSNP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
version := AzureSEVSNPVersion{}
|
version := AzureSEVSNPVersion{}
|
||||||
date := time.Date(2023, 1, 1, 1, 1, 1, 1, time.UTC)
|
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)
|
ops := sut.constructUploadCmd(version, []string{"2021-01-01-01-01.json", "2019-01-01-01-01.json"}, date)
|
||||||
assert := assert.New(t)
|
|
||||||
assert.NoError(err)
|
|
||||||
dateStr := "2023-01-01-01-01.json"
|
dateStr := "2023-01-01-01-01.json"
|
||||||
|
assert := assert.New(t)
|
||||||
assert.Contains(ops, putCmd{
|
assert.Contains(ops, putCmd{
|
||||||
apiObject: AzureSEVSNPVersionAPI{
|
apiObject: AzureSEVSNPVersionAPI{
|
||||||
Version: dateStr,
|
Version: dateStr,
|
||||||
AzureSEVSNPVersion: version,
|
AzureSEVSNPVersion: version,
|
||||||
},
|
},
|
||||||
})
|
signer: fakeSigner{},
|
||||||
assert.Contains(ops, putCmd{
|
|
||||||
apiObject: AzureSEVSNPVersionSignature{
|
|
||||||
Version: dateStr,
|
|
||||||
Signature: []byte("signature"),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
assert.Contains(ops, putCmd{
|
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"}),
|
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",
|
Version: "2021-01-01.json",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
assert.Contains(ops, deleteCmd{
|
|
||||||
apiObject: AzureSEVSNPVersionSignature{
|
|
||||||
Version: "2021-01-01.json",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Contains(ops, putCmd{
|
assert.Contains(ops, putCmd{
|
||||||
apiObject: AzureSEVSNPVersionList([]string{"2023-01-01.json", "2019-01-01.json"}),
|
apiObject: AzureSEVSNPVersionList([]string{"2023-01-01.json", "2019-01-01.json"}),
|
||||||
|
@ -8,7 +8,6 @@ package attestationconfigapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -57,31 +56,17 @@ func newFetcherWithClientAndVerifier(client apifetcher.HTTPClient, cosignVerifie
|
|||||||
|
|
||||||
// FetchAzureSEVSNPVersionList fetches the version list information from the config API.
|
// FetchAzureSEVSNPVersionList fetches the version list information from the config API.
|
||||||
func (f *fetcher) FetchAzureSEVSNPVersionList(ctx context.Context, attestation AzureSEVSNPVersionList) (AzureSEVSNPVersionList, error) {
|
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)
|
return apifetcher.Fetch(ctx, f.HTTPClient, attestation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchAzureSEVSNPVersion fetches the version information from the config API.
|
// FetchAzureSEVSNPVersion fetches the version information from the config API.
|
||||||
func (f *fetcher) FetchAzureSEVSNPVersion(ctx context.Context, azureVersion AzureSEVSNPVersionAPI) (AzureSEVSNPVersionAPI, error) {
|
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 {
|
if err != nil {
|
||||||
return fetchedVersion, fmt.Errorf("fetch version %s: %w", fetchedVersion.Version, err)
|
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
|
return fetchedVersion, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,6 @@ type fakeConfigAPIHandler struct {
|
|||||||
|
|
||||||
// RoundTrip resolves the request and returns a dummy response.
|
// RoundTrip resolves the request and returns a dummy response.
|
||||||
func (f *fakeConfigAPIHandler) RoundTrip(req *http.Request) (*http.Response, error) {
|
func (f *fakeConfigAPIHandler) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
signature := []byte("placeholderSignature")
|
|
||||||
if req.URL.Path == "/constellation/v1/attestation/azure-sev-snp/list" {
|
if req.URL.Path == "/constellation/v1/attestation/azure-sev-snp/list" {
|
||||||
res := &http.Response{}
|
res := &http.Response{}
|
||||||
bt, err := json.Marshal(f.versions)
|
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.Body = io.NopCloser(bytes.NewReader(bt))
|
||||||
res.StatusCode = http.StatusOK
|
res.StatusCode = http.StatusOK
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
||||||
} else if req.URL.Path == fmt.Sprintf("/constellation/v1/attestation/azure-sev-snp/%s.sig", f.latestVersion) {
|
} else if req.URL.Path == fmt.Sprintf("/constellation/v1/attestation/azure-sev-snp/%s.sig", f.latestVersion) {
|
||||||
res := &http.Response{}
|
res := &http.Response{}
|
||||||
obj := AzureSEVSNPVersionSignature{
|
res.Body = io.NopCloser(bytes.NewReader([]byte("null")))
|
||||||
Signature: signature,
|
|
||||||
}
|
|
||||||
bt, err := json.Marshal(obj)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res.Body = io.NopCloser(bytes.NewReader(bt))
|
|
||||||
res.StatusCode = http.StatusOK
|
res.StatusCode = http.StatusOK
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
||||||
} else if req.URL.Path == fmt.Sprintf("/constellation/v1/attestation/azure-sev-snp/%s.sig", f.olderVersion) {
|
} else if req.URL.Path == fmt.Sprintf("/constellation/v1/attestation/azure-sev-snp/%s.sig", f.olderVersion) {
|
||||||
res := &http.Response{}
|
res := &http.Response{}
|
||||||
obj := AzureSEVSNPVersionSignature{
|
res.Body = io.NopCloser(bytes.NewReader([]byte("null")))
|
||||||
Signature: signature,
|
|
||||||
}
|
|
||||||
bt, err := json.Marshal(obj)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res.Body = io.NopCloser(bytes.NewReader(bt))
|
|
||||||
res.StatusCode = http.StatusOK
|
res.StatusCode = http.StatusOK
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
||||||
|
@ -374,5 +374,5 @@ func (s signature) ValidateRequest() error {
|
|||||||
|
|
||||||
// Validate checks that the signature is base64 encoded.
|
// Validate checks that the signature is base64 encoded.
|
||||||
func (s signature) Validate() error {
|
func (s signature) Validate() error {
|
||||||
return sigstore.IsBase64([]byte(s.Signature))
|
return sigstore.IsBase64(s.Signature)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user