AB#2350: Configurably enforce idkeydigest on Azure

* Add join-config entry for "enforceIdKeyDigest" bool
* Add join-config entry for "idkeydigest"
* Initially filled with TPM value from bootstrapper
* Add config entries for idkeydigest and enforceIdKeyDigest
* Extend azure attestation validator to check idkeydigest,
if configured.
* Update unittests
* Add logger to NewValidator for all CSPs
* Add csp to Updateable type

Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com>
Co-authored-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
Otto Bittner 2022-08-29 16:41:09 +02:00
parent c84e44913b
commit 4adc19b7f5
31 changed files with 350 additions and 136 deletions

View file

@ -3,6 +3,7 @@ package cloudcmd
import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
@ -17,10 +18,12 @@ import (
)
type Validator struct {
provider cloudprovider.Provider
pcrs map[uint32][]byte
enforcedPCRs []uint32
validator atls.Validator
provider cloudprovider.Provider
pcrs map[uint32][]byte
enforcedPCRs []uint32
idkeydigest []byte
enforceIdKeyDigest bool
validator atls.Validator
}
func NewValidator(provider cloudprovider.Provider, config *config.Config) (*Validator, error) {
@ -32,6 +35,16 @@ func NewValidator(provider cloudprovider.Provider, config *config.Config) (*Vali
if err := v.setPCRs(config); err != nil {
return nil, err
}
if v.provider == cloudprovider.Azure {
idkeydigest, err := hex.DecodeString(config.Provider.Azure.IdKeyDigest)
if err != nil {
return nil, fmt.Errorf("bad config: decoding idkeydigest from config: %w", err)
}
v.enforceIdKeyDigest = *config.Provider.Azure.EnforceIdKeyDigest
v.idkeydigest = idkeydigest
}
return &v, nil
}
@ -116,15 +129,15 @@ func (v *Validator) PCRS() map[uint32][]byte {
}
func (v *Validator) updateValidator(cmd *cobra.Command) {
log := warnLogger{cmd: cmd}
switch v.provider {
case cloudprovider.GCP:
v.validator = gcp.NewValidator(v.pcrs, v.enforcedPCRs)
v.validator = gcp.NewValidator(v.pcrs, v.enforcedPCRs, log)
case cloudprovider.Azure:
v.validator = azure.NewValidator(v.pcrs, v.enforcedPCRs)
v.validator = azure.NewValidator(v.pcrs, v.enforcedPCRs, v.idkeydigest, v.enforceIdKeyDigest, log)
case cloudprovider.QEMU:
v.validator = qemu.NewValidator(v.pcrs, v.enforcedPCRs)
v.validator = qemu.NewValidator(v.pcrs, v.enforcedPCRs, log)
}
v.validator.AddLogger(warnLogger{cmd: cmd})
}
func (v *Validator) checkPCRs(pcrs map[uint32][]byte, enforcedPCRs []uint32) error {

View file

@ -29,10 +29,12 @@ func TestNewValidator(t *testing.T) {
}
testCases := map[string]struct {
provider cloudprovider.Provider
config *config.Config
pcrs map[uint32][]byte
wantErr bool
provider cloudprovider.Provider
config *config.Config
pcrs map[uint32][]byte
enforceIdKeyDigest bool
idkeydigest string
wantErr bool
}{
"gcp": {
provider: cloudprovider.GCP,
@ -61,6 +63,19 @@ func TestNewValidator(t *testing.T) {
pcrs: testPCRs,
wantErr: true,
},
"set idkeydigest": {
provider: cloudprovider.Azure,
pcrs: testPCRs,
idkeydigest: "414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141",
enforceIdKeyDigest: true,
},
"invalid idkeydigest": {
provider: cloudprovider.Azure,
pcrs: testPCRs,
idkeydigest: "41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414",
enforceIdKeyDigest: true,
wantErr: true,
},
}
for name, tc := range testCases {
@ -74,7 +89,7 @@ func TestNewValidator(t *testing.T) {
}
if tc.provider == cloudprovider.Azure {
measurements := config.Measurements(tc.pcrs)
conf.Provider.Azure = &config.AzureConfig{Measurements: measurements}
conf.Provider.Azure = &config.AzureConfig{Measurements: measurements, EnforceIdKeyDigest: &tc.enforceIdKeyDigest, IdKeyDigest: tc.idkeydigest}
}
if tc.provider == cloudprovider.QEMU {
measurements := config.Measurements(tc.pcrs)
@ -96,6 +111,7 @@ func TestNewValidator(t *testing.T) {
func TestValidatorV(t *testing.T) {
zero := []byte("00000000000000000000000000000000")
newTestPCRs := func() map[uint32][]byte {
return map[uint32][]byte{
0: zero,
@ -122,17 +138,17 @@ func TestValidatorV(t *testing.T) {
"gcp": {
provider: cloudprovider.GCP,
pcrs: newTestPCRs(),
wantVs: gcp.NewValidator(newTestPCRs(), nil),
wantVs: gcp.NewValidator(newTestPCRs(), nil, nil),
},
"azure": {
provider: cloudprovider.Azure,
pcrs: newTestPCRs(),
wantVs: azure.NewValidator(newTestPCRs(), nil),
wantVs: azure.NewValidator(newTestPCRs(), nil, nil, false, nil),
},
"qemu": {
provider: cloudprovider.QEMU,
pcrs: newTestPCRs(),
wantVs: qemu.NewValidator(newTestPCRs(), nil),
wantVs: qemu.NewValidator(newTestPCRs(), nil, nil),
},
}

View file

@ -140,6 +140,7 @@ func initialize(cmd *cobra.Command, newDialer func(validator *cloudcmd.Validator
SshUserKeys: ssh.ToProtoSlice(sshUsers),
HelmDeployments: helmDeployments,
EnforcedPcrs: getEnforcedMeasurements(provider, config),
EnforceIdkeydigest: getEnforceIdKeyDigest(provider, config),
}
resp, err := initCall(cmd.Context(), newDialer(validator), flags.endpoint, req)
if err != nil {
@ -236,6 +237,15 @@ func getEnforcedMeasurements(provider cloudprovider.Provider, config *config.Con
}
}
func getEnforceIdKeyDigest(provider cloudprovider.Provider, config *config.Config) bool {
switch provider {
case cloudprovider.Azure:
return *config.Provider.Azure.EnforceIdKeyDigest
default:
return false
}
}
// evalFlagArgs gets the flag values and does preprocessing of these values like
// reading the content from file path flags and deriving other values from flag combinations.
func evalFlagArgs(cmd *cobra.Command, fileHandler file.Handler) (initFlags, error) {

View file

@ -14,7 +14,6 @@ import (
"github.com/edgelesssys/constellation/bootstrapper/initproto"
"github.com/edgelesssys/constellation/cli/internal/cloudcmd"
"github.com/edgelesssys/constellation/internal/attestation/vtpm"
"github.com/edgelesssys/constellation/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/internal/cloud/cloudtypes"
"github.com/edgelesssys/constellation/internal/config"
@ -505,8 +504,6 @@ func (v *testValidator) Validate(attDoc []byte, nonce []byte) ([]byte, error) {
return attestation.UserData, nil
}
func (v *testValidator) AddLogger(vtpm.WarnLogger) {}
type testIssuer struct {
oid.Getter
pcrs map[uint32][]byte