Enable CLI verify with JSON output for Azure TDX

Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
Daniel Weiße 2024-06-11 13:44:07 +02:00
parent 574a0812b0
commit 3e91f1a53f
No known key found for this signature in database
GPG Key ID: 7DD3015F3DDE4B9C
5 changed files with 53 additions and 23 deletions

View File

@ -111,6 +111,9 @@ go_library(
"@io_k8s_sigs_yaml//:yaml",
"@org_golang_x_mod//semver",
"@org_golang_google_grpc//:grpc",
"@com_github_google_go_tdx_guest//abi",
"@com_github_google_go_tdx_guest//proto/tdx",
"//internal/attestation/azure/tdx",
] + select({
"@io_bazel_rules_go//go/platform:android_amd64": [
"@org_golang_x_sys//unix",

View File

@ -21,10 +21,9 @@ import (
"strconv"
"strings"
tpmProto "github.com/google/go-tpm-tools/proto/tpm"
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
"github.com/edgelesssys/constellation/v2/internal/atls"
azuretdx "github.com/edgelesssys/constellation/v2/internal/attestation/azure/tdx"
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
"github.com/edgelesssys/constellation/v2/internal/attestation/snp"
@ -38,6 +37,10 @@ import (
"github.com/edgelesssys/constellation/v2/internal/grpc/dialer"
"github.com/edgelesssys/constellation/v2/internal/verify"
"github.com/edgelesssys/constellation/v2/verify/verifyproto"
"github.com/google/go-tdx-guest/abi"
"github.com/google/go-tdx-guest/proto/tdx"
tpmProto "github.com/google/go-tpm-tools/proto/tpm"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@ -189,8 +192,9 @@ func (c *verifyCmd) verify(cmd *cobra.Command, verifyClient verifyClient, config
case "json":
if !(attConfig.GetVariant().Equal(variant.AzureSEVSNP{}) ||
attConfig.GetVariant().Equal(variant.AWSSEVSNP{}) ||
attConfig.GetVariant().Equal(variant.GCPSEVSNP{})) {
return errors.New("json output is only supported for SEV-SNP")
attConfig.GetVariant().Equal(variant.GCPSEVSNP{}) ||
attConfig.GetVariant().Equal(variant.AzureTDX{})) {
return errors.New("json output is only supported for SEV-SNP and TDX variants")
}
attDocOutput, err = formatJSON(cmd.Context(), rawAttestationDoc, attConfig, c.log)
@ -247,13 +251,24 @@ func (c *verifyCmd) validateEndpointFlag(cmd *cobra.Command, stateFile *state.St
// formatJSON returns the json formatted attestation doc.
func formatJSON(ctx context.Context, docString string, attestationCfg config.AttestationCfg, log debugLog,
) (string, error) {
var doc attestationDoc
var doc vtpm.AttestationDocument
if err := json.Unmarshal([]byte(docString), &doc); err != nil {
return "", fmt.Errorf("unmarshalling attestation document: %w", err)
}
if (attestationCfg.GetVariant().Equal(variant.AWSSEVSNP{}) ||
attestationCfg.GetVariant().Equal(variant.AzureSEVSNP{}) ||
attestationCfg.GetVariant().Equal(variant.GCPSEVSNP{})) {
return snpFormatJSON(ctx, doc.InstanceInfo, attestationCfg, log)
}
return tdxFormatJSON(doc.InstanceInfo, attestationCfg)
}
func snpFormatJSON(ctx context.Context, instanceInfoRaw []byte, attestationCfg config.AttestationCfg, log debugLog,
) (string, error) {
var instanceInfo snp.InstanceInfo
if err := json.Unmarshal(doc.InstanceInfo, &instanceInfo); err != nil {
if err := json.Unmarshal(instanceInfoRaw, &instanceInfo); err != nil {
return "", fmt.Errorf("unmarshalling instance info: %w", err)
}
report, err := verify.NewReport(ctx, instanceInfo, attestationCfg, log)
@ -262,17 +277,40 @@ func formatJSON(ctx context.Context, docString string, attestationCfg config.Att
}
jsonBytes, err := json.Marshal(report)
return string(jsonBytes), err
}
func tdxFormatJSON(instanceInfoRaw []byte, attestationCfg config.AttestationCfg) (string, error) {
var rawQuote []byte
if attestationCfg.GetVariant().Equal(variant.AzureTDX{}) {
var instanceInfo azuretdx.InstanceInfo
if err := json.Unmarshal(instanceInfoRaw, &instanceInfo); err != nil {
return "", fmt.Errorf("unmarshalling instance info: %w", err)
}
rawQuote = instanceInfo.AttestationReport
}
tdxQuote, err := abi.QuoteToProto(rawQuote)
if err != nil {
return "", fmt.Errorf("converting quote to proto: %w", err)
}
quote, ok := tdxQuote.(*tdx.QuoteV4)
if !ok {
return "", fmt.Errorf("unexpected quote type: %T", tdxQuote)
}
quoteJSON, err := json.Marshal(quote)
return string(quoteJSON), err
}
// format returns the formatted attestation doc.
func formatDefault(ctx context.Context, docString string, attestationCfg config.AttestationCfg, log debugLog,
) (string, error) {
b := &strings.Builder{}
b.WriteString("Attestation Document:\n")
var doc attestationDoc
var doc vtpm.AttestationDocument
if err := json.Unmarshal([]byte(docString), &doc); err != nil {
return "", fmt.Errorf("unmarshal attestation document: %w", err)
}
@ -330,18 +368,6 @@ func parseQuotes(b *strings.Builder, quotes []*tpmProto.Quote, expectedPCRs meas
return nil
}
// attestationDoc is the attestation document returned by the verifier.
type attestationDoc struct {
Attestation struct {
AkPub string `json:"ak_pub"`
Quotes []*tpmProto.Quote `json:"quotes"`
EventLog string `json:"event_log"`
TeeAttestation interface{} `json:"TeeAttestation"`
} `json:"Attestation"`
InstanceInfo []byte `json:"InstanceInfo"`
UserData []byte `json:"UserData"`
}
type constellationVerifier struct {
dialer grpcInsecureDialer
log debugLog

View File

@ -90,7 +90,7 @@ func (i *Issuer) getInstanceInfo(ctx context.Context, tpm io.ReadWriteCloser, _
return nil, fmt.Errorf("getting quote: %w", err)
}
instanceInfo := instanceInfo{
instanceInfo := InstanceInfo{
AttestationReport: quote,
RuntimeData: runtimeData,
}

View File

@ -19,7 +19,8 @@ More specifically:
*/
package tdx
type instanceInfo struct {
// InstanceInfo wraps the TDX report with additional Azure specific runtime data.
type InstanceInfo struct {
AttestationReport []byte
RuntimeData []byte
}

View File

@ -58,7 +58,7 @@ func NewValidator(cfg *config.AzureTDX, log attestation.Logger) *Validator {
}
func (v *Validator) getTrustedTPMKey(_ context.Context, attDoc vtpm.AttestationDocument, _ []byte) (crypto.PublicKey, error) {
var instanceInfo instanceInfo
var instanceInfo InstanceInfo
if err := json.Unmarshal(attDoc.InstanceInfo, &instanceInfo); err != nil {
return nil, err
}