2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-03-22 11:03:15 -04:00
|
|
|
package gcp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"cloud.google.com/go/compute/metadata"
|
2022-09-21 07:47:57 -04:00
|
|
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
|
|
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
2022-03-22 11:03:15 -04:00
|
|
|
tpmclient "github.com/google/go-tpm-tools/client"
|
|
|
|
"github.com/google/go-tpm-tools/proto/attest"
|
|
|
|
)
|
|
|
|
|
2022-04-21 10:27:34 -04:00
|
|
|
// Issuer for GCP confidential VM attestation.
|
2022-03-22 11:03:15 -04:00
|
|
|
type Issuer struct {
|
|
|
|
oid.GCP
|
|
|
|
*vtpm.Issuer
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewIssuer initializes a new GCP Issuer.
|
2023-02-28 10:34:18 -05:00
|
|
|
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
2022-03-22 11:03:15 -04:00
|
|
|
return &Issuer{
|
|
|
|
Issuer: vtpm.NewIssuer(
|
|
|
|
vtpm.OpenVTPM,
|
|
|
|
tpmclient.GceAttestationKeyRSA,
|
|
|
|
getGCEInstanceInfo(metadataClient{}),
|
2023-02-28 10:34:18 -05:00
|
|
|
log,
|
2022-03-22 11:03:15 -04:00
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// getGCEInstanceInfo fetches VM metadata used for attestation.
|
|
|
|
func getGCEInstanceInfo(client gcpMetadataClient) func(io.ReadWriteCloser) ([]byte, error) {
|
|
|
|
// Ideally we would want to use the endorsement public key certificate
|
|
|
|
// However, this is not available on GCE instances
|
|
|
|
// Workaround: Provide ShieldedVM instance info
|
|
|
|
// The attestating party can request the VMs signing key using Google's API
|
|
|
|
return func(io.ReadWriteCloser) ([]byte, error) {
|
|
|
|
projectID, err := client.projectID()
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.New("unable to fetch projectID")
|
|
|
|
}
|
|
|
|
zone, err := client.zone()
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.New("unable to fetch zone")
|
|
|
|
}
|
|
|
|
instanceName, err := client.instanceName()
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.New("unable to fetch instance name")
|
|
|
|
}
|
|
|
|
|
|
|
|
return json.Marshal(attest.GCEInstanceInfo{
|
|
|
|
Zone: zone,
|
|
|
|
ProjectId: projectID,
|
|
|
|
InstanceName: instanceName,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type gcpMetadataClient interface {
|
|
|
|
projectID() (string, error)
|
|
|
|
instanceName() (string, error)
|
|
|
|
zone() (string, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type metadataClient struct{}
|
|
|
|
|
|
|
|
func (c metadataClient) projectID() (string, error) {
|
|
|
|
return metadata.ProjectID()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c metadataClient) instanceName() (string, error) {
|
|
|
|
return metadata.InstanceName()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c metadataClient) zone() (string, error) {
|
|
|
|
return metadata.Zone()
|
|
|
|
}
|