mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-11-13 00:50:38 -05:00
attestation: add awsSEVSNP as new variant (#1900)
* variant: move into internal/attestation * attesation: move aws attesation into subfolder nitrotpm * config: add aws-sev-snp variant * cli: add tf option to enable AWS SNP For now the implementations in aws/nitrotpm and aws/snp are identical. They both contain the aws/nitrotpm impl. A separate commit will add the actual attestation logic.
This commit is contained in:
parent
947d0cb20a
commit
8f21972aec
110 changed files with 993 additions and 215 deletions
|
|
@ -1,51 +1,8 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "aws",
|
||||
srcs = [
|
||||
"aws.go",
|
||||
"issuer.go",
|
||||
"validator.go",
|
||||
],
|
||||
srcs = ["aws.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/aws",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
||||
"@com_github_aws_aws_sdk_go_v2_feature_ec2_imds//:imds",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2",
|
||||
"@com_github_google_go_tpm//tpm2",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "aws_test",
|
||||
srcs = [
|
||||
"issuer_test.go",
|
||||
"validator_test.go",
|
||||
],
|
||||
embed = [":aws"],
|
||||
# keep
|
||||
gotags = select({
|
||||
"//bazel/settings:tpm_simulator_enabled": [],
|
||||
"//conditions:default": ["disable_tpm_simulator"],
|
||||
}),
|
||||
deps = [
|
||||
"//internal/attestation/simulator",
|
||||
"//internal/attestation/vtpm",
|
||||
"@com_github_aws_aws_sdk_go_v2_feature_ec2_imds//:imds",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//types",
|
||||
"@com_github_aws_smithy_go//middleware",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,24 +7,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
/*
|
||||
# Amazon Web Services attestation
|
||||
|
||||
Attestation for AWS using [NitroTPM].
|
||||
Constellation supports multiple attestation technologies on AWS.
|
||||
|
||||
AWS currently does not support confidential VMs, but offers a TPM 2.0 compliant vTPM integration.
|
||||
We use this to enable a TPM based measured boot Constellation deployment.
|
||||
- SEV - Secure Nested Paging (SEV-SNP)
|
||||
|
||||
# Issuer
|
||||
TPM attestation verified using an SEV-SNP attestation statement.
|
||||
The TPM runs outside the confidential context.
|
||||
The initial firmware measurement included in the SNP report can be calculated idependently.
|
||||
The source code of the firmware is publicly available.
|
||||
|
||||
The TPM attestation is signed by the NitroTPM's RSA attestation key.
|
||||
Additionally to the TPM attestation, we attach a node's [instance identity document] to the attestation document.
|
||||
- NitroTPM
|
||||
|
||||
# Validator
|
||||
|
||||
Currently, the NitroTPM provides no endorsement certificate for its attestation key, nor does AWS offer a secondary of of verifying it.
|
||||
For now we have to blindly trust the key.
|
||||
|
||||
Additionally to verifying the TPM attestation, we also check the instance identity document for consistency.
|
||||
|
||||
[NitroTPM]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nitrotpm.html
|
||||
[instance identity document]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
|
||||
No confidential computing. Attestation via a TPM 2.0 compliant vTPM.
|
||||
*/
|
||||
package aws
|
||||
|
|
|
|||
72
internal/attestation/aws/nitrotpm/BUILD.bazel
Normal file
72
internal/attestation/aws/nitrotpm/BUILD.bazel
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "nitrotpm",
|
||||
srcs = [
|
||||
"issuer.go",
|
||||
"nitrotpm.go",
|
||||
"validator.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/aws/nitrotpm",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
||||
"@com_github_aws_aws_sdk_go_v2_feature_ec2_imds//:imds",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2",
|
||||
"@com_github_google_go_tpm//tpm2",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "nitro_test",
|
||||
srcs = [
|
||||
"issuer_test.go",
|
||||
"validator_test.go",
|
||||
],
|
||||
embed = [":nitrotpm"],
|
||||
# keep
|
||||
gotags = select({
|
||||
"//bazel/settings:tpm_simulator_enabled": [],
|
||||
"//conditions:default": ["disable_tpm_simulator"],
|
||||
}),
|
||||
deps = [
|
||||
"//internal/attestation/simulator",
|
||||
"//internal/attestation/vtpm",
|
||||
"@com_github_aws_aws_sdk_go_v2_feature_ec2_imds//:imds",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//types",
|
||||
"@com_github_aws_smithy_go//middleware",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "nitrotpm_test",
|
||||
srcs = [
|
||||
"issuer_test.go",
|
||||
"validator_test.go",
|
||||
],
|
||||
embed = [":nitrotpm"],
|
||||
deps = [
|
||||
"//internal/attestation/simulator",
|
||||
"//internal/attestation/vtpm",
|
||||
"@com_github_aws_aws_sdk_go_v2_feature_ec2_imds//:imds",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//types",
|
||||
"@com_github_aws_smithy_go//middleware",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
],
|
||||
)
|
||||
|
|
@ -4,19 +4,18 @@ Copyright (c) Edgeless Systems GmbH
|
|||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package aws
|
||||
package nitrotpm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
|
||||
"github.com/google/go-tpm-tools/client"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
|
|
@ -28,7 +27,7 @@ type Issuer struct {
|
|||
*vtpm.Issuer
|
||||
}
|
||||
|
||||
// NewIssuer creates a new OpenVTPM based issuer for AWS.
|
||||
// NewIssuer creates a TPM based issuer for AWS.
|
||||
func NewIssuer(log attestation.Logger) *Issuer {
|
||||
return &Issuer{
|
||||
Issuer: vtpm.NewIssuer(
|
||||
|
|
@ -44,8 +43,7 @@ func NewIssuer(log attestation.Logger) *Issuer {
|
|||
func getAttestationKey(tpm io.ReadWriter) (*tpmclient.Key, error) {
|
||||
tpmAk, err := client.AttestationKeyRSA(tpm)
|
||||
if err != nil {
|
||||
log.Fatalf("error creating RSA Endorsement key!")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("error creating RSA Endorsement key: %w", err)
|
||||
}
|
||||
|
||||
return tpmAk, nil
|
||||
|
|
@ -54,10 +52,10 @@ func getAttestationKey(tpm io.ReadWriter) (*tpmclient.Key, error) {
|
|||
// getInstanceInfo returns information about the current instance using the aws Metadata SDK.
|
||||
// The returned bytes will be written into the attestation document.
|
||||
func getInstanceInfo(client awsMetaData) func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) {
|
||||
return func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) {
|
||||
ec2InstanceIdentityOutput, err := client.GetInstanceIdentityDocument(context.Background(), &imds.GetInstanceIdentityDocumentInput{})
|
||||
return func(ctx context.Context, _ io.ReadWriteCloser, _ []byte) ([]byte, error) {
|
||||
ec2InstanceIdentityOutput, err := client.GetInstanceIdentityDocument(ctx, &imds.GetInstanceIdentityDocumentInput{})
|
||||
if err != nil {
|
||||
return nil, errors.New("unable to fetch instance identity document")
|
||||
return nil, fmt.Errorf("fetching instance identity document: %w", err)
|
||||
}
|
||||
return json.Marshal(ec2InstanceIdentityOutput.InstanceIdentityDocument)
|
||||
}
|
||||
118
internal/attestation/aws/nitrotpm/issuer_test.go
Normal file
118
internal/attestation/aws/nitrotpm/issuer_test.go
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package nitrotpm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetAttestationKey(t *testing.T) {
|
||||
require := require.New(t)
|
||||
assert := assert.New(t)
|
||||
|
||||
tpm, err := simulator.OpenSimulatedTPM()
|
||||
require.NoError(err)
|
||||
defer tpm.Close()
|
||||
|
||||
// create the attestation ket in RSA format
|
||||
tpmAk, err := tpmclient.AttestationKeyRSA(tpm)
|
||||
assert.NoError(err)
|
||||
assert.NotNil(tpmAk)
|
||||
|
||||
// get the cached, already created key
|
||||
getAk, err := getAttestationKey(tpm)
|
||||
assert.NoError(err)
|
||||
assert.NotNil(getAk)
|
||||
|
||||
// if everything worked fine, tpmAk and getAk are the same key
|
||||
assert.Equal(tpmAk, getAk)
|
||||
}
|
||||
|
||||
func TestGetInstanceInfo(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
client stubMetadataAPI
|
||||
wantErr bool
|
||||
}{
|
||||
"invalid region": {
|
||||
client: stubMetadataAPI{
|
||||
instanceDoc: imds.InstanceIdentityDocument{
|
||||
Region: "invalid-region",
|
||||
},
|
||||
instanceErr: errors.New("failed"),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"valid region": {
|
||||
client: stubMetadataAPI{
|
||||
instanceDoc: imds.InstanceIdentityDocument{
|
||||
Region: "us-east-2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid imageID": {
|
||||
client: stubMetadataAPI{
|
||||
instanceDoc: imds.InstanceIdentityDocument{
|
||||
ImageID: "ami-fail",
|
||||
},
|
||||
instanceErr: errors.New("failed"),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
"valid imageID": {
|
||||
client: stubMetadataAPI{
|
||||
instanceDoc: imds.InstanceIdentityDocument{
|
||||
ImageID: "ami-09e7c7f5617a47830",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tpm, err := simulator.OpenSimulatedTPM()
|
||||
assert.NoError(err)
|
||||
defer tpm.Close()
|
||||
|
||||
instanceInfoFunc := getInstanceInfo(&tc.client)
|
||||
assert.NotNil(instanceInfoFunc)
|
||||
|
||||
info, err := instanceInfoFunc(context.Background(), tpm, nil)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
assert.Nil(info)
|
||||
} else {
|
||||
assert.Nil(err)
|
||||
assert.NotNil(info)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type stubMetadataAPI struct {
|
||||
instanceDoc imds.InstanceIdentityDocument
|
||||
instanceErr error
|
||||
}
|
||||
|
||||
func (c *stubMetadataAPI) GetInstanceIdentityDocument(context.Context, *imds.GetInstanceIdentityDocumentInput, ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error) {
|
||||
output := &imds.InstanceIdentityDocument{}
|
||||
|
||||
return &imds.GetInstanceIdentityDocumentOutput{
|
||||
InstanceIdentityDocument: *output,
|
||||
ResultMetadata: middleware.Metadata{},
|
||||
}, c.instanceErr
|
||||
}
|
||||
29
internal/attestation/aws/nitrotpm/nitrotpm.go
Normal file
29
internal/attestation/aws/nitrotpm/nitrotpm.go
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
# NitroTPM Attestation.
|
||||
|
||||
Uses NitroTPM to enable a TPM based measured boot Constellation deployment.
|
||||
The origin of the attesation statement can not be verified.
|
||||
|
||||
# Issuer
|
||||
|
||||
The TPM attestation is signed by the NitroTPM's RSA attestation key.
|
||||
Additionally to the TPM attestation, we attach a node's [instance identity document] to the attestation document.
|
||||
|
||||
# Validator
|
||||
|
||||
Currently, the NitroTPM provides no endorsement certificate for its attestation key, nor does AWS offer an alternative way of verifying it.
|
||||
For now we have to blindly trust the key.
|
||||
|
||||
Additionally to verifying the TPM attestation, we also check the instance identity document for consistency.
|
||||
|
||||
[instance identity document]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
|
||||
|
||||
[NitroTPM]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nitrotpm.html
|
||||
*/
|
||||
package nitrotpm
|
||||
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package aws
|
||||
package nitrotpm
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -16,9 +16,9 @@ import (
|
|||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
146
internal/attestation/aws/nitrotpm/validator_test.go
Normal file
146
internal/attestation/aws/nitrotpm/validator_test.go
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package nitrotpm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGeTrustedKey(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
akPub []byte
|
||||
info []byte
|
||||
wantErr bool
|
||||
}{
|
||||
"nul byte docs": {
|
||||
akPub: []byte{0x00, 0x00, 0x00, 0x00},
|
||||
info: []byte{0x00, 0x00, 0x00, 0x00},
|
||||
wantErr: true,
|
||||
},
|
||||
"nil": {
|
||||
akPub: nil,
|
||||
info: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
out, err := getTrustedKey(
|
||||
context.Background(),
|
||||
vtpm.AttestationDocument{
|
||||
Attestation: &attest.Attestation{
|
||||
AkPub: tc.akPub,
|
||||
},
|
||||
InstanceInfo: tc.info,
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
}
|
||||
|
||||
assert.Nil(out)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTpmEnabled(t *testing.T) {
|
||||
idDocNoTPM := imds.InstanceIdentityDocument{
|
||||
ImageID: "ami-tpm-disabled",
|
||||
}
|
||||
userDataNoTPM, _ := json.Marshal(idDocNoTPM)
|
||||
attDocNoTPM := vtpm.AttestationDocument{
|
||||
InstanceInfo: userDataNoTPM,
|
||||
}
|
||||
|
||||
idDocTPM := imds.InstanceIdentityDocument{
|
||||
ImageID: "ami-tpm-enabled",
|
||||
}
|
||||
userDataTPM, _ := json.Marshal(idDocTPM)
|
||||
attDocTPM := vtpm.AttestationDocument{
|
||||
InstanceInfo: userDataTPM,
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
attDoc vtpm.AttestationDocument
|
||||
awsAPI awsMetadataAPI
|
||||
wantErr bool
|
||||
}{
|
||||
"ami with tpm": {
|
||||
attDoc: attDocNoTPM,
|
||||
awsAPI: &stubDescribeAPI{describeImagesTPMSupport: "v2.0"},
|
||||
},
|
||||
"ami without tpm": {
|
||||
attDoc: attDocTPM,
|
||||
awsAPI: &stubDescribeAPI{describeImagesTPMSupport: "v1.0"},
|
||||
wantErr: true,
|
||||
},
|
||||
"ami undefined": {
|
||||
attDoc: vtpm.AttestationDocument{},
|
||||
awsAPI: &stubDescribeAPI{describeImagesErr: errors.New("failed")},
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid json instanceIdentityDocument": {
|
||||
attDoc: vtpm.AttestationDocument{
|
||||
UserData: []byte("{invalid}"),
|
||||
},
|
||||
awsAPI: &stubDescribeAPI{describeImagesErr: errors.New("failed")},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
v := Validator{
|
||||
getDescribeClient: func(context.Context, string) (awsMetadataAPI, error) {
|
||||
return tc.awsAPI, nil
|
||||
},
|
||||
}
|
||||
|
||||
err := v.tpmEnabled(tc.attDoc, nil)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.Nil(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type stubDescribeAPI struct {
|
||||
describeImagesErr error
|
||||
describeImagesTPMSupport string
|
||||
}
|
||||
|
||||
func (a *stubDescribeAPI) DescribeImages(
|
||||
_ context.Context, _ *ec2.DescribeImagesInput, _ ...func(*ec2.Options),
|
||||
) (*ec2.DescribeImagesOutput, error) {
|
||||
output := &ec2.DescribeImagesOutput{
|
||||
Images: []types.Image{
|
||||
{TpmSupport: types.TpmSupportValues(a.describeImagesTPMSupport)},
|
||||
},
|
||||
}
|
||||
|
||||
return output, a.describeImagesErr
|
||||
}
|
||||
51
internal/attestation/aws/snp/BUILD.bazel
Normal file
51
internal/attestation/aws/snp/BUILD.bazel
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("//bazel/go:go_test.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "snp",
|
||||
srcs = [
|
||||
"issuer.go",
|
||||
"snp.go",
|
||||
"validator.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/aws/snp",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"@com_github_aws_aws_sdk_go_v2_config//:config",
|
||||
"@com_github_aws_aws_sdk_go_v2_feature_ec2_imds//:imds",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2",
|
||||
"@com_github_google_go_tpm//tpm2",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "snp_test",
|
||||
srcs = [
|
||||
"issuer_test.go",
|
||||
"validator_test.go",
|
||||
],
|
||||
embed = [":snp"],
|
||||
# keep
|
||||
gotags = select({
|
||||
"//bazel/settings:tpm_simulator_enabled": [],
|
||||
"//conditions:default": ["disable_tpm_simulator"],
|
||||
}),
|
||||
deps = [
|
||||
"//internal/attestation/simulator",
|
||||
"//internal/attestation/vtpm",
|
||||
"@com_github_aws_aws_sdk_go_v2_feature_ec2_imds//:imds",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2",
|
||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//types",
|
||||
"@com_github_aws_smithy_go//middleware",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
],
|
||||
)
|
||||
66
internal/attestation/aws/snp/issuer.go
Normal file
66
internal/attestation/aws/snp/issuer.go
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package snp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
|
||||
"github.com/google/go-tpm-tools/client"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
)
|
||||
|
||||
// Issuer for AWS SNP attestation.
|
||||
type Issuer struct {
|
||||
variant.AWSSEVSNP
|
||||
*vtpm.Issuer
|
||||
}
|
||||
|
||||
// NewIssuer creates a SEV-SNP based issuer for AWS.
|
||||
func NewIssuer(log attestation.Logger) *Issuer {
|
||||
return &Issuer{
|
||||
Issuer: vtpm.NewIssuer(
|
||||
vtpm.OpenVTPM,
|
||||
getAttestationKey,
|
||||
getInstanceInfo(imds.New(imds.Options{})),
|
||||
log,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// getAttestationKey returns a new attestation key.
|
||||
func getAttestationKey(tpm io.ReadWriter) (*tpmclient.Key, error) {
|
||||
tpmAk, err := client.AttestationKeyRSA(tpm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating RSA Endorsement key: %w", err)
|
||||
}
|
||||
|
||||
return tpmAk, nil
|
||||
}
|
||||
|
||||
// getInstanceInfo returns information about the current instance using the aws Metadata SDK.
|
||||
// The returned bytes will be written into the attestation document.
|
||||
func getInstanceInfo(client awsMetaData) func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) {
|
||||
return func(ctx context.Context, _ io.ReadWriteCloser, _ []byte) ([]byte, error) {
|
||||
ec2InstanceIdentityOutput, err := client.GetInstanceIdentityDocument(ctx, &imds.GetInstanceIdentityDocumentInput{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetching instance identity document: %w", err)
|
||||
}
|
||||
return json.Marshal(ec2InstanceIdentityOutput.InstanceIdentityDocument)
|
||||
}
|
||||
}
|
||||
|
||||
type awsMetaData interface {
|
||||
GetInstanceIdentityDocument(context.Context, *imds.GetInstanceIdentityDocumentInput, ...func(*imds.Options)) (*imds.GetInstanceIdentityDocumentOutput, error)
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package aws
|
||||
package snp
|
||||
|
||||
import (
|
||||
"context"
|
||||
52
internal/attestation/aws/snp/snp.go
Normal file
52
internal/attestation/aws/snp/snp.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
--------- WARNING! ---------
|
||||
|
||||
THIS PACKAGE DOES CURRENTLY NOT IMPLEMENT ANY SNP ATTESTATION.
|
||||
It exists to implement required interfaces while implementing other parts of the AWS SNP attestation variant within Constellation.
|
||||
|
||||
----------------------------
|
||||
|
||||
# SNP
|
||||
|
||||
Attestation based on TPMs and AMD SEV-SNP.
|
||||
The TPM is used to generate runtime measurements and sign them with an attestation key.
|
||||
The TPM currently runs outside the confidential context. This is a limitation imposed by the AWS implementation.
|
||||
|
||||
# Issuer
|
||||
|
||||
Generates a TPM attestation using an attestation key saved inside the TPM.
|
||||
Additionally loads the SEV-SNP attestation report and AMD VLEK certificate chain, and adds them to the attestation document.
|
||||
The SNP report includes a measurement of the initial firmware inside the CVM, which can be precalculated independently for verification.
|
||||
The report also includes the attestation key.
|
||||
|
||||
# Validator
|
||||
|
||||
Verifies the SNP report by verifying the VLEK certificate chain and the report's signature.
|
||||
This estabilishes trust in the attestation key and the CVM's initial firmware.
|
||||
However, since the TPM is outside the confidential context, it has to be trusted without verification.
|
||||
Thus, the hypervisor is still included in the trusted computing base.
|
||||
|
||||
# Glossary
|
||||
|
||||
This section explains abbreviations used in SNP implementation.
|
||||
|
||||
- Attestation Key (AK)
|
||||
|
||||
- AMD Root Key (ARK)
|
||||
|
||||
- AMD Signing Key (ASK)
|
||||
|
||||
- Versioned Chip Endorsement Key (VCEK)
|
||||
|
||||
- Versioned Loaded Endorsement Key (VLEK)
|
||||
For more information see [SNP WhitePaper]
|
||||
|
||||
[SNP WhitePaper]: https://www.amd.com/system/files/TechDocs/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf
|
||||
*/
|
||||
package snp
|
||||
101
internal/attestation/aws/snp/validator.go
Normal file
101
internal/attestation/aws/snp/validator.go
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package snp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
awsConfig "github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
||||
// Validator for AWS TPM attestation.
|
||||
type Validator struct {
|
||||
variant.AWSSEVSNP
|
||||
*vtpm.Validator
|
||||
getDescribeClient func(context.Context, string) (awsMetadataAPI, error)
|
||||
}
|
||||
|
||||
// NewValidator create a new Validator structure and returns it.
|
||||
func NewValidator(cfg *config.AWSSEVSNP, log attestation.Logger) *Validator {
|
||||
v := &Validator{}
|
||||
v.Validator = vtpm.NewValidator(
|
||||
cfg.Measurements,
|
||||
getTrustedKey,
|
||||
v.tpmEnabled,
|
||||
log,
|
||||
)
|
||||
v.getDescribeClient = getEC2Client
|
||||
return v
|
||||
}
|
||||
|
||||
// getTrustedKeys return the public area of the provides attestation key.
|
||||
// Normally, here the trust of this key should be verified, but currently AWS does not provide this feature.
|
||||
func getTrustedKey(_ context.Context, attDoc vtpm.AttestationDocument, _ []byte) (crypto.PublicKey, error) {
|
||||
// Copied from https://github.com/edgelesssys/constellation/blob/main/internal/attestation/qemu/validator.go
|
||||
pubArea, err := tpm2.DecodePublic(attDoc.Attestation.AkPub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pubArea.Key()
|
||||
}
|
||||
|
||||
// tpmEnabled verifies if the virtual machine has the tpm2.0 feature enabled.
|
||||
func (v *Validator) tpmEnabled(attestation vtpm.AttestationDocument, _ *attest.MachineState) error {
|
||||
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/verify-nitrotpm-support-on-ami.html
|
||||
// 1. Get the vm's ami (from IdentiTyDocument.imageId)
|
||||
// 2. Check the value of key "TpmSupport": {"Value": "v2.0"}"
|
||||
ctx := context.Background()
|
||||
|
||||
idDocument := imds.InstanceIdentityDocument{}
|
||||
err := json.Unmarshal(attestation.InstanceInfo, &idDocument)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
imageID := idDocument.ImageID
|
||||
|
||||
client, err := v.getDescribeClient(ctx, idDocument.Region)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Currently, there seems to be a problem with retrieving image attributes directly.
|
||||
// Alternatively, parse it from the general output.
|
||||
imageOutput, err := client.DescribeImages(ctx, &ec2.DescribeImagesInput{ImageIds: []string{imageID}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if imageOutput.Images[0].TpmSupport == "v2.0" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("iam image %s does not support TPM v2.0", imageID)
|
||||
}
|
||||
|
||||
func getEC2Client(ctx context.Context, region string) (awsMetadataAPI, error) {
|
||||
client, err := awsConfig.LoadDefaultConfig(ctx, awsConfig.WithRegion(region))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ec2.NewFromConfig(client), nil
|
||||
}
|
||||
|
||||
type awsMetadataAPI interface {
|
||||
DescribeImages(ctx context.Context, params *ec2.DescribeImagesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeImagesOutput, error)
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package aws
|
||||
package snp
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -16,11 +16,11 @@ go_library(
|
|||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/idkeydigest",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/cloud/azure",
|
||||
"//internal/config",
|
||||
"//internal/crypto",
|
||||
"//internal/variant",
|
||||
"@com_github_edgelesssys_go_azguestattestation//maa",
|
||||
"@com_github_google_go_tpm//tpm2",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/go-azguestattestation/maa"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ import (
|
|||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
internalCrypto "github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ go_library(
|
|||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"//internal/crypto",
|
||||
"//internal/variant",
|
||||
"@com_github_google_go_tpm//tpm2",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
certutil "github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,14 +9,15 @@ go_library(
|
|||
deps = [
|
||||
"//internal/atls",
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/aws",
|
||||
"//internal/attestation/aws/nitrotpm",
|
||||
"//internal/attestation/aws/snp",
|
||||
"//internal/attestation/azure/snp",
|
||||
"//internal/attestation/azure/trustedlaunch",
|
||||
"//internal/attestation/gcp",
|
||||
"//internal/attestation/qemu",
|
||||
"//internal/attestation/tdx",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
@ -26,8 +27,8 @@ go_test(
|
|||
embed = [":choose"],
|
||||
deps = [
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -11,25 +11,28 @@ import (
|
|||
|
||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/aws"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/aws/nitrotpm"
|
||||
awssnp "github.com/edgelesssys/constellation/v2/internal/attestation/aws/snp"
|
||||
azuresnp "github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/azure/trustedlaunch"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/gcp"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/qemu"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/tdx"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
)
|
||||
|
||||
// Issuer returns the issuer for the given variant.
|
||||
func Issuer(attestationVariant variant.Variant, log attestation.Logger) (atls.Issuer, error) {
|
||||
switch attestationVariant {
|
||||
case variant.AWSSEVSNP{}:
|
||||
return awssnp.NewIssuer(log), nil
|
||||
case variant.AWSNitroTPM{}:
|
||||
return aws.NewIssuer(log), nil
|
||||
return nitrotpm.NewIssuer(log), nil
|
||||
case variant.AzureTrustedLaunch{}:
|
||||
return trustedlaunch.NewIssuer(log), nil
|
||||
case variant.AzureSEVSNP{}:
|
||||
return snp.NewIssuer(log), nil
|
||||
return azuresnp.NewIssuer(log), nil
|
||||
case variant.GCPSEVES{}:
|
||||
return gcp.NewIssuer(log), nil
|
||||
case variant.QEMUVTPM{}:
|
||||
|
|
@ -46,12 +49,14 @@ func Issuer(attestationVariant variant.Variant, log attestation.Logger) (atls.Is
|
|||
// Validator returns the validator for the given variant.
|
||||
func Validator(cfg config.AttestationCfg, log attestation.Logger) (atls.Validator, error) {
|
||||
switch cfg := cfg.(type) {
|
||||
case *config.AWSSEVSNP:
|
||||
return awssnp.NewValidator(cfg, log), nil
|
||||
case *config.AWSNitroTPM:
|
||||
return aws.NewValidator(cfg, log), nil
|
||||
return nitrotpm.NewValidator(cfg, log), nil
|
||||
case *config.AzureTrustedLaunch:
|
||||
return trustedlaunch.NewValidator(cfg, log), nil
|
||||
case *config.AzureSEVSNP:
|
||||
return snp.NewValidator(cfg, log), nil
|
||||
return azuresnp.NewValidator(cfg, log), nil
|
||||
case *config.GCPSEVES:
|
||||
return gcp.NewValidator(cfg, log), nil
|
||||
case *config.QEMUVTPM:
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
@ -22,6 +22,9 @@ func TestIssuer(t *testing.T) {
|
|||
variant variant.Variant
|
||||
wantErr bool
|
||||
}{
|
||||
"aws-sev-snp": {
|
||||
variant: variant.AWSSEVSNP{},
|
||||
},
|
||||
"aws-nitro-tpm": {
|
||||
variant: variant.AWSNitroTPM{},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ go_library(
|
|||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
"@com_github_googleapis_gax_go_v2//:gax-go",
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import (
|
|||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ import (
|
|||
compute "cloud.google.com/go/compute/apiv1"
|
||||
"cloud.google.com/go/compute/apiv1/computepb"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/googleapis/gax-go/v2"
|
||||
"google.golang.org/api/option"
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ go_library(
|
|||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/sigstore",
|
||||
"//internal/variant",
|
||||
"@com_github_google_go_tpm//tpmutil",
|
||||
"@com_github_siderolabs_talos_pkg_machinery//config/encoder",
|
||||
"@in_gopkg_yaml_v3//:yaml_v3",
|
||||
|
|
@ -29,9 +29,9 @@ go_test(
|
|||
embed = [":measurements"],
|
||||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/sigstore",
|
||||
"//internal/variant",
|
||||
"@com_github_siderolabs_talos_pkg_machinery//config/encoder",
|
||||
"@com_github_stretchr_testify//assert",
|
||||
"@com_github_stretchr_testify//require",
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ go_library(
|
|||
deps = [
|
||||
"//internal/api/versionsapi",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/sigstore",
|
||||
"//internal/variant",
|
||||
"@org_golang_x_tools//go/ast/astutil",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ import (
|
|||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
)
|
||||
|
||||
|
|
@ -249,6 +249,8 @@ func attestationVariantFromGoIdentifier(identifier string) (variant.Variant, err
|
|||
switch identifier {
|
||||
case "Dummy":
|
||||
return variant.Dummy{}, nil
|
||||
case "AWSSEVSNP":
|
||||
return variant.AWSSEVSNP{}, nil
|
||||
case "AWSNitroTPM":
|
||||
return variant.AWSNitroTPM{}, nil
|
||||
case "GCPSEVES":
|
||||
|
|
|
|||
|
|
@ -27,14 +27,14 @@ import (
|
|||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
)
|
||||
|
||||
//go:generate measurement-generator
|
||||
|
|
@ -467,6 +467,9 @@ func DefaultsFor(provider cloudprovider.Provider, attestationVariant variant.Var
|
|||
case provider == cloudprovider.AWS && attestationVariant == variant.AWSNitroTPM{}:
|
||||
return aws_AWSNitroTPM.Copy()
|
||||
|
||||
case provider == cloudprovider.AWS && attestationVariant == variant.AWSSEVSNP{}:
|
||||
return aws_AWSSEVSNP.Copy()
|
||||
|
||||
case provider == cloudprovider.Azure && attestationVariant == variant.AzureSEVSNP{}:
|
||||
return azure_AzureSEVSNP.Copy()
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package measurements
|
|||
// revive:disable:var-naming
|
||||
var (
|
||||
aws_AWSNitroTPM = M{0: {Expected: []byte{0x73, 0x7f, 0x76, 0x7a, 0x12, 0xf5, 0x4e, 0x70, 0xee, 0xcb, 0xc8, 0x68, 0x40, 0x11, 0x32, 0x3a, 0xe2, 0xfe, 0x2d, 0xd9, 0xf9, 0x07, 0x85, 0x57, 0x79, 0x69, 0xd7, 0xa2, 0x01, 0x3e, 0x8c, 0x12}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0xe0, 0x6b, 0x6d, 0x04, 0x8c, 0x0f, 0x0f, 0x39, 0x66, 0x0f, 0x0b, 0xd5, 0xff, 0xb9, 0xc6, 0xf1, 0x44, 0xf2, 0x05, 0x0b, 0x9d, 0x57, 0xe9, 0xed, 0xb9, 0x63, 0x45, 0x60, 0x20, 0x73, 0x7c, 0x2d}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 7: {Expected: []byte{0x12, 0x0e, 0x49, 0x8d, 0xb2, 0xa2, 0x24, 0xbd, 0x51, 0x2b, 0x6e, 0xfc, 0x9b, 0x02, 0x34, 0xf8, 0x43, 0xe1, 0x0b, 0xf0, 0x61, 0xeb, 0x7a, 0x76, 0xec, 0xca, 0x55, 0x09, 0xa2, 0x23, 0x89, 0x01}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x9e, 0x31, 0x6d, 0x07, 0x03, 0xde, 0xc5, 0x56, 0x30, 0x67, 0x29, 0x42, 0x65, 0x15, 0x07, 0x9e, 0xd9, 0xba, 0x6f, 0x21, 0x8d, 0x65, 0x92, 0xfb, 0xa9, 0x69, 0xd0, 0xca, 0x6f, 0x91, 0x9a, 0x82}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: []byte{0xda, 0xc1, 0x49, 0x8b, 0x42, 0xd3, 0x77, 0x49, 0x69, 0xba, 0xdd, 0xa8, 0xa0, 0x1a, 0xe4, 0x94, 0xbc, 0x5c, 0x3f, 0x9d, 0x08, 0x09, 0x64, 0xc1, 0x60, 0xff, 0xac, 0x45, 0x17, 0xe6, 0x5e, 0xba}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
aws_AWSSEVSNP = M{0: {Expected: []byte{0x73, 0x7f, 0x76, 0x7a, 0x12, 0xf5, 0x4e, 0x70, 0xee, 0xcb, 0xc8, 0x68, 0x40, 0x11, 0x32, 0x3a, 0xe2, 0xfe, 0x2d, 0xd9, 0xf9, 0x07, 0x85, 0x57, 0x79, 0x69, 0xd7, 0xa2, 0x01, 0x3e, 0x8c, 0x12}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0xf4, 0xe9, 0x30, 0x3d, 0xf3, 0x34, 0x41, 0x55, 0xdd, 0x14, 0x2d, 0x4d, 0xd8, 0xef, 0xfa, 0x20, 0xf4, 0x21, 0x39, 0x09, 0x9c, 0xc5, 0x2b, 0xca, 0x25, 0xd2, 0x86, 0xe9, 0x26, 0xbd, 0x61, 0x51}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 7: {Expected: []byte{0x12, 0x0e, 0x49, 0x8d, 0xb2, 0xa2, 0x24, 0xbd, 0x51, 0x2b, 0x6e, 0xfc, 0x9b, 0x02, 0x34, 0xf8, 0x43, 0xe1, 0x0b, 0xf0, 0x61, 0xeb, 0x7a, 0x76, 0xec, 0xca, 0x55, 0x09, 0xa2, 0x23, 0x89, 0x01}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x9e, 0x31, 0x6d, 0x07, 0x03, 0xde, 0xc5, 0x56, 0x30, 0x67, 0x29, 0x42, 0x65, 0x15, 0x07, 0x9e, 0xd9, 0xba, 0x6f, 0x21, 0x8d, 0x65, 0x92, 0xfb, 0xa9, 0x69, 0xd0, 0xca, 0x6f, 0x91, 0x9a, 0x82}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: []byte{0xbb, 0xa3, 0x3c, 0xc6, 0xe8, 0xa9, 0xfd, 0xef, 0xb4, 0x56, 0x8a, 0x04, 0x7d, 0xad, 0x27, 0x96, 0xcc, 0x81, 0x6d, 0x1a, 0x50, 0x57, 0xc5, 0xe7, 0x31, 0xe4, 0x5d, 0xa2, 0x8a, 0x56, 0xf0, 0xfa}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
azure_AzureSEVSNP = M{1: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x25, 0xf8, 0x89, 0x54, 0x69, 0xac, 0xbf, 0x28, 0x64, 0x48, 0xe4, 0x80, 0xdc, 0x33, 0x74, 0x80, 0x47, 0xd7, 0x56, 0x75, 0xaa, 0x83, 0x8b, 0xfd, 0x85, 0x58, 0xd4, 0xd7, 0x0c, 0x69, 0x13, 0xb5}, ValidationOpt: Enforce}, 7: {Expected: []byte{0x34, 0x65, 0x47, 0xa8, 0xce, 0x59, 0x57, 0xaf, 0x27, 0xe5, 0x52, 0x42, 0x7d, 0x6b, 0x9e, 0x6d, 0x9c, 0xb5, 0x02, 0xf0, 0x15, 0x6e, 0x91, 0x55, 0x38, 0x04, 0x51, 0xee, 0xa1, 0xb3, 0xf0, 0xed}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x99, 0x35, 0x5b, 0xbe, 0xb0, 0xa6, 0xff, 0x67, 0x6c, 0x51, 0x0a, 0xfb, 0xab, 0xe0, 0x5f, 0x84, 0x26, 0x17, 0x7b, 0xc7, 0xd6, 0x5c, 0xb7, 0xc1, 0xc3, 0xda, 0x8b, 0x00, 0xa2, 0x29, 0x57, 0x54}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x0f, 0xdb, 0x9d, 0xb0, 0x1a, 0x73, 0x9d, 0xa2, 0x3e, 0xd9, 0xbe, 0x68, 0xff, 0x86, 0xbd, 0x8c, 0xfc, 0x48, 0x54, 0x32, 0x13, 0x8c, 0xf3, 0xba, 0x77, 0x10, 0xff, 0x40, 0x35, 0xea, 0x10, 0x74}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
azure_AzureTrustedLaunch M
|
||||
gcp_GCPSEVES = M{1: {Expected: []byte{0x74, 0x5f, 0x2f, 0xb4, 0x23, 0x5e, 0x46, 0x47, 0xaa, 0x0a, 0xd5, 0xac, 0xe7, 0x81, 0xcd, 0x92, 0x9e, 0xb6, 0x8c, 0x28, 0x87, 0x0e, 0x7d, 0xd5, 0xd1, 0xa1, 0x53, 0x58, 0x54, 0x32, 0x5e, 0x56}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0xf8, 0xd7, 0x95, 0xe3, 0x27, 0x4d, 0x8d, 0x32, 0x78, 0xe2, 0xcc, 0xb5, 0x29, 0xfd, 0x7b, 0xce, 0x70, 0xef, 0x0e, 0x67, 0x99, 0xe4, 0xaa, 0x21, 0x7e, 0xac, 0x17, 0x42, 0xdf, 0xfc, 0x1d, 0xce}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 7: {Expected: []byte{0xb1, 0xe9, 0xb3, 0x05, 0x32, 0x5c, 0x51, 0xb9, 0x3d, 0xa5, 0x8c, 0xbf, 0x7f, 0x92, 0x51, 0x2d, 0x8e, 0xeb, 0xfa, 0x01, 0x14, 0x3e, 0x4d, 0x88, 0x44, 0xe4, 0x0e, 0x06, 0x2e, 0x9b, 0x6c, 0xd5}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x99, 0x35, 0x5b, 0xbe, 0xb0, 0xa6, 0xff, 0x67, 0x6c, 0x51, 0x0a, 0xfb, 0xab, 0xe0, 0x5f, 0x84, 0x26, 0x17, 0x7b, 0xc7, 0xd6, 0x5c, 0xb7, 0xc1, 0xc3, 0xda, 0x8b, 0x00, 0xa2, 0x29, 0x57, 0x54}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 12: {Expected: []byte{0xab, 0x50, 0x0c, 0x4b, 0xc9, 0x4b, 0xb3, 0xa8, 0x7c, 0x47, 0x92, 0x23, 0x58, 0x1f, 0xcd, 0x03, 0xae, 0xb1, 0xc6, 0x87, 0xa4, 0x6a, 0x6b, 0x98, 0xaf, 0xce, 0x1c, 0x52, 0x43, 0x87, 0xd8, 0xed}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0xd7, 0xc4, 0xcc, 0x7f, 0xf7, 0x93, 0x30, 0x22, 0xf0, 0x13, 0xe0, 0x3b, 0xde, 0xe8, 0x75, 0xb9, 0x17, 0x20, 0xb5, 0xb8, 0x6c, 0xf1, 0x75, 0x3c, 0xad, 0x83, 0x0f, 0x95, 0xe7, 0x91, 0x92, 0x6f}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,17 @@ var (
|
|||
13: WithAllBytes(0x00, Enforce, PCRMeasurementLength),
|
||||
uint32(PCRIndexClusterID): WithAllBytes(0x00, Enforce, PCRMeasurementLength),
|
||||
}
|
||||
|
||||
aws_AWSSEVSNP = M{
|
||||
4: PlaceHolderMeasurement(PCRMeasurementLength),
|
||||
8: WithAllBytes(0x00, Enforce, PCRMeasurementLength),
|
||||
9: PlaceHolderMeasurement(PCRMeasurementLength),
|
||||
11: WithAllBytes(0x00, Enforce, PCRMeasurementLength),
|
||||
12: PlaceHolderMeasurement(PCRMeasurementLength),
|
||||
13: WithAllBytes(0x00, Enforce, PCRMeasurementLength),
|
||||
uint32(PCRIndexClusterID): WithAllBytes(0x00, Enforce, PCRMeasurementLength),
|
||||
}
|
||||
|
||||
azure_AzureSEVSNP = M{
|
||||
4: PlaceHolderMeasurement(PCRMeasurementLength),
|
||||
8: WithAllBytes(0x00, Enforce, PCRMeasurementLength),
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ import (
|
|||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
)
|
||||
|
||||
func TestMarshal(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ go_library(
|
|||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/attestation/vtpm",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
"@com_github_google_go_tpm//tpm2",
|
||||
"@com_github_google_go_tpm_tools//client",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
tpmclient "github.com/google/go-tpm-tools/client"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import (
|
|||
"crypto"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ go_library(
|
|||
deps = [
|
||||
"//internal/attestation",
|
||||
"//internal/attestation/measurements",
|
||||
"//internal/attestation/variant",
|
||||
"//internal/config",
|
||||
"//internal/variant",
|
||||
"@com_github_edgelesssys_go_tdx_qpl//tdx",
|
||||
"@com_github_edgelesssys_go_tdx_qpl//verification",
|
||||
"@com_github_edgelesssys_go_tdx_qpl//verification/types",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/go-tdx-qpl/tdx"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import (
|
|||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/edgelesssys/go-tdx-qpl/verification"
|
||||
"github.com/edgelesssys/go-tdx-qpl/verification/types"
|
||||
)
|
||||
|
|
|
|||
9
internal/attestation/variant/BUILD.bazel
Normal file
9
internal/attestation/variant/BUILD.bazel
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "variant",
|
||||
srcs = ["variant.go"],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/variant",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = ["//internal/cloud/cloudprovider"],
|
||||
)
|
||||
294
internal/attestation/variant/variant.go
Normal file
294
internal/attestation/variant/variant.go
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
Package variant defines Attestation variants for different CSPs.
|
||||
|
||||
Each variant defines an OID, a string representation, and a function to compare it to other OIDs.
|
||||
|
||||
The OID is used in attested TLS to distinguish the attestation documents.
|
||||
OIDs beginning with 1.3.9900 are reserved and can be used without registration.
|
||||
|
||||
* The 1.3.9900.1 branch is reserved for placeholder values and testing.
|
||||
|
||||
* The 1.3.9900.2 branch is reserved for AWS.
|
||||
|
||||
* The 1.3.9900.3 branch is reserved for GCP.
|
||||
|
||||
* The 1.3.9900.4 branch is reserved for Azure.
|
||||
|
||||
* The 1.3.9900.5 branch is reserved for QEMU.
|
||||
|
||||
Deprecated OIDs should never be reused for different purposes.
|
||||
Instead, new OIDs should be added in the appropriate branch at the next available index.
|
||||
|
||||
String representation should be lowercase and contain only letters, numbers, and hyphens.
|
||||
They should be prefixed with the branch name, e.g. all variants in the 1.3.9900.2 (AWS) branch should start with "aws-".
|
||||
Each variant should have a unique string representation.
|
||||
*/
|
||||
package variant
|
||||
|
||||
import (
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
)
|
||||
|
||||
const (
|
||||
dummy = "dummy"
|
||||
awsNitroTPM = "aws-nitro-tpm"
|
||||
awsSEVSNP = "aws-sev-snp"
|
||||
gcpSEVES = "gcp-sev-es"
|
||||
azureSEVSNP = "azure-sev-snp"
|
||||
azureTrustedLaunch = "azure-trustedlaunch"
|
||||
qemuVTPM = "qemu-vtpm"
|
||||
qemuTDX = "qemu-tdx"
|
||||
)
|
||||
|
||||
var providerAttestationMapping = map[cloudprovider.Provider][]Variant{
|
||||
cloudprovider.AWS: {AWSSEVSNP{}, AWSNitroTPM{}},
|
||||
cloudprovider.Azure: {AzureSEVSNP{}, AzureTrustedLaunch{}},
|
||||
cloudprovider.GCP: {GCPSEVES{}},
|
||||
cloudprovider.QEMU: {QEMUVTPM{}},
|
||||
cloudprovider.OpenStack: {QEMUVTPM{}},
|
||||
}
|
||||
|
||||
// GetDefaultAttestation returns the default attestation type for the given provider. If not found, it returns the default variant.
|
||||
func GetDefaultAttestation(provider cloudprovider.Provider) Variant {
|
||||
res, ok := providerAttestationMapping[provider]
|
||||
if ok {
|
||||
return res[0]
|
||||
}
|
||||
return Dummy{}
|
||||
}
|
||||
|
||||
// GetAvailableAttestationTypes returns the available attestation types.
|
||||
func GetAvailableAttestationTypes() []Variant {
|
||||
var res []Variant
|
||||
|
||||
// assumes that cloudprovider.Provider is a uint32 to sort the providers and get a consistent order
|
||||
var keys []cloudprovider.Provider
|
||||
for k := range providerAttestationMapping {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return uint(keys[i]) < uint(keys[j])
|
||||
})
|
||||
|
||||
for _, k := range keys {
|
||||
res = append(res, providerAttestationMapping[k]...)
|
||||
}
|
||||
return RemoveDuplicate(res)
|
||||
}
|
||||
|
||||
// Getter returns an ASN.1 Object Identifier.
|
||||
type Getter interface {
|
||||
OID() asn1.ObjectIdentifier
|
||||
}
|
||||
|
||||
// Variant describes an attestation variant.
|
||||
type Variant interface {
|
||||
Getter
|
||||
String() string
|
||||
Equal(other Getter) bool
|
||||
}
|
||||
|
||||
// FromString returns the OID for the given string.
|
||||
func FromString(oid string) (Variant, error) {
|
||||
switch oid {
|
||||
case dummy:
|
||||
return Dummy{}, nil
|
||||
case awsSEVSNP:
|
||||
return AWSSEVSNP{}, nil
|
||||
case awsNitroTPM:
|
||||
return AWSNitroTPM{}, nil
|
||||
case gcpSEVES:
|
||||
return GCPSEVES{}, nil
|
||||
case azureSEVSNP:
|
||||
return AzureSEVSNP{}, nil
|
||||
case azureTrustedLaunch:
|
||||
return AzureTrustedLaunch{}, nil
|
||||
case qemuVTPM:
|
||||
return QEMUVTPM{}, nil
|
||||
case qemuTDX:
|
||||
return QEMUTDX{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown OID: %q", oid)
|
||||
}
|
||||
|
||||
// ValidProvider returns true if the attestation type is valid for the given provider.
|
||||
func ValidProvider(provider cloudprovider.Provider, variant Variant) bool {
|
||||
validTypes, ok := providerAttestationMapping[provider]
|
||||
if ok {
|
||||
for _, aType := range validTypes {
|
||||
if variant.Equal(aType) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Dummy OID for testfing.
|
||||
type Dummy struct{}
|
||||
|
||||
// OID returns the struct's object identifier.
|
||||
func (Dummy) OID() asn1.ObjectIdentifier {
|
||||
return asn1.ObjectIdentifier{1, 3, 9900, 1, 1}
|
||||
}
|
||||
|
||||
// String returns the string representation of the OID.
|
||||
func (Dummy) String() string {
|
||||
return dummy
|
||||
}
|
||||
|
||||
// Equal returns true if the other variant is also a Default.
|
||||
func (Dummy) Equal(other Getter) bool {
|
||||
return other.OID().Equal(Dummy{}.OID())
|
||||
}
|
||||
|
||||
// AWSNitroTPM holds the AWS nitro TPM OID.
|
||||
type AWSNitroTPM struct{}
|
||||
|
||||
// OID returns the struct's object identifier.
|
||||
func (AWSNitroTPM) OID() asn1.ObjectIdentifier {
|
||||
return asn1.ObjectIdentifier{1, 3, 9900, 2, 1}
|
||||
}
|
||||
|
||||
// String returns the string representation of the OID.
|
||||
func (AWSNitroTPM) String() string {
|
||||
return awsNitroTPM
|
||||
}
|
||||
|
||||
// Equal returns true if the other variant is also AWSNitroTPM.
|
||||
func (AWSNitroTPM) Equal(other Getter) bool {
|
||||
return other.OID().Equal(AWSNitroTPM{}.OID())
|
||||
}
|
||||
|
||||
// AWSSEVSNP holds the AWS nitro TPM OID.
|
||||
type AWSSEVSNP struct{}
|
||||
|
||||
// OID returns the struct's object identifier.
|
||||
func (AWSSEVSNP) OID() asn1.ObjectIdentifier {
|
||||
return asn1.ObjectIdentifier{1, 3, 9900, 2, 2}
|
||||
}
|
||||
|
||||
// String returns the string representation of the OID.
|
||||
func (AWSSEVSNP) String() string {
|
||||
return awsSEVSNP
|
||||
}
|
||||
|
||||
// Equal returns true if the other variant is also AWSSEVSNP.
|
||||
func (AWSSEVSNP) Equal(other Getter) bool {
|
||||
return other.OID().Equal(AWSSEVSNP{}.OID())
|
||||
}
|
||||
|
||||
// GCPSEVES holds the GCP SEV-ES OID.
|
||||
type GCPSEVES struct{}
|
||||
|
||||
// OID returns the struct's object identifier.
|
||||
func (GCPSEVES) OID() asn1.ObjectIdentifier {
|
||||
return asn1.ObjectIdentifier{1, 3, 9900, 3, 1}
|
||||
}
|
||||
|
||||
// String returns the string representation of the OID.
|
||||
func (GCPSEVES) String() string {
|
||||
return gcpSEVES
|
||||
}
|
||||
|
||||
// Equal returns true if the other variant is also GCPSEVES.
|
||||
func (GCPSEVES) Equal(other Getter) bool {
|
||||
return other.OID().Equal(GCPSEVES{}.OID())
|
||||
}
|
||||
|
||||
// AzureSEVSNP holds the OID for Azure SNP CVMs.
|
||||
type AzureSEVSNP struct{}
|
||||
|
||||
// OID returns the struct's object identifier.
|
||||
func (AzureSEVSNP) OID() asn1.ObjectIdentifier {
|
||||
return asn1.ObjectIdentifier{1, 3, 9900, 4, 1}
|
||||
}
|
||||
|
||||
// String returns the string representation of the OID.
|
||||
func (AzureSEVSNP) String() string {
|
||||
return azureSEVSNP
|
||||
}
|
||||
|
||||
// Equal returns true if the other variant is also AzureSEVSNP.
|
||||
func (AzureSEVSNP) Equal(other Getter) bool {
|
||||
return other.OID().Equal(AzureSEVSNP{}.OID())
|
||||
}
|
||||
|
||||
// AzureTrustedLaunch holds the OID for Azure TrustedLaunch VMs.
|
||||
type AzureTrustedLaunch struct{}
|
||||
|
||||
// OID returns the struct's object identifier.
|
||||
func (AzureTrustedLaunch) OID() asn1.ObjectIdentifier {
|
||||
return asn1.ObjectIdentifier{1, 3, 9900, 4, 2}
|
||||
}
|
||||
|
||||
// String returns the string representation of the OID.
|
||||
func (AzureTrustedLaunch) String() string {
|
||||
return azureTrustedLaunch
|
||||
}
|
||||
|
||||
// Equal returns true if the other variant is also AzureTrustedLaunch.
|
||||
func (AzureTrustedLaunch) Equal(other Getter) bool {
|
||||
return other.OID().Equal(AzureTrustedLaunch{}.OID())
|
||||
}
|
||||
|
||||
// QEMUVTPM holds the QEMUVTPM OID.
|
||||
type QEMUVTPM struct{}
|
||||
|
||||
// OID returns the struct's object identifier.
|
||||
func (QEMUVTPM) OID() asn1.ObjectIdentifier {
|
||||
return asn1.ObjectIdentifier{1, 3, 9900, 5, 1}
|
||||
}
|
||||
|
||||
// String returns the string representation of the OID.
|
||||
func (QEMUVTPM) String() string {
|
||||
return qemuVTPM
|
||||
}
|
||||
|
||||
// Equal returns true if the other variant is also QEMUVTPM.
|
||||
func (QEMUVTPM) Equal(other Getter) bool {
|
||||
return other.OID().Equal(QEMUVTPM{}.OID())
|
||||
}
|
||||
|
||||
// QEMUTDX holds the QEMU TDX OID.
|
||||
// Placeholder for dev-cloud integration.
|
||||
type QEMUTDX struct{}
|
||||
|
||||
// OID returns the struct's object identifier.
|
||||
// Placeholder for dev-cloud integration.
|
||||
func (QEMUTDX) OID() asn1.ObjectIdentifier {
|
||||
return asn1.ObjectIdentifier{1, 3, 9900, 5, 99}
|
||||
}
|
||||
|
||||
// String returns the string representation of the OID.
|
||||
func (QEMUTDX) String() string {
|
||||
return qemuTDX
|
||||
}
|
||||
|
||||
// Equal returns true if the other variant is also QEMUTDX.
|
||||
func (QEMUTDX) Equal(other Getter) bool {
|
||||
return other.OID().Equal(QEMUTDX{}.OID())
|
||||
}
|
||||
|
||||
// RemoveDuplicate removes duplicate elements from a slice.
|
||||
func RemoveDuplicate[T comparable](sliceList []T) []T {
|
||||
allKeys := make(map[T]bool)
|
||||
list := []T{}
|
||||
for _, item := range sliceList {
|
||||
if _, value := allKeys[item]; !value {
|
||||
allKeys[item] = true
|
||||
list = append(list, item)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue