mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-01-23 13:51:06 -05:00
add tooling to obtain Azure ID key digest
This commit is contained in:
parent
66d8c8037b
commit
2d611e8148
16
hack/azure-snp-idkey-digest/Dockerfile
Normal file
16
hack/azure-snp-idkey-digest/Dockerfile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
FROM ubuntu:20.04 AS build
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
libcurl4-openssl-dev \
|
||||||
|
wget
|
||||||
|
RUN wget 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 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
|
||||||
|
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"]
|
20
hack/azure-snp-idkey-digest/README.md
Normal file
20
hack/azure-snp-idkey-digest/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Obtain current Azure SNP ID key digest
|
||||||
|
|
||||||
|
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.
|
||||||
|
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:
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
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.
|
106
hack/azure-snp-idkey-digest/verify.go
Normal file
106
hack/azure-snp-idkey-digest/verify.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// Verify verifies an MAA JWT and prints the SNP ID key digest on success.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/square/go-jose.v2"
|
||||||
|
"gopkg.in/square/go-jose.v2/jwt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 2 {
|
||||||
|
fmt.Println("Usage:", os.Args[0], "<maa-jwt>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
idKeyDigest, err := getIDKeyDigest(os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Println("Successfully validated ID key digest:", idKeyDigest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIDKeyDigest(rawToken string) (string, error) {
|
||||||
|
// Parse token.
|
||||||
|
token, err := jwt.ParseSigned(rawToken)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get JSON Web Key set.
|
||||||
|
keySetBytes, err := httpGet("https://sharedeus.eus.attest.azure.net/certs")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
keySet, err := parseKeySet(keySetBytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get claims. Private claims contain ID Key digest.
|
||||||
|
|
||||||
|
var publicClaims jwt.Claims
|
||||||
|
|
||||||
|
var privateClaims struct {
|
||||||
|
IsolationTEE struct {
|
||||||
|
IDKeyDigest string `json:"x-ms-sevsnpvm-idkeydigest"`
|
||||||
|
} `json:"x-ms-isolation-tee"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := token.Claims(&keySet, &publicClaims, &privateClaims); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := publicClaims.Validate(jwt.Expected{Time: time.Now()}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return privateClaims.IsolationTEE.IDKeyDigest, 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(url string) ([]byte, error) {
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user