hack: remove azure-snp-report-verify

Signed-off-by: Paul Meyer <49727155+katexochen@users.noreply.github.com>
This commit is contained in:
Paul Meyer 2023-08-11 18:59:11 +02:00
parent 001219d26a
commit 30df225ccc
5 changed files with 1 additions and 223 deletions

View File

@ -1,19 +0,0 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "azure-snp-report-verify_lib",
srcs = ["verify.go"],
importpath = "github.com/edgelesssys/constellation/v2/hack/azure-snp-report-verify",
visibility = ["//visibility:private"],
deps = [
"//internal/api/attestationconfigapi",
"@in_gopkg_square_go_jose_v2//:go-jose_v2",
"@in_gopkg_square_go_jose_v2//jwt",
],
)
go_binary(
name = "azure-snp-report-verify",
embed = [":azure-snp-report-verify_lib"],
visibility = ["//visibility:public"],
)

View File

@ -1,16 +0,0 @@
FROM ubuntu:20.04@sha256:33a5cc25d22c45900796a1aca487ad7a7cb09f09ea00b779e3b2026b4fc2faba AS build
RUN apt-get update && apt-get install -y \
build-essential \
libcurl4-openssl-dev \
wget
RUN wget -q https://packages.microsoft.com/repos/azurecore/pool/main/a/azguestattestation1/azguestattestation1_1.0.2_amd64.deb \
&& apt-get install /azguestattestation1_1.0.2_amd64.deb
RUN wget -q https://github.com/Azure/confidential-computing-cvm-guest-attestation/raw/4bd89d2808912fbaa319e8853e6f5e1e245d45ca/cvm-guest-attestation-linux-app/main.cpp \
&& sed -i s/test.attest.azure.net/attest.azure.net/ main.cpp \
&& touch Utils.h \
&& g++ -Os -I/usr/include/azguestattestation1 -oclient main.cpp -lazguestattestation
FROM ubuntu:20.04@sha256:33a5cc25d22c45900796a1aca487ad7a7cb09f09ea00b779e3b2026b4fc2faba AS release
COPY --from=build client azguestattestation1_1.0.2_amd64.deb /
RUN apt-get update && apt-get install -y /azguestattestation1_1.0.2_amd64.deb
ENTRYPOINT ["/client"]

View File

@ -1,21 +0,0 @@
# Obtain current Azure SNP ID key digest & firmware versions
On Azure, Constellation verifies that the SNP attestation report contains Azure's ID key digest.
Additionally, some firmware security version numbers (SVNs) are validated.
Currently, the only way to verify the digest's origin is to perform guest attestation with the help of the Microsoft Azure Attestation (MAA) service.
There's a [sample](https://github.com/Azure/confidential-computing-cvm-guest-attestation) on how to do this, but it's not straightforward.
So we created tooling to make things easier.
Perform the following steps to get the ID key digest & firmware versions:
1. Create an Ubuntu CVM on Azure with secure boot enabled and ssh into it.
2. Run
```
docker run --rm --privileged -v/sys/kernel/security:/sys/kernel/security ghcr.io/edgelesssys/constellation/azure-snp-reporter
```
This executes the guest attestation and prints the JWT received from the MAA. (It's the long base64 blob.)
3. Copy the JWT and run **on your local trusted machine**:
```
go run verify.go <jwt>
```
On success it prints the ID key digest and relevant firmware SVNs.

View File

@ -1,166 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
// Verify verifies an MAA JWT and prints the SNP ID key digest on success.
package main
import (
"context"
"crypto/x509"
"encoding/base64"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"net/http"
"os"
"time"
configapi "github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)
// IsolationTEE describes an Azure SNP TEE.
type IsolationTEE struct {
IDKeyDigest string `json:"x-ms-sevsnpvm-idkeydigest"`
TEESvn int `json:"x-ms-sevsnpvm-tee-svn"`
SNPFwSvn int `json:"x-ms-sevsnpvm-snpfw-svn"`
MicrocodeSvn int `json:"x-ms-sevsnpvm-microcode-svn"`
BootloaderSvn int `json:"x-ms-sevsnpvm-bootloader-svn"`
GuestSvn int `json:"x-ms-sevsnpvm-guestsvn"`
}
// PrintSVNs prints the relevant Security Version Numbers (SVNs).
func (i *IsolationTEE) PrintSVNs() {
fmt.Println("\tTEE SVN:", i.TEESvn)
fmt.Println("\tSNP FW SVN:", i.SNPFwSvn)
fmt.Println("\tMicrocode SVN:", i.MicrocodeSvn)
fmt.Println("\tBootloader SVN:", i.BootloaderSvn)
fmt.Println("\tGuest SVN:", i.GuestSvn)
}
func main() {
configAPIExportPath := flag.String("export-path", "azure-sev-snp-version.json", "Path to the exported config API file.")
maaJWT := flag.String("report", "", "MAA JWT report to verify")
flag.Parse()
if *maaJWT == "" {
fmt.Println("Must provide --report")
return
}
report, err := getTEEReport(*maaJWT)
if err != nil {
panic(err)
}
fmt.Println("Successfully validated ID key digest:", report.IDKeyDigest)
fmt.Println("Currently reported SVNs:")
report.PrintSVNs()
if *configAPIExportPath != "" {
configAPIVersion := convertToConfigAPIFile(report)
if err := exportToJSONFile(configAPIVersion, *configAPIExportPath); err != nil {
panic(err)
}
fmt.Println("Successfully exported config API file to:", configAPIExportPath)
}
}
func convertToConfigAPIFile(i IsolationTEE) configapi.AzureSEVSNPVersion {
return configapi.AzureSEVSNPVersion{
Bootloader: uint8(i.BootloaderSvn),
TEE: uint8(i.TEESvn),
SNP: uint8(i.SNPFwSvn),
Microcode: uint8(i.MicrocodeSvn),
}
}
func exportToJSONFile(configAPIVersion configapi.AzureSEVSNPVersion, configAPIExportPath string) error {
data, err := json.Marshal(configAPIVersion)
if err != nil {
return err
}
return os.WriteFile(configAPIExportPath, data, 0o644)
}
func getTEEReport(rawToken string) (IsolationTEE, error) {
// Parse token.
token, err := jwt.ParseSigned(rawToken)
if err != nil {
return IsolationTEE{}, err
}
// Get JSON Web Key set.
keySetBytes, err := httpGet(context.Background(), "https://sharedeus.eus.attest.azure.net/certs")
if err != nil {
return IsolationTEE{}, err
}
keySet, err := parseKeySet(keySetBytes)
if err != nil {
return IsolationTEE{}, err
}
// Get claims. Private claims contain ID Key digest.
var publicClaims jwt.Claims
var privateClaims struct {
IsolationTEE IsolationTEE `json:"x-ms-isolation-tee"`
}
if err := token.Claims(&keySet, &publicClaims, &privateClaims); err != nil {
return IsolationTEE{}, err
}
if err := publicClaims.Validate(jwt.Expected{Time: time.Now()}); err != nil {
return IsolationTEE{}, err
}
return privateClaims.IsolationTEE, nil
}
func parseKeySet(keySetBytes []byte) (jose.JSONWebKeySet, error) {
var rawKeySet struct {
Keys []struct {
X5c []string
Kid string
}
}
if err := json.Unmarshal(keySetBytes, &rawKeySet); err != nil {
return jose.JSONWebKeySet{}, err
}
var keySet jose.JSONWebKeySet
for _, key := range rawKeySet.Keys {
rawCert, _ := base64.StdEncoding.DecodeString(key.X5c[0])
cert, err := x509.ParseCertificate(rawCert)
if err != nil {
return jose.JSONWebKeySet{}, err
}
keySet.Keys = append(keySet.Keys, jose.JSONWebKey{KeyID: key.Kid, Key: cert.PublicKey})
}
return keySet, nil
}
func httpGet(ctx context.Context, url string) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}

View File

@ -51,7 +51,6 @@ require (
go.uber.org/zap v1.24.0
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
golang.org/x/mod v0.12.0
gopkg.in/square/go-jose.v2 v2.6.0
libvirt.org/go/libvirt v1.9004.0
)
@ -297,6 +296,7 @@ require (
google.golang.org/grpc v1.56.2 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect