config: disable user-facing version Azure SEV SNP fetch for v2.8 (#1882)

* config: disable user-facing version fetch for Azure SEV SNP

don't allow "latest" value and disable user-facing version fetcher for Azure SEV SNP

Co-authored-by: @derpsteb

* fix unittests

* attestation: getTrustedKey

---------

Co-authored-by: Otto Bittner <cobittner@posteo.net>
This commit is contained in:
Adrian Stobbe 2023-06-06 10:44:13 +02:00 committed by GitHub
parent 7c07e3be18
commit c7b22d314a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 121 additions and 48 deletions

View File

@ -218,6 +218,10 @@ func TestTrustedKeyFromSNP(t *testing.T) {
AcceptedKeyDigests: tc.idkeydigests, AcceptedKeyDigests: tc.idkeydigests,
EnforcementPolicy: tc.enforceIDKeyDigest, EnforcementPolicy: tc.enforceIDKeyDigest,
} }
cfg.BootloaderVersion = config.AttestationVersion{Value: 2}
cfg.TEEVersion = config.AttestationVersion{Value: 0}
cfg.MicrocodeVersion = config.AttestationVersion{Value: 93}
cfg.SNPVersion = config.AttestationVersion{Value: 6}
validator := &Validator{ validator := &Validator{
hclValidator: &instanceInfo, hclValidator: &instanceInfo,
@ -349,6 +353,12 @@ func TestNewSNPReportFromBytes(t *testing.T) {
}, },
} }
cfg := config.DefaultForAzureSEVSNP() cfg := config.DefaultForAzureSEVSNP()
cfg.BootloaderVersion = config.AttestationVersion{Value: 2}
cfg.TEEVersion = config.AttestationVersion{Value: 0}
cfg.MicrocodeVersion = config.AttestationVersion{Value: 93}
cfg.SNPVersion = config.AttestationVersion{Value: 6}
for name, tc := range testCases { for name, tc := range testCases {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)

View File

@ -8,6 +8,7 @@ package config
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"strings" "strings"
) )
@ -33,7 +34,7 @@ func (v AttestationVersion) MarshalYAML() (any, error) {
if v.IsLatest { if v.IsLatest {
return "latest", nil return "latest", nil
} }
return v.Value, nil return int(v.Value), nil
} }
// UnmarshalYAML implements a custom unmarshaller to resolve "atest" values. // UnmarshalYAML implements a custom unmarshaller to resolve "atest" values.
@ -67,13 +68,17 @@ func (v *AttestationVersion) parseRawUnmarshal(rawUnmarshal any) error {
switch s := rawUnmarshal.(type) { switch s := rawUnmarshal.(type) {
case string: case string:
if strings.ToLower(s) == "latest" { if strings.ToLower(s) == "latest" {
v.IsLatest = true // TODO(elchead): activate latest logic for next release AB#3036
v.Value = placeholderVersionValue return errors.New("latest is not supported as a version value")
} else { // v.IsLatest = true
return fmt.Errorf("invalid version value: %s", s) // v.Value = placeholderVersionValue
} }
return fmt.Errorf("invalid version value: %s", s)
case int: case int:
v.Value = uint8(s) v.Value = uint8(s)
// yaml spec allows "1" as float64, so version number might come as a float: https://github.com/go-yaml/yaml/issues/430
case float64:
v.Value = uint8(s)
default: default:
return fmt.Errorf("invalid version value type: %s", s) return fmt.Errorf("invalid version value type: %s", s)
} }

View File

@ -9,6 +9,7 @@ package config
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -44,3 +45,39 @@ func TestVersionMarshalYAML(t *testing.T) {
}) })
} }
} }
func TestVersionUnmarshalYAML(t *testing.T) {
tests := []struct {
name string
expected AttestationVersion
yamlInput string
wantErr bool
}{
// TODO(elchead): activate latest logic for next release AB#3036
{
name: "latest value is not allowed",
expected: AttestationVersion{},
yamlInput: "latest\n",
wantErr: true,
},
{
name: "value 5 resolves to 5",
expected: AttestationVersion{
Value: 5,
},
yamlInput: "5\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sut := AttestationVersion{}
err := yaml.Unmarshal([]byte(tt.yamlInput), &sut)
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.expected.IsLatest, sut.IsLatest)
})
}
}

View File

@ -387,18 +387,19 @@ func fromFile(fileHandler file.Handler, name string) (*Config, error) {
// 2. For "latest" version values of the attestation variants fetch the version numbers. // 2. For "latest" version values of the attestation variants fetch the version numbers.
// 3. Read secrets from environment variables. // 3. Read secrets from environment variables.
// 4. Validate config. If `--force` is set the version validation will be disabled and any version combination is allowed. // 4. Validate config. If `--force` is set the version validation will be disabled and any version combination is allowed.
func New(fileHandler file.Handler, name string, fetcher attestationconfigfetcher.AttestationConfigAPIFetcher, force bool) (*Config, error) { func New(fileHandler file.Handler, name string, _ attestationconfigfetcher.AttestationConfigAPIFetcher, force bool) (*Config, error) {
// Read config file // Read config file
c, err := fromFile(fileHandler, name) c, err := fromFile(fileHandler, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if azure := c.Attestation.AzureSEVSNP; azure != nil { // TODO(elchead): activate latest logic for next release AB#3036
if err := azure.FetchAndSetLatestVersionNumbers(fetcher); err != nil { //if azure := c.Attestation.AzureSEVSNP; azure != nil {
return c, err // if err := azure.FetchAndSetLatestVersionNumbers(fetcher); err != nil {
} // return c, err
} // }
//}
// Read secrets from env-vars. // Read secrets from env-vars.
clientSecretValue := os.Getenv(constants.EnvVarAzureClientSecretValue) clientSecretValue := os.Getenv(constants.EnvVarAzureClientSecretValue)
@ -925,12 +926,19 @@ type AzureSEVSNP struct {
// DefaultForAzureSEVSNP returns the default configuration for Azure SEV-SNP attestation. // DefaultForAzureSEVSNP returns the default configuration for Azure SEV-SNP attestation.
// Version numbers have placeholder values and the latest available values can be fetched using [AzureSEVSNP.FetchAndSetLatestVersionNumbers]. // Version numbers have placeholder values and the latest available values can be fetched using [AzureSEVSNP.FetchAndSetLatestVersionNumbers].
func DefaultForAzureSEVSNP() *AzureSEVSNP { func DefaultForAzureSEVSNP() *AzureSEVSNP {
// TODO(elchead): activate latest logic for next release AB#3036
azureSNPCfg := configapi.AzureSEVSNPVersion{
Bootloader: 3,
TEE: 0,
SNP: 8,
Microcode: 115,
}
return &AzureSEVSNP{ return &AzureSEVSNP{
Measurements: measurements.DefaultsFor(cloudprovider.Azure, variant.AzureSEVSNP{}), Measurements: measurements.DefaultsFor(cloudprovider.Azure, variant.AzureSEVSNP{}),
BootloaderVersion: NewLatestPlaceholderVersion(), BootloaderVersion: AttestationVersion{Value: azureSNPCfg.Bootloader}, // NewLatestPlaceholderVersion(),
TEEVersion: NewLatestPlaceholderVersion(), TEEVersion: AttestationVersion{Value: azureSNPCfg.TEE}, // NewLatestPlaceholderVersion(),
SNPVersion: NewLatestPlaceholderVersion(), SNPVersion: AttestationVersion{Value: azureSNPCfg.SNP}, // NewLatestPlaceholderVersion(),
MicrocodeVersion: NewLatestPlaceholderVersion(), MicrocodeVersion: AttestationVersion{Value: azureSNPCfg.Microcode}, // NewLatestPlaceholderVersion(),
FirmwareSignerConfig: SNPFirmwareSignerConfig{ FirmwareSignerConfig: SNPFirmwareSignerConfig{
AcceptedKeyDigests: idkeydigest.DefaultList(), AcceptedKeyDigests: idkeydigest.DefaultList(),
EnforcementPolicy: idkeydigest.MAAFallback, EnforcementPolicy: idkeydigest.MAAFallback,

View File

@ -41,20 +41,21 @@ func TestDefaultConfig(t *testing.T) {
assert.NotNil(def) assert.NotNil(def)
} }
func TestDefaultConfigWritesLatestVersion(t *testing.T) { // TODO(elchead): activate latest logic for next release AB#3036
conf := Default() // func TestDefaultConfigWritesLatestVersion(t *testing.T) {
bt, err := yaml.Marshal(conf) // conf := Default()
require := require.New(t) // bt, err := yaml.Marshal(conf)
require.NoError(err) // require := require.New(t)
// require.NoError(err)
var mp configMap // var mp configMap
require.NoError(yaml.Unmarshal(bt, &mp)) // require.NoError(yaml.Unmarshal(bt, &mp))
assert := assert.New(t) // assert := assert.New(t)
assert.Equal("latest", mp.getAzureSEVSNPVersion("microcodeVersion")) // assert.Equal("latest", mp.getAzureSEVSNPVersion("microcodeVersion"))
assert.Equal("latest", mp.getAzureSEVSNPVersion("teeVersion")) // assert.Equal("latest", mp.getAzureSEVSNPVersion("teeVersion"))
assert.Equal("latest", mp.getAzureSEVSNPVersion("snpVersion")) // assert.Equal("latest", mp.getAzureSEVSNPVersion("snpVersion"))
assert.Equal("latest", mp.getAzureSEVSNPVersion("bootloaderVersion")) // assert.Equal("latest", mp.getAzureSEVSNPVersion("bootloaderVersion"))
} //}
func TestReadConfigFile(t *testing.T) { func TestReadConfigFile(t *testing.T) {
testCases := map[string]struct { testCases := map[string]struct {
@ -63,29 +64,41 @@ func TestReadConfigFile(t *testing.T) {
wantResult *Config wantResult *Config
wantErr bool wantErr bool
}{ }{
"mix of Latest and uint as version value": { // TODO(elchead): activate latest logic for next release AB#3036
//"mix of Latest and uint as version value": {
// config: func() configMap {
// conf := Default()
// m := getConfigAsMap(conf, t)
// m.setAzureSEVSNPVersion("microcodeVersion", "Latest") // check uppercase also works
// m.setAzureSEVSNPVersion("teeVersion", 2)
// m.setAzureSEVSNPVersion("bootloaderVersion", 1)
// return m
// }(),
// configName: constants.ConfigFilename,
// wantResult: func() *Config {
// conf := Default()
// conf.Attestation.AzureSEVSNP.BootloaderVersion = AttestationVersion{
// Value: 1,
// IsLatest: false,
// }
// conf.Attestation.AzureSEVSNP.TEEVersion = AttestationVersion{
// Value: 2,
// IsLatest: false,
// }
// return conf
// }(),
//},
// TODO(elchead): activate latest logic for next release AB#3036
"refuse invalid latest value": {
config: func() configMap { config: func() configMap {
conf := Default() conf := Default()
m := getConfigAsMap(conf, t) m := getConfigAsMap(conf, t)
m.setAzureSEVSNPVersion("microcodeVersion", "Latest") // check uppercase also works m.setAzureSEVSNPVersion("microcodeVersion", "latest")
m.setAzureSEVSNPVersion("teeVersion", 2)
m.setAzureSEVSNPVersion("bootloaderVersion", 1)
return m return m
}(), }(),
configName: constants.ConfigFilename, configName: constants.ConfigFilename,
wantResult: func() *Config { wantErr: true,
conf := Default()
conf.Attestation.AzureSEVSNP.BootloaderVersion = AttestationVersion{
Value: 1,
IsLatest: false,
}
conf.Attestation.AzureSEVSNP.TEEVersion = AttestationVersion{
Value: 2,
IsLatest: false,
}
return conf
}(),
}, },
"refuse invalid version value": { "refuse invalid version value": {
config: func() configMap { config: func() configMap {
@ -876,9 +889,9 @@ func (c configMap) setAzureSEVSNPVersion(versionType string, value interface{})
c["attestation"].(configMap)["azureSEVSNP"].(configMap)[versionType] = value c["attestation"].(configMap)["azureSEVSNP"].(configMap)[versionType] = value
} }
func (c configMap) getAzureSEVSNPVersion(versionType string) interface{} { //func (c configMap) getAzureSEVSNPVersion(versionType string) interface{} {
return c["attestation"].(configMap)["azureSEVSNP"].(configMap)[versionType] // return c["attestation"].(configMap)["azureSEVSNP"].(configMap)[versionType]
} //}
// getConfigAsMap returns a map of the config. // getConfigAsMap returns a map of the config.
func getConfigAsMap(conf *Config, t *testing.T) (res configMap) { func getConfigAsMap(conf *Config, t *testing.T) (res configMap) {