-
Notifications
You must be signed in to change notification settings - Fork 47
/
fetcher.go
111 lines (91 loc) · 4.11 KB
/
fetcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package attestationconfigapi
import (
"context"
"errors"
"fmt"
apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher"
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/sigstore"
)
const cosignPublicKey = constants.CosignPublicKeyReleases
// ErrNoVersionsFound is returned if no versions are found.
var ErrNoVersionsFound = errors.New("no versions found")
// Fetcher fetches config API resources without authentication.
type Fetcher interface {
FetchSEVSNPVersion(ctx context.Context, version SEVSNPVersionAPI) (SEVSNPVersionAPI, error)
FetchSEVSNPVersionList(ctx context.Context, list SEVSNPVersionList) (SEVSNPVersionList, error)
FetchSEVSNPVersionLatest(ctx context.Context, attestation variant.Variant) (SEVSNPVersionAPI, error)
}
// fetcher fetches AttestationCfg API resources without authentication.
type fetcher struct {
apifetcher.HTTPClient
cdnURL string
verifier sigstore.Verifier
}
// NewFetcher returns a new apifetcher.
func NewFetcher() Fetcher {
return NewFetcherWithClient(apifetcher.NewHTTPClient(), constants.CDNRepositoryURL)
}
// NewFetcherWithCustomCDNAndCosignKey returns a new fetcher with custom CDN URL.
func NewFetcherWithCustomCDNAndCosignKey(cdnURL, cosignKey string) Fetcher {
verifier, err := sigstore.NewCosignVerifier([]byte(cosignKey))
if err != nil {
// This relies on an embedded public key. If this key can not be validated, there is no way to recover from this.
panic(fmt.Errorf("creating cosign verifier: %w", err))
}
return newFetcherWithClientAndVerifier(apifetcher.NewHTTPClient(), verifier, cdnURL)
}
// NewFetcherWithClient returns a new fetcher with custom http client.
func NewFetcherWithClient(client apifetcher.HTTPClient, cdnURL string) Fetcher {
verifier, err := sigstore.NewCosignVerifier([]byte(cosignPublicKey))
if err != nil {
// This relies on an embedded public key. If this key can not be validated, there is no way to recover from this.
panic(fmt.Errorf("creating cosign verifier: %w", err))
}
return newFetcherWithClientAndVerifier(client, verifier, cdnURL)
}
func newFetcherWithClientAndVerifier(client apifetcher.HTTPClient, cosignVerifier sigstore.Verifier, url string) Fetcher {
return &fetcher{HTTPClient: client, verifier: cosignVerifier, cdnURL: url}
}
// FetchSEVSNPVersionList fetches the version list information from the config API.
func (f *fetcher) FetchSEVSNPVersionList(ctx context.Context, list SEVSNPVersionList) (SEVSNPVersionList, error) {
// TODO(derpsteb): Replace with FetchAndVerify once we move to v2 of the config API.
fetchedList, err := apifetcher.Fetch(ctx, f.HTTPClient, f.cdnURL, list)
if err != nil {
return list, fmt.Errorf("fetching version list: %w", err)
}
// Need to set this explicitly as the variant is not part of the marshalled JSON.
fetchedList.variant = list.variant
return fetchedList, nil
}
// FetchSEVSNPVersion fetches the version information from the config API.
func (f *fetcher) FetchSEVSNPVersion(ctx context.Context, version SEVSNPVersionAPI) (SEVSNPVersionAPI, error) {
fetchedVersion, err := apifetcher.FetchAndVerify(ctx, f.HTTPClient, f.cdnURL, version, f.verifier)
if err != nil {
return fetchedVersion, fmt.Errorf("fetching version %s: %w", version.Version, err)
}
// Need to set this explicitly as the variant is not part of the marshalled JSON.
fetchedVersion.Variant = version.Variant
return fetchedVersion, nil
}
// FetchSEVSNPVersionLatest returns the latest versions of the given type.
func (f *fetcher) FetchSEVSNPVersionLatest(ctx context.Context, attesation variant.Variant) (res SEVSNPVersionAPI, err error) {
list, err := f.FetchSEVSNPVersionList(ctx, SEVSNPVersionList{variant: attesation})
if err != nil {
return res, ErrNoVersionsFound
}
getVersionRequest := SEVSNPVersionAPI{
Version: list.List()[0], // latest version is first in list
Variant: attesation,
}
res, err = f.FetchSEVSNPVersion(ctx, getVersionRequest)
if err != nil {
return res, err
}
return
}