mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-09-26 19:41:05 -04:00
AB#2413: Add workflow for snp-report-verify
* Extend azure-snp-report-verify to also report fw SVNs. * Add workflow based on azure-cvm to get maa-jwt and verify it on a second runner.
This commit is contained in:
parent
d85b281570
commit
0eb4a7831b
6 changed files with 133 additions and 18 deletions
|
@ -10,7 +10,7 @@ RUN wget -q https://github.com/Azure/confidential-computing-cvm-guest-attestatio
|
|||
&& touch Utils.h \
|
||||
&& g++ -Os -I/usr/include/azguestattestation1 -oclient main.cpp -lazguestattestation
|
||||
|
||||
FROM ubuntu:20.04
|
||||
FROM ubuntu:20.04 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"]
|
|
@ -1,20 +1,21 @@
|
|||
# Obtain current Azure SNP ID key digest
|
||||
# Obtain current Azure SNP ID key digest & firmware versions
|
||||
|
||||
On Azure, Constellation verifies that the SNP attestation report contains Azure's ID key digest.
|
||||
Currently, the only way to verify this digest's origin is to perform guest attestation with the help of the Microsoft Azure Attestation (MAA) service.
|
||||
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:
|
||||
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/get-azure-snp-jwt
|
||||
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.
|
||||
On success it prints the ID key digest and relevant firmware SVNs.
|
|
@ -23,33 +23,52 @@ import (
|
|||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
)
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
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() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Println("Usage:", os.Args[0], "<maa-jwt>")
|
||||
return
|
||||
}
|
||||
idKeyDigest, err := getIDKeyDigest(os.Args[1])
|
||||
report, err := getTEEReport(os.Args[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("Successfully validated ID key digest:", idKeyDigest)
|
||||
fmt.Println("Successfully validated ID key digest:", report.IDKeyDigest)
|
||||
fmt.Println("Currently reported SVNs:")
|
||||
report.PrintSVNs()
|
||||
}
|
||||
|
||||
func getIDKeyDigest(rawToken string) (string, error) {
|
||||
func getTEEReport(rawToken string) (IsolationTEE, error) {
|
||||
// Parse token.
|
||||
token, err := jwt.ParseSigned(rawToken)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return IsolationTEE{}, err
|
||||
}
|
||||
|
||||
// Get JSON Web Key set.
|
||||
keySetBytes, err := httpGet(context.Background(), "https://sharedeus.eus.attest.azure.net/certs")
|
||||
if err != nil {
|
||||
return "", err
|
||||
return IsolationTEE{}, err
|
||||
}
|
||||
keySet, err := parseKeySet(keySetBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return IsolationTEE{}, err
|
||||
}
|
||||
|
||||
// Get claims. Private claims contain ID Key digest.
|
||||
|
@ -57,19 +76,17 @@ func getIDKeyDigest(rawToken string) (string, error) {
|
|||
var publicClaims jwt.Claims
|
||||
|
||||
var privateClaims struct {
|
||||
IsolationTEE struct {
|
||||
IDKeyDigest string `json:"x-ms-sevsnpvm-idkeydigest"`
|
||||
} `json:"x-ms-isolation-tee"`
|
||||
IsolationTEE IsolationTEE `json:"x-ms-isolation-tee"`
|
||||
}
|
||||
|
||||
if err := token.Claims(&keySet, &publicClaims, &privateClaims); err != nil {
|
||||
return "", err
|
||||
return IsolationTEE{}, err
|
||||
}
|
||||
if err := publicClaims.Validate(jwt.Expected{Time: time.Now()}); err != nil {
|
||||
return "", err
|
||||
return IsolationTEE{}, err
|
||||
}
|
||||
|
||||
return privateClaims.IsolationTEE.IDKeyDigest, nil
|
||||
return privateClaims.IsolationTEE, nil
|
||||
}
|
||||
|
||||
func parseKeySet(keySetBytes []byte) (jose.JSONWebKeySet, error) {
|
Loading…
Add table
Add a link
Reference in a new issue