mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
config: add attestation variant (#1413)
* Add attestation type to config (optional for now) * Get attestation variant from config in CLI * Set attestation variant for Constellation services in helm deployments * Remove AzureCVM variable from helm deployments --------- Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
8679988b6c
commit
6ea5588bdc
@ -21,7 +21,7 @@ type clusterFake struct{}
|
|||||||
|
|
||||||
// InitCluster fakes bootstrapping a new cluster with the current node being the master, returning the arguments required to join the cluster.
|
// InitCluster fakes bootstrapping a new cluster with the current node being the master, returning the arguments required to join the cluster.
|
||||||
func (c *clusterFake) InitCluster(
|
func (c *clusterFake) InitCluster(
|
||||||
context.Context, string, string, string, []byte, []uint32, bool, bool,
|
context.Context, string, string, string, []byte, []uint32, bool,
|
||||||
[]byte, bool, components.Components, *logger.Logger,
|
[]byte, bool, components.Components, *logger.Logger,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
return []byte{}, nil
|
return []byte{}, nil
|
||||||
|
@ -11,7 +11,6 @@ go_library(
|
|||||||
"//bootstrapper/internal/diskencryption",
|
"//bootstrapper/internal/diskencryption",
|
||||||
"//internal/atls",
|
"//internal/atls",
|
||||||
"//internal/attestation",
|
"//internal/attestation",
|
||||||
"//internal/attestation/azure/snp",
|
|
||||||
"//internal/crypto",
|
"//internal/crypto",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
"//internal/grpc/atlscredentials",
|
"//internal/grpc/atlscredentials",
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/diskencryption"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/diskencryption"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/grpc/atlscredentials"
|
"github.com/edgelesssys/constellation/v2/internal/grpc/atlscredentials"
|
||||||
@ -168,9 +167,6 @@ func (s *Server) Init(ctx context.Context, req *initproto.InitRequest) (*initpro
|
|||||||
return nil, status.Errorf(codes.Internal, "persisting node state: %s", err)
|
return nil, status.Errorf(codes.Internal, "persisting node state: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we are running on a CVM
|
|
||||||
_, isCVM := s.issuer.(*snp.Issuer)
|
|
||||||
|
|
||||||
clusterName := req.ClusterName
|
clusterName := req.ClusterName
|
||||||
if clusterName == "" {
|
if clusterName == "" {
|
||||||
clusterName = "constellation"
|
clusterName = "constellation"
|
||||||
@ -183,7 +179,6 @@ func (s *Server) Init(ctx context.Context, req *initproto.InitRequest) (*initpro
|
|||||||
measurementSalt,
|
measurementSalt,
|
||||||
req.EnforcedPcrs,
|
req.EnforcedPcrs,
|
||||||
req.EnforceIdkeydigest,
|
req.EnforceIdkeydigest,
|
||||||
isCVM,
|
|
||||||
req.HelmDeployments,
|
req.HelmDeployments,
|
||||||
req.ConformanceMode,
|
req.ConformanceMode,
|
||||||
components.NewComponentsFromInitProto(req.KubernetesComponents),
|
components.NewComponentsFromInitProto(req.KubernetesComponents),
|
||||||
@ -260,7 +255,6 @@ type ClusterInitializer interface {
|
|||||||
measurementSalt []byte,
|
measurementSalt []byte,
|
||||||
enforcedPcrs []uint32,
|
enforcedPcrs []uint32,
|
||||||
enforceIDKeyDigest bool,
|
enforceIDKeyDigest bool,
|
||||||
azureCVM bool,
|
|
||||||
helmDeployments []byte,
|
helmDeployments []byte,
|
||||||
conformanceMode bool,
|
conformanceMode bool,
|
||||||
kubernetesComponents components.Components,
|
kubernetesComponents components.Components,
|
||||||
|
@ -320,7 +320,7 @@ type stubClusterInitializer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *stubClusterInitializer) InitCluster(
|
func (i *stubClusterInitializer) InitCluster(
|
||||||
context.Context, string, string, string, []byte, []uint32, bool, bool,
|
context.Context, string, string, string, []byte, []uint32, bool,
|
||||||
[]byte, bool, components.Components, *logger.Logger,
|
[]byte, bool, components.Components, *logger.Logger,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
return i.initClusterKubeconfig, i.initClusterErr
|
return i.initClusterKubeconfig, i.initClusterErr
|
||||||
|
@ -15,7 +15,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -82,7 +81,7 @@ func New(cloudProvider string, clusterUtil clusterUtil, configProvider configura
|
|||||||
// InitCluster initializes a new Kubernetes cluster and applies pod network provider.
|
// InitCluster initializes a new Kubernetes cluster and applies pod network provider.
|
||||||
func (k *KubeWrapper) InitCluster(
|
func (k *KubeWrapper) InitCluster(
|
||||||
ctx context.Context, cloudServiceAccountURI, versionString, clusterName string,
|
ctx context.Context, cloudServiceAccountURI, versionString, clusterName string,
|
||||||
measurementSalt []byte, enforcedPCRs []uint32, enforceIDKeyDigest bool, azureCVM bool,
|
measurementSalt []byte, enforcedPCRs []uint32, enforceIDKeyDigest bool,
|
||||||
helmReleasesRaw []byte, conformanceMode bool, kubernetesComponents components.Components, log *logger.Logger,
|
helmReleasesRaw []byte, conformanceMode bool, kubernetesComponents components.Components, log *logger.Logger,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
log.With(zap.String("version", versionString)).Infof("Installing Kubernetes components")
|
log.With(zap.String("version", versionString)).Infof("Installing Kubernetes components")
|
||||||
@ -222,7 +221,7 @@ func (k *KubeWrapper) InitCluster(
|
|||||||
return nil, fmt.Errorf("installing constellation-services: %w", err)
|
return nil, fmt.Errorf("installing constellation-services: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := k.setupInternalConfigMap(ctx, strconv.FormatBool(azureCVM)); err != nil {
|
if err := k.setupInternalConfigMap(ctx); err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup internal ConfigMap: %w", err)
|
return nil, fmt.Errorf("failed to setup internal ConfigMap: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +318,7 @@ func (k *KubeWrapper) setupK8sComponentsConfigMap(ctx context.Context, component
|
|||||||
}
|
}
|
||||||
|
|
||||||
// setupInternalConfigMap applies a ConfigMap (cf. server-side apply) to store information that is not supposed to be user-editable.
|
// setupInternalConfigMap applies a ConfigMap (cf. server-side apply) to store information that is not supposed to be user-editable.
|
||||||
func (k *KubeWrapper) setupInternalConfigMap(ctx context.Context, azureCVM string) error {
|
func (k *KubeWrapper) setupInternalConfigMap(ctx context.Context) error {
|
||||||
config := corev1.ConfigMap{
|
config := corev1.ConfigMap{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
APIVersion: "v1",
|
APIVersion: "v1",
|
||||||
@ -329,9 +328,7 @@ func (k *KubeWrapper) setupInternalConfigMap(ctx context.Context, azureCVM strin
|
|||||||
Name: constants.InternalConfigMap,
|
Name: constants.InternalConfigMap,
|
||||||
Namespace: "kube-system",
|
Namespace: "kube-system",
|
||||||
},
|
},
|
||||||
Data: map[string]string{
|
Data: map[string]string{},
|
||||||
constants.AzureCVM: azureCVM,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We do not use the client's Apply method here since we are handling a kubernetes-native type.
|
// We do not use the client's Apply method here since we are handling a kubernetes-native type.
|
||||||
|
@ -216,7 +216,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
|
|
||||||
_, err := kube.InitCluster(
|
_, err := kube.InitCluster(
|
||||||
context.Background(), serviceAccountURI, string(tc.k8sVersion), "kubernetes",
|
context.Background(), serviceAccountURI, string(tc.k8sVersion), "kubernetes",
|
||||||
nil, nil, false, true, []byte("{}"), false, nil, logger.NewTest(t),
|
nil, nil, false, []byte("{}"), false, nil, logger.NewTest(t),
|
||||||
)
|
)
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
|
@ -23,13 +23,9 @@ go_library(
|
|||||||
"//cli/internal/libvirt",
|
"//cli/internal/libvirt",
|
||||||
"//cli/internal/terraform",
|
"//cli/internal/terraform",
|
||||||
"//internal/atls",
|
"//internal/atls",
|
||||||
"//internal/attestation/aws",
|
"//internal/attestation/choose",
|
||||||
"//internal/attestation/azure/snp",
|
|
||||||
"//internal/attestation/azure/trustedlaunch",
|
|
||||||
"//internal/attestation/gcp",
|
|
||||||
"//internal/attestation/idkeydigest",
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/attestation/qemu",
|
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/cloud/gcpshared",
|
"//internal/cloud/gcpshared",
|
||||||
"//internal/compatibility",
|
"//internal/compatibility",
|
||||||
@ -37,6 +33,7 @@ go_library(
|
|||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/kubernetes",
|
"//internal/kubernetes",
|
||||||
"//internal/kubernetes/kubectl",
|
"//internal/kubernetes/kubectl",
|
||||||
|
"//internal/oid",
|
||||||
"//internal/versions",
|
"//internal/versions",
|
||||||
"//internal/versions/components",
|
"//internal/versions/components",
|
||||||
"//internal/versionsapi",
|
"//internal/versionsapi",
|
||||||
@ -83,6 +80,7 @@ go_test(
|
|||||||
"//internal/config",
|
"//internal/config",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/oid",
|
||||||
"//internal/versions",
|
"//internal/versions",
|
||||||
"//internal/versions/components",
|
"//internal/versions/components",
|
||||||
"//operators/constellation-node-operator/api/v1alpha1",
|
"//operators/constellation-node-operator/api/v1alpha1",
|
||||||
|
@ -14,46 +14,40 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/aws"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
|
||||||
"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/idkeydigest"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/qemu"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validator validates Platform Configuration Registers (PCRs).
|
// Validator validates Platform Configuration Registers (PCRs).
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
provider cloudprovider.Provider
|
attestationVariant oid.Getter
|
||||||
pcrs measurements.M
|
pcrs measurements.M
|
||||||
idkeydigests idkeydigest.IDKeyDigests
|
idkeydigests idkeydigest.IDKeyDigests
|
||||||
enforceIDKeyDigest bool
|
enforceIDKeyDigest bool
|
||||||
azureCVM bool
|
|
||||||
validator atls.Validator
|
validator atls.Validator
|
||||||
log debugLog
|
log debugLog
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidator creates a new Validator.
|
// NewValidator creates a new Validator.
|
||||||
func NewValidator(provider cloudprovider.Provider, conf *config.Config, log debugLog) (*Validator, error) {
|
func NewValidator(conf *config.Config, log debugLog) (*Validator, error) {
|
||||||
v := Validator{log: log}
|
v := Validator{log: log}
|
||||||
if provider == cloudprovider.Unknown {
|
variant, err := oid.FromString(conf.AttestationVariant)
|
||||||
return nil, errors.New("unknown cloud provider")
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing attestation variant: %w", err)
|
||||||
}
|
}
|
||||||
v.provider = provider
|
v.attestationVariant = variant // valid variant
|
||||||
|
|
||||||
if err := v.setPCRs(conf); err != nil {
|
if err := v.setPCRs(conf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.provider == cloudprovider.Azure {
|
if v.attestationVariant.OID().Equal(oid.AzureSEVSNP{}.OID()) {
|
||||||
v.azureCVM = *conf.Provider.Azure.ConfidentialVM
|
v.enforceIDKeyDigest = conf.EnforcesIDKeyDigest()
|
||||||
if v.azureCVM {
|
v.idkeydigests = conf.IDKeyDigests()
|
||||||
v.enforceIDKeyDigest = *conf.Provider.Azure.EnforceIDKeyDigest
|
|
||||||
v.idkeydigests = conf.Provider.Azure.IDKeyDigest
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v, nil
|
return &v, nil
|
||||||
@ -100,26 +94,26 @@ func (v *Validator) updatePCR(pcrIndex uint32, encoded string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validator) setPCRs(config *config.Config) error {
|
func (v *Validator) setPCRs(config *config.Config) error {
|
||||||
switch v.provider {
|
switch v.attestationVariant {
|
||||||
case cloudprovider.AWS:
|
case oid.AWSNitroTPM{}:
|
||||||
awsPCRs := config.Provider.AWS.Measurements
|
awsPCRs := config.Provider.AWS.Measurements
|
||||||
if len(awsPCRs) == 0 {
|
if len(awsPCRs) == 0 {
|
||||||
return errors.New("no expected measurement provided")
|
return errors.New("no expected measurement provided")
|
||||||
}
|
}
|
||||||
v.pcrs = awsPCRs
|
v.pcrs = awsPCRs
|
||||||
case cloudprovider.Azure:
|
case oid.AzureSEVSNP{}, oid.AzureTrustedLaunch{}:
|
||||||
azurePCRs := config.Provider.Azure.Measurements
|
azurePCRs := config.Provider.Azure.Measurements
|
||||||
if len(azurePCRs) == 0 {
|
if len(azurePCRs) == 0 {
|
||||||
return errors.New("no expected measurement provided")
|
return errors.New("no expected measurement provided")
|
||||||
}
|
}
|
||||||
v.pcrs = azurePCRs
|
v.pcrs = azurePCRs
|
||||||
case cloudprovider.GCP:
|
case oid.GCPSEVES{}:
|
||||||
gcpPCRs := config.Provider.GCP.Measurements
|
gcpPCRs := config.Provider.GCP.Measurements
|
||||||
if len(gcpPCRs) == 0 {
|
if len(gcpPCRs) == 0 {
|
||||||
return errors.New("no expected measurement provided")
|
return errors.New("no expected measurement provided")
|
||||||
}
|
}
|
||||||
v.pcrs = gcpPCRs
|
v.pcrs = gcpPCRs
|
||||||
case cloudprovider.QEMU:
|
case oid.QEMUVTPM{}:
|
||||||
qemuPCRs := config.Provider.QEMU.Measurements
|
qemuPCRs := config.Provider.QEMU.Measurements
|
||||||
if len(qemuPCRs) == 0 {
|
if len(qemuPCRs) == 0 {
|
||||||
return errors.New("no expected measurement provided")
|
return errors.New("no expected measurement provided")
|
||||||
@ -142,20 +136,9 @@ func (v *Validator) PCRS() measurements.M {
|
|||||||
|
|
||||||
func (v *Validator) updateValidator(cmd *cobra.Command) {
|
func (v *Validator) updateValidator(cmd *cobra.Command) {
|
||||||
log := warnLogger{cmd: cmd, log: v.log}
|
log := warnLogger{cmd: cmd, log: v.log}
|
||||||
switch v.provider {
|
|
||||||
case cloudprovider.GCP:
|
// Use of a valid variant has been check in NewValidator so we may drop the error
|
||||||
v.validator = gcp.NewValidator(v.pcrs, log)
|
v.validator, _ = choose.Validator(v.attestationVariant, v.pcrs, v.idkeydigests, v.enforceIDKeyDigest, log)
|
||||||
case cloudprovider.Azure:
|
|
||||||
if v.azureCVM {
|
|
||||||
v.validator = snp.NewValidator(v.pcrs, v.idkeydigests, v.enforceIDKeyDigest, log)
|
|
||||||
} else {
|
|
||||||
v.validator = trustedlaunch.NewValidator(v.pcrs, log)
|
|
||||||
}
|
|
||||||
case cloudprovider.AWS:
|
|
||||||
v.validator = aws.NewValidator(v.pcrs, log)
|
|
||||||
case cloudprovider.QEMU:
|
|
||||||
v.validator = qemu.NewValidator(v.pcrs, log)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// warnLogger implements logging of warnings for validators.
|
// warnLogger implements logging of warnings for validators.
|
||||||
|
@ -19,11 +19,12 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/qemu"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/qemu"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewValidator(t *testing.T) {
|
func TestNewValidator(t *testing.T) {
|
||||||
@ -37,47 +38,82 @@ func TestNewValidator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
provider cloudprovider.Provider
|
config *config.Config
|
||||||
config *config.Config
|
wantErr bool
|
||||||
pcrs measurements.M
|
|
||||||
enforceIDKeyDigest bool
|
|
||||||
digest idkeydigest.IDKeyDigests
|
|
||||||
azureCVM bool
|
|
||||||
wantErr bool
|
|
||||||
}{
|
}{
|
||||||
"gcp": {
|
"gcp": {
|
||||||
provider: cloudprovider.GCP,
|
config: &config.Config{
|
||||||
pcrs: testPCRs,
|
AttestationVariant: oid.GCPSEVES{}.String(),
|
||||||
|
Provider: config.ProviderConfig{
|
||||||
|
GCP: &config.GCPConfig{
|
||||||
|
Measurements: testPCRs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"azure cvm": {
|
"azure cvm": {
|
||||||
provider: cloudprovider.Azure,
|
config: &config.Config{
|
||||||
pcrs: testPCRs,
|
AttestationVariant: oid.AzureSEVSNP{}.String(),
|
||||||
azureCVM: true,
|
Provider: config.ProviderConfig{
|
||||||
|
Azure: &config.AzureConfig{
|
||||||
|
Measurements: testPCRs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"azure trusted launch": {
|
"azure trusted launch": {
|
||||||
provider: cloudprovider.Azure,
|
config: &config.Config{
|
||||||
pcrs: testPCRs,
|
AttestationVariant: oid.AzureTrustedLaunch{}.String(),
|
||||||
azureCVM: false,
|
Provider: config.ProviderConfig{
|
||||||
|
Azure: &config.AzureConfig{
|
||||||
|
Measurements: testPCRs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"qemu": {
|
"qemu": {
|
||||||
provider: cloudprovider.QEMU,
|
config: &config.Config{
|
||||||
pcrs: testPCRs,
|
AttestationVariant: oid.QEMUVTPM{}.String(),
|
||||||
|
Provider: config.ProviderConfig{
|
||||||
|
QEMU: &config.QEMUConfig{
|
||||||
|
Measurements: testPCRs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"no pcrs provided": {
|
"no pcrs provided": {
|
||||||
provider: cloudprovider.Azure,
|
config: &config.Config{
|
||||||
pcrs: measurements.M{},
|
AttestationVariant: oid.AzureSEVSNP{}.String(),
|
||||||
wantErr: true,
|
Provider: config.ProviderConfig{
|
||||||
|
Azure: &config.AzureConfig{
|
||||||
|
Measurements: measurements.M{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"unknown provider": {
|
"unknown variant": {
|
||||||
provider: cloudprovider.Unknown,
|
config: &config.Config{
|
||||||
pcrs: testPCRs,
|
AttestationVariant: "unknown",
|
||||||
wantErr: true,
|
Provider: config.ProviderConfig{
|
||||||
|
QEMU: &config.QEMUConfig{
|
||||||
|
Measurements: testPCRs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"set idkeydigest": {
|
"set idkeydigest": {
|
||||||
provider: cloudprovider.Azure,
|
config: &config.Config{
|
||||||
pcrs: testPCRs,
|
AttestationVariant: oid.AzureSEVSNP{}.String(),
|
||||||
digest: idkeydigest.IDKeyDigests{[]byte("414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141")},
|
Provider: config.ProviderConfig{
|
||||||
enforceIDKeyDigest: true,
|
Azure: &config.AzureConfig{
|
||||||
|
Measurements: testPCRs,
|
||||||
|
IDKeyDigest: idkeydigest.IDKeyDigests{[]byte("414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141")},
|
||||||
|
EnforceIDKeyDigest: &[]bool{true}[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,25 +121,16 @@ func TestNewValidator(t *testing.T) {
|
|||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
conf := &config.Config{Provider: config.ProviderConfig{}}
|
validators, err := NewValidator(tc.config, logger.NewTest(t))
|
||||||
if tc.provider == cloudprovider.GCP {
|
|
||||||
conf.Provider.GCP = &config.GCPConfig{Measurements: tc.pcrs}
|
|
||||||
}
|
|
||||||
if tc.provider == cloudprovider.Azure {
|
|
||||||
conf.Provider.Azure = &config.AzureConfig{Measurements: tc.pcrs, EnforceIDKeyDigest: &tc.enforceIDKeyDigest, IDKeyDigest: tc.digest, ConfidentialVM: &tc.azureCVM}
|
|
||||||
}
|
|
||||||
if tc.provider == cloudprovider.QEMU {
|
|
||||||
conf.Provider.QEMU = &config.QEMUConfig{Measurements: tc.pcrs}
|
|
||||||
}
|
|
||||||
|
|
||||||
validators, err := NewValidator(tc.provider, conf, logger.NewTest(t))
|
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
} else {
|
} else {
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(tc.pcrs, validators.pcrs)
|
assert.Equal(tc.config.GetMeasurements(), validators.pcrs)
|
||||||
assert.Equal(tc.provider, validators.provider)
|
variant, err := oid.FromString(tc.config.AttestationVariant)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(variant, validators.attestationVariant)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -129,31 +156,29 @@ func TestValidatorV(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
provider cloudprovider.Provider
|
variant oid.Getter
|
||||||
pcrs measurements.M
|
pcrs measurements.M
|
||||||
wantVs atls.Validator
|
wantVs atls.Validator
|
||||||
azureCVM bool
|
|
||||||
}{
|
}{
|
||||||
"gcp": {
|
"gcp": {
|
||||||
provider: cloudprovider.GCP,
|
variant: oid.GCPSEVES{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
wantVs: gcp.NewValidator(newTestPCRs(), nil),
|
wantVs: gcp.NewValidator(newTestPCRs(), nil),
|
||||||
},
|
},
|
||||||
"azure cvm": {
|
"azure cvm": {
|
||||||
provider: cloudprovider.Azure,
|
variant: oid.AzureSEVSNP{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
wantVs: snp.NewValidator(newTestPCRs(), idkeydigest.IDKeyDigests{}, false, nil),
|
wantVs: snp.NewValidator(newTestPCRs(), idkeydigest.IDKeyDigests{}, false, nil),
|
||||||
azureCVM: true,
|
|
||||||
},
|
},
|
||||||
"azure trusted launch": {
|
"azure trusted launch": {
|
||||||
provider: cloudprovider.Azure,
|
variant: oid.AzureTrustedLaunch{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
wantVs: trustedlaunch.NewValidator(newTestPCRs(), nil),
|
wantVs: trustedlaunch.NewValidator(newTestPCRs(), nil),
|
||||||
},
|
},
|
||||||
"qemu": {
|
"qemu": {
|
||||||
provider: cloudprovider.QEMU,
|
variant: oid.QEMUVTPM{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
wantVs: qemu.NewValidator(newTestPCRs(), nil),
|
wantVs: qemu.NewValidator(newTestPCRs(), nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +186,7 @@ func TestValidatorV(t *testing.T) {
|
|||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
validators := &Validator{provider: tc.provider, pcrs: tc.pcrs, azureCVM: tc.azureCVM}
|
validators := &Validator{attestationVariant: tc.variant, pcrs: tc.pcrs}
|
||||||
|
|
||||||
resultValidator := validators.V(&cobra.Command{})
|
resultValidator := validators.V(&cobra.Command{})
|
||||||
|
|
||||||
@ -206,53 +231,53 @@ func TestValidatorUpdateInitPCRs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
provider cloudprovider.Provider
|
variant oid.Getter
|
||||||
pcrs measurements.M
|
pcrs measurements.M
|
||||||
ownerID string
|
ownerID string
|
||||||
clusterID string
|
clusterID string
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"gcp update owner ID": {
|
"gcp update owner ID": {
|
||||||
provider: cloudprovider.GCP,
|
variant: oid.GCPSEVES{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
ownerID: one64,
|
ownerID: one64,
|
||||||
},
|
},
|
||||||
"gcp update cluster ID": {
|
"gcp update cluster ID": {
|
||||||
provider: cloudprovider.GCP,
|
variant: oid.GCPSEVES{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
clusterID: one64,
|
clusterID: one64,
|
||||||
},
|
},
|
||||||
"gcp update both": {
|
"gcp update both": {
|
||||||
provider: cloudprovider.GCP,
|
variant: oid.GCPSEVES{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
ownerID: one64,
|
ownerID: one64,
|
||||||
clusterID: one64,
|
clusterID: one64,
|
||||||
},
|
},
|
||||||
"azure update owner ID": {
|
"azure update owner ID": {
|
||||||
provider: cloudprovider.Azure,
|
variant: oid.AzureSEVSNP{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
ownerID: one64,
|
ownerID: one64,
|
||||||
},
|
},
|
||||||
"azure update cluster ID": {
|
"azure update cluster ID": {
|
||||||
provider: cloudprovider.Azure,
|
variant: oid.AzureSEVSNP{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
clusterID: one64,
|
clusterID: one64,
|
||||||
},
|
},
|
||||||
"azure update both": {
|
"azure update both": {
|
||||||
provider: cloudprovider.Azure,
|
variant: oid.AzureSEVSNP{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
ownerID: one64,
|
ownerID: one64,
|
||||||
clusterID: one64,
|
clusterID: one64,
|
||||||
},
|
},
|
||||||
"owner ID and cluster ID empty": {
|
"owner ID and cluster ID empty": {
|
||||||
provider: cloudprovider.GCP,
|
variant: oid.GCPSEVES{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
},
|
},
|
||||||
"invalid encoding": {
|
"invalid encoding": {
|
||||||
provider: cloudprovider.GCP,
|
variant: oid.GCPSEVES{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
ownerID: "invalid",
|
ownerID: "invalid",
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +285,7 @@ func TestValidatorUpdateInitPCRs(t *testing.T) {
|
|||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
validators := &Validator{provider: tc.provider, pcrs: tc.pcrs}
|
validators := &Validator{attestationVariant: tc.variant, pcrs: tc.pcrs}
|
||||||
|
|
||||||
err := validators.UpdateInitPCRs(tc.ownerID, tc.clusterID)
|
err := validators.UpdateInitPCRs(tc.ownerID, tc.clusterID)
|
||||||
|
|
||||||
@ -392,8 +417,8 @@ func TestUpdatePCR(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validators := &Validator{
|
validators := &Validator{
|
||||||
provider: cloudprovider.GCP,
|
attestationVariant: oid.GCPSEVES{},
|
||||||
pcrs: pcrs,
|
pcrs: pcrs,
|
||||||
}
|
}
|
||||||
err := validators.updatePCR(tc.pcrIndex, tc.encoded)
|
err := validators.updatePCR(tc.pcrIndex, tc.encoded)
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ go_library(
|
|||||||
"//internal/kubernetes/kubectl",
|
"//internal/kubernetes/kubectl",
|
||||||
"//internal/license",
|
"//internal/license",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/oid",
|
||||||
"//internal/retry",
|
"//internal/retry",
|
||||||
"//internal/sigstore",
|
"//internal/sigstore",
|
||||||
"//internal/versions",
|
"//internal/versions",
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
|
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
@ -105,6 +106,18 @@ func createConfig(provider cloudprovider.Provider) *config.Config {
|
|||||||
conf.StateDiskSizeGB = 10
|
conf.StateDiskSizeGB = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(AB#2976): Replace hardcoded values with user input
|
||||||
|
switch provider {
|
||||||
|
case cloudprovider.AWS:
|
||||||
|
conf.AttestationVariant = oid.AWSNitroTPM{}.String()
|
||||||
|
case cloudprovider.Azure:
|
||||||
|
conf.AttestationVariant = oid.AzureSEVSNP{}.String()
|
||||||
|
case cloudprovider.GCP:
|
||||||
|
conf.AttestationVariant = oid.GCPSEVES{}.String()
|
||||||
|
case cloudprovider.QEMU:
|
||||||
|
conf.AttestationVariant = oid.QEMUVTPM{}.String()
|
||||||
|
}
|
||||||
|
|
||||||
return conf
|
return conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -92,6 +93,9 @@ func TestConfigGenerateDefaultGCPSpecific(t *testing.T) {
|
|||||||
cg := &configGenerateCmd{log: logger.NewTest(t)}
|
cg := &configGenerateCmd{log: logger.NewTest(t)}
|
||||||
require.NoError(cg.configGenerate(cmd, fileHandler, cloudprovider.GCP))
|
require.NoError(cg.configGenerate(cmd, fileHandler, cloudprovider.GCP))
|
||||||
|
|
||||||
|
// TODO(AB#2976): Remove this once attestation variants are dynamically created
|
||||||
|
wantConf.AttestationVariant = oid.GCPSEVES{}.String()
|
||||||
|
|
||||||
var readConfig config.Config
|
var readConfig config.Config
|
||||||
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
|
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
@ -135,7 +135,7 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator *cloud
|
|||||||
cmd.PrintErrf("License check failed: %v", err)
|
cmd.PrintErrf("License check failed: %v", err)
|
||||||
}
|
}
|
||||||
i.log.Debugf("Checked license")
|
i.log.Debugf("Checked license")
|
||||||
validator, err := cloudcmd.NewValidator(provider, conf, i.log)
|
validator, err := cloudcmd.NewValidator(conf, i.log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -436,6 +436,7 @@ func TestAttestation(t *testing.T) {
|
|||||||
|
|
||||||
cfg := config.Default()
|
cfg := config.Default()
|
||||||
cfg.Image = "image"
|
cfg.Image = "image"
|
||||||
|
cfg.AttestationVariant = oid.QEMUVTPM{}.String()
|
||||||
cfg.RemoveProviderExcept(cloudprovider.QEMU)
|
cfg.RemoveProviderExcept(cloudprovider.QEMU)
|
||||||
cfg.Provider.QEMU.Measurements[0] = measurements.WithAllBytes(0x00, false)
|
cfg.Provider.QEMU.Measurements[0] = measurements.WithAllBytes(0x00, false)
|
||||||
cfg.Provider.QEMU.Measurements[1] = measurements.WithAllBytes(0x11, false)
|
cfg.Provider.QEMU.Measurements[1] = measurements.WithAllBytes(0x11, false)
|
||||||
@ -529,6 +530,7 @@ func defaultConfigWithExpectedMeasurements(t *testing.T, conf *config.Config, cs
|
|||||||
|
|
||||||
switch csp {
|
switch csp {
|
||||||
case cloudprovider.Azure:
|
case cloudprovider.Azure:
|
||||||
|
conf.AttestationVariant = oid.AzureSEVSNP{}.String()
|
||||||
conf.Provider.Azure.SubscriptionID = "01234567-0123-0123-0123-0123456789ab"
|
conf.Provider.Azure.SubscriptionID = "01234567-0123-0123-0123-0123456789ab"
|
||||||
conf.Provider.Azure.TenantID = "01234567-0123-0123-0123-0123456789ab"
|
conf.Provider.Azure.TenantID = "01234567-0123-0123-0123-0123456789ab"
|
||||||
conf.Provider.Azure.Location = "test-location"
|
conf.Provider.Azure.Location = "test-location"
|
||||||
@ -540,6 +542,7 @@ func defaultConfigWithExpectedMeasurements(t *testing.T, conf *config.Config, cs
|
|||||||
conf.Provider.Azure.Measurements[9] = measurements.WithAllBytes(0x11, false)
|
conf.Provider.Azure.Measurements[9] = measurements.WithAllBytes(0x11, false)
|
||||||
conf.Provider.Azure.Measurements[12] = measurements.WithAllBytes(0xcc, false)
|
conf.Provider.Azure.Measurements[12] = measurements.WithAllBytes(0xcc, false)
|
||||||
case cloudprovider.GCP:
|
case cloudprovider.GCP:
|
||||||
|
conf.AttestationVariant = oid.GCPSEVES{}.String()
|
||||||
conf.Provider.GCP.Region = "test-region"
|
conf.Provider.GCP.Region = "test-region"
|
||||||
conf.Provider.GCP.Project = "test-project"
|
conf.Provider.GCP.Project = "test-project"
|
||||||
conf.Provider.GCP.Zone = "test-zone"
|
conf.Provider.GCP.Zone = "test-zone"
|
||||||
@ -548,6 +551,7 @@ func defaultConfigWithExpectedMeasurements(t *testing.T, conf *config.Config, cs
|
|||||||
conf.Provider.GCP.Measurements[9] = measurements.WithAllBytes(0x11, false)
|
conf.Provider.GCP.Measurements[9] = measurements.WithAllBytes(0x11, false)
|
||||||
conf.Provider.GCP.Measurements[12] = measurements.WithAllBytes(0xcc, false)
|
conf.Provider.GCP.Measurements[12] = measurements.WithAllBytes(0xcc, false)
|
||||||
case cloudprovider.QEMU:
|
case cloudprovider.QEMU:
|
||||||
|
conf.AttestationVariant = oid.QEMUVTPM{}.String()
|
||||||
conf.Provider.QEMU.Measurements[4] = measurements.WithAllBytes(0x44, false)
|
conf.Provider.QEMU.Measurements[4] = measurements.WithAllBytes(0x44, false)
|
||||||
conf.Provider.QEMU.Measurements[9] = measurements.WithAllBytes(0x11, false)
|
conf.Provider.QEMU.Measurements[9] = measurements.WithAllBytes(0x11, false)
|
||||||
conf.Provider.QEMU.Measurements[12] = measurements.WithAllBytes(0xcc, false)
|
conf.Provider.QEMU.Measurements[12] = measurements.WithAllBytes(0xcc, false)
|
||||||
|
@ -95,7 +95,7 @@ func (r *recoverCmd) recover(
|
|||||||
interval = 20 * time.Second // Azure LB takes a while to remove unhealthy instances
|
interval = 20 * time.Second // Azure LB takes a while to remove unhealthy instances
|
||||||
}
|
}
|
||||||
|
|
||||||
validator, err := cloudcmd.NewValidator(provider, conf, r.log)
|
validator, err := cloudcmd.NewValidator(conf, r.log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ func (v *verifyCmd) verify(cmd *cobra.Command, fileHandler file.Handler, verifyC
|
|||||||
|
|
||||||
provider := conf.GetProvider()
|
provider := conf.GetProvider()
|
||||||
v.log.Debugf("Creating aTLS Validator for %s", provider)
|
v.log.Debugf("Creating aTLS Validator for %s", provider)
|
||||||
validators, err := cloudcmd.NewValidator(provider, conf, v.log)
|
validators, err := cloudcmd.NewValidator(conf, v.log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -357,6 +357,7 @@ go_test(
|
|||||||
"//internal/deploy/helm",
|
"//internal/deploy/helm",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/oid",
|
||||||
"@com_github_pkg_errors//:errors",
|
"@com_github_pkg_errors//:errors",
|
||||||
"@com_github_spf13_afero//:afero",
|
"@com_github_spf13_afero//:afero",
|
||||||
"@com_github_stretchr_testify//assert",
|
"@com_github_stretchr_testify//assert",
|
||||||
|
@ -39,6 +39,7 @@ spec:
|
|||||||
args:
|
args:
|
||||||
- --cloud-provider={{ .Values.csp }}
|
- --cloud-provider={{ .Values.csp }}
|
||||||
- --key-service-endpoint=key-service.{{ .Release.Namespace }}:{{ .Values.global.keyServicePort }}
|
- --key-service-endpoint=key-service.{{ .Release.Namespace }}:{{ .Values.global.keyServicePort }}
|
||||||
|
- --attestation-variant={{ .Values.attestationVariant }}
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: {{ .Values.global.serviceBasePath | quote }}
|
- mountPath: {{ .Values.global.serviceBasePath | quote }}
|
||||||
name: config
|
name: config
|
||||||
|
@ -28,13 +28,19 @@
|
|||||||
"description": "Salt used to generate node measurements",
|
"description": "Salt used to generate node measurements",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"examples": ["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"]
|
"examples": ["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"]
|
||||||
|
},
|
||||||
|
"attestationVariant": {
|
||||||
|
"description": "Attestation variant to use for aTLS connections.",
|
||||||
|
"type": "string",
|
||||||
|
"examples": ["azure-sev-snp", "azure-trusted-launch", "gcp-sev-es"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"csp",
|
"csp",
|
||||||
"measurements",
|
"measurements",
|
||||||
"measurementSalt",
|
"measurementSalt",
|
||||||
"image"
|
"image",
|
||||||
|
"attestationVariant"
|
||||||
],
|
],
|
||||||
"if": {
|
"if": {
|
||||||
"properties": { "csp": { "const": "azure" } },
|
"properties": { "csp": { "const": "azure" } },
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
csp: "gcp"
|
csp: "gcp"
|
||||||
|
attestationVariant: ""
|
||||||
joinServicePort: 9090
|
joinServicePort: 9090
|
||||||
joinServiceNodePort: 30090
|
joinServiceNodePort: 30090
|
||||||
|
@ -17,7 +17,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- args:
|
- args:
|
||||||
- --cloud-provider={{ .Values.csp }}
|
- --attestation-variant={{ .Values.attestationVariant }}
|
||||||
image: {{ .Values.image | quote }}
|
image: {{ .Values.image | quote }}
|
||||||
name: verification-service
|
name: verification-service
|
||||||
ports:
|
ports:
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft-07/schema#",
|
"$schema": "https://json-schema.org/draft-07/schema#",
|
||||||
"properties": {
|
"properties": {
|
||||||
"csp": {
|
|
||||||
"description": "CSP to which the chart is deployed.",
|
|
||||||
"enum": ["Azure", "GCP", "AWS", "QEMU"]
|
|
||||||
},
|
|
||||||
"image": {
|
"image": {
|
||||||
"description": "Container image to use for the spawned pods.",
|
"description": "Container image to use for the spawned pods.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -13,12 +9,17 @@
|
|||||||
"loadBalancerIP": {
|
"loadBalancerIP": {
|
||||||
"description": "IP of the k8s LB service",
|
"description": "IP of the k8s LB service",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"attestationVariant": {
|
||||||
|
"description": "Attestation variant to use for aTLS connections.",
|
||||||
|
"type": "string",
|
||||||
|
"examples": ["azure-sev-snp", "azure-trusted-launch", "gcp-sev-es"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"csp",
|
|
||||||
"image",
|
"image",
|
||||||
"loadBalancerIP"
|
"loadBalancerIP",
|
||||||
|
"attestationVariant"
|
||||||
],
|
],
|
||||||
"title": "Values",
|
"title": "Values",
|
||||||
"type": "object"
|
"type": "object"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
image: ""
|
||||||
|
attestationVariant: ""
|
||||||
httpContainerPort: 8080
|
httpContainerPort: 8080
|
||||||
grpcContainerPort: 9090
|
grpcContainerPort: 9090
|
||||||
httpNodePort: 30080
|
httpNodePort: 30080
|
||||||
|
@ -415,7 +415,6 @@ func (i *ChartLoader) loadConstellationServicesValues() (map[string]any, error)
|
|||||||
"image": i.autoscalerImage,
|
"image": i.autoscalerImage,
|
||||||
},
|
},
|
||||||
"verification-service": map[string]any{
|
"verification-service": map[string]any{
|
||||||
"csp": i.csp.String(),
|
|
||||||
"image": i.verificationServiceImage,
|
"image": i.verificationServiceImage,
|
||||||
},
|
},
|
||||||
"gcp-guest-agent": map[string]any{
|
"gcp-guest-agent": map[string]any{
|
||||||
@ -491,6 +490,18 @@ func extendConstellationServicesValues(in map[string]any, config *config.Config,
|
|||||||
keyServiceValues["masterSecret"] = base64.StdEncoding.EncodeToString(masterSecret)
|
keyServiceValues["masterSecret"] = base64.StdEncoding.EncodeToString(masterSecret)
|
||||||
keyServiceValues["salt"] = base64.StdEncoding.EncodeToString(salt)
|
keyServiceValues["salt"] = base64.StdEncoding.EncodeToString(salt)
|
||||||
|
|
||||||
|
joinServiceVals, ok := in["join-service"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("invalid join-service values")
|
||||||
|
}
|
||||||
|
joinServiceVals["attestationVariant"] = config.AttestationVariant
|
||||||
|
|
||||||
|
verifyServiceVals, ok := in["verification-service"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("invalid verification-service values")
|
||||||
|
}
|
||||||
|
verifyServiceVals["attestationVariant"] = config.AttestationVariant
|
||||||
|
|
||||||
csp := config.GetProvider()
|
csp := config.GetProvider()
|
||||||
switch csp {
|
switch csp {
|
||||||
case cloudprovider.Azure:
|
case cloudprovider.Azure:
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
|
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -59,25 +60,34 @@ func TestConstellationServices(t *testing.T) {
|
|||||||
cnmImage string
|
cnmImage string
|
||||||
}{
|
}{
|
||||||
"GCP": {
|
"GCP": {
|
||||||
config: &config.Config{Provider: config.ProviderConfig{GCP: &config.GCPConfig{
|
config: &config.Config{
|
||||||
DeployCSIDriver: func() *bool { b := true; return &b }(),
|
AttestationVariant: oid.GCPSEVES{}.String(),
|
||||||
}}},
|
Provider: config.ProviderConfig{GCP: &config.GCPConfig{
|
||||||
|
DeployCSIDriver: toPtr(true),
|
||||||
|
}},
|
||||||
|
},
|
||||||
enforceIDKeyDigest: false,
|
enforceIDKeyDigest: false,
|
||||||
valuesModifier: prepareGCPValues,
|
valuesModifier: prepareGCPValues,
|
||||||
ccmImage: "ccmImageForGCP",
|
ccmImage: "ccmImageForGCP",
|
||||||
},
|
},
|
||||||
"Azure": {
|
"Azure": {
|
||||||
config: &config.Config{Provider: config.ProviderConfig{Azure: &config.AzureConfig{
|
config: &config.Config{
|
||||||
DeployCSIDriver: func() *bool { b := true; return &b }(),
|
AttestationVariant: oid.AzureSEVSNP{}.String(),
|
||||||
EnforceIDKeyDigest: func() *bool { b := true; return &b }(),
|
Provider: config.ProviderConfig{Azure: &config.AzureConfig{
|
||||||
}}},
|
DeployCSIDriver: toPtr(true),
|
||||||
|
EnforceIDKeyDigest: toPtr(true),
|
||||||
|
}},
|
||||||
|
},
|
||||||
enforceIDKeyDigest: true,
|
enforceIDKeyDigest: true,
|
||||||
valuesModifier: prepareAzureValues,
|
valuesModifier: prepareAzureValues,
|
||||||
ccmImage: "ccmImageForAzure",
|
ccmImage: "ccmImageForAzure",
|
||||||
cnmImage: "cnmImageForAzure",
|
cnmImage: "cnmImageForAzure",
|
||||||
},
|
},
|
||||||
"QEMU": {
|
"QEMU": {
|
||||||
config: &config.Config{Provider: config.ProviderConfig{QEMU: &config.QEMUConfig{}}},
|
config: &config.Config{
|
||||||
|
AttestationVariant: oid.QEMUVTPM{}.String(),
|
||||||
|
Provider: config.ProviderConfig{QEMU: &config.QEMUConfig{}},
|
||||||
|
},
|
||||||
enforceIDKeyDigest: false,
|
enforceIDKeyDigest: false,
|
||||||
valuesModifier: prepareQEMUValues,
|
valuesModifier: prepareQEMUValues,
|
||||||
},
|
},
|
||||||
@ -430,3 +440,7 @@ func prepareQEMUValues(values map[string]any) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toPtr[T any](v T) *T {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
@ -39,6 +39,7 @@ spec:
|
|||||||
args:
|
args:
|
||||||
- --cloud-provider=Azure
|
- --cloud-provider=Azure
|
||||||
- --key-service-endpoint=key-service.testNamespace:9000
|
- --key-service-endpoint=key-service.testNamespace:9000
|
||||||
|
- --attestation-variant=azure-sev-snp
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: /var/config
|
- mountPath: /var/config
|
||||||
name: config
|
name: config
|
||||||
|
@ -17,7 +17,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- args:
|
- args:
|
||||||
- --cloud-provider=Azure
|
- --attestation-variant=azure-sev-snp
|
||||||
image: verificationImage
|
image: verificationImage
|
||||||
name: verification-service
|
name: verification-service
|
||||||
ports:
|
ports:
|
||||||
|
@ -39,6 +39,7 @@ spec:
|
|||||||
args:
|
args:
|
||||||
- --cloud-provider=GCP
|
- --cloud-provider=GCP
|
||||||
- --key-service-endpoint=key-service.testNamespace:9000
|
- --key-service-endpoint=key-service.testNamespace:9000
|
||||||
|
- --attestation-variant=gcp-sev-es
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: /var/config
|
- mountPath: /var/config
|
||||||
name: config
|
name: config
|
||||||
|
@ -17,7 +17,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- args:
|
- args:
|
||||||
- --cloud-provider=GCP
|
- --attestation-variant=gcp-sev-es
|
||||||
image: verificationImage
|
image: verificationImage
|
||||||
name: verification-service
|
name: verification-service
|
||||||
ports:
|
ports:
|
||||||
|
@ -39,6 +39,7 @@ spec:
|
|||||||
args:
|
args:
|
||||||
- --cloud-provider=QEMU
|
- --cloud-provider=QEMU
|
||||||
- --key-service-endpoint=key-service.testNamespace:9000
|
- --key-service-endpoint=key-service.testNamespace:9000
|
||||||
|
- --attestation-variant=qemu-vtpm
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: /var/config
|
- mountPath: /var/config
|
||||||
name: config
|
name: config
|
||||||
|
@ -17,7 +17,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- args:
|
- args:
|
||||||
- --cloud-provider=QEMU
|
- --attestation-variant=qemu-vtpm
|
||||||
image: verificationImage
|
image: verificationImage
|
||||||
name: verification-service
|
name: verification-service
|
||||||
ports:
|
ports:
|
||||||
|
@ -22,6 +22,7 @@ go_library(
|
|||||||
"//internal/config/instancetypes",
|
"//internal/config/instancetypes",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
|
"//internal/oid",
|
||||||
"//internal/versions",
|
"//internal/versions",
|
||||||
"//internal/versionsapi",
|
"//internal/versionsapi",
|
||||||
"@com_github_go_playground_locales//en",
|
"@com_github_go_playground_locales//en",
|
||||||
@ -48,6 +49,7 @@ go_test(
|
|||||||
"//internal/config/instancetypes",
|
"//internal/config/instancetypes",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
|
"//internal/oid",
|
||||||
"@com_github_go_playground_locales//en",
|
"@com_github_go_playground_locales//en",
|
||||||
"@com_github_go_playground_universal_translator//:universal-translator",
|
"@com_github_go_playground_universal_translator//:universal-translator",
|
||||||
"@com_github_go_playground_validator_v10//:validator",
|
"@com_github_go_playground_validator_v10//:validator",
|
||||||
|
@ -77,6 +77,9 @@ type Config struct {
|
|||||||
// DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md
|
// DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md
|
||||||
DebugCluster *bool `yaml:"debugCluster" validate:"required"`
|
DebugCluster *bool `yaml:"debugCluster" validate:"required"`
|
||||||
// description: |
|
// description: |
|
||||||
|
// Attestation variant used to verify the integrity of a node.
|
||||||
|
AttestationVariant string `yaml:"attestationVariant" validate:"valid_attestation_variant"` // TODO: v2.8: Mark required
|
||||||
|
// description: |
|
||||||
// Supported cloud providers and their specific configurations.
|
// Supported cloud providers and their specific configurations.
|
||||||
Provider ProviderConfig `yaml:"provider" validate:"dive"`
|
Provider ProviderConfig `yaml:"provider" validate:"dive"`
|
||||||
// description: |
|
// description: |
|
||||||
@ -573,10 +576,15 @@ func (c *Config) Validate(force bool) error {
|
|||||||
if err := validate.RegisterTranslation("version_compatibility", trans, registerVersionCompatibilityError, translateVersionCompatibilityError); err != nil {
|
if err := validate.RegisterTranslation("version_compatibility", trans, registerVersionCompatibilityError, translateVersionCompatibilityError); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validate.RegisterTranslation("valid_name", trans, registerValidateNameError, c.translateValidateNameError); err != nil {
|
if err := validate.RegisterTranslation("valid_name", trans, registerValidateNameError, c.translateValidateNameError); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validate.RegisterTranslation("valid_attestation_variant", trans, registerValidAttestVariantError, c.translateValidAttestVariantError); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := validate.RegisterValidation("valid_name", c.validateName); err != nil {
|
if err := validate.RegisterValidation("valid_name", c.validateName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -613,6 +621,10 @@ func (c *Config) Validate(force bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validate.RegisterValidation("valid_attestation_variant", c.validAttestVariant); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Register provider validation
|
// Register provider validation
|
||||||
validate.RegisterStructValidation(validateProvider, ProviderConfig{})
|
validate.RegisterStructValidation(validateProvider, ProviderConfig{})
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ func init() {
|
|||||||
ConfigDoc.Type = "Config"
|
ConfigDoc.Type = "Config"
|
||||||
ConfigDoc.Comments[encoder.LineComment] = "Config defines configuration used by CLI."
|
ConfigDoc.Comments[encoder.LineComment] = "Config defines configuration used by CLI."
|
||||||
ConfigDoc.Description = "Config defines configuration used by CLI."
|
ConfigDoc.Description = "Config defines configuration used by CLI."
|
||||||
ConfigDoc.Fields = make([]encoder.Doc, 9)
|
ConfigDoc.Fields = make([]encoder.Doc, 10)
|
||||||
ConfigDoc.Fields[0].Name = "version"
|
ConfigDoc.Fields[0].Name = "version"
|
||||||
ConfigDoc.Fields[0].Type = "string"
|
ConfigDoc.Fields[0].Type = "string"
|
||||||
ConfigDoc.Fields[0].Note = ""
|
ConfigDoc.Fields[0].Note = ""
|
||||||
@ -61,18 +61,23 @@ func init() {
|
|||||||
ConfigDoc.Fields[6].Note = ""
|
ConfigDoc.Fields[6].Note = ""
|
||||||
ConfigDoc.Fields[6].Description = "DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md"
|
ConfigDoc.Fields[6].Description = "DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md"
|
||||||
ConfigDoc.Fields[6].Comments[encoder.LineComment] = "DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md"
|
ConfigDoc.Fields[6].Comments[encoder.LineComment] = "DON'T USE IN PRODUCTION: enable debug mode and use debug images. For usage, see: https://github.com/edgelesssys/constellation/blob/main/debugd/README.md"
|
||||||
ConfigDoc.Fields[7].Name = "provider"
|
ConfigDoc.Fields[7].Name = "attestationVariant"
|
||||||
ConfigDoc.Fields[7].Type = "ProviderConfig"
|
ConfigDoc.Fields[7].Type = "string"
|
||||||
ConfigDoc.Fields[7].Note = ""
|
ConfigDoc.Fields[7].Note = "TODO: v2.8: Mark required\n"
|
||||||
ConfigDoc.Fields[7].Description = "Supported cloud providers and their specific configurations."
|
ConfigDoc.Fields[7].Description = "Attestation variant used to verify the integrity of a node."
|
||||||
ConfigDoc.Fields[7].Comments[encoder.LineComment] = "Supported cloud providers and their specific configurations."
|
ConfigDoc.Fields[7].Comments[encoder.LineComment] = "Attestation variant used to verify the integrity of a node."
|
||||||
ConfigDoc.Fields[8].Name = "upgrade"
|
ConfigDoc.Fields[8].Name = "provider"
|
||||||
ConfigDoc.Fields[8].Type = "UpgradeConfig"
|
ConfigDoc.Fields[8].Type = "ProviderConfig"
|
||||||
ConfigDoc.Fields[8].Note = ""
|
ConfigDoc.Fields[8].Note = ""
|
||||||
ConfigDoc.Fields[8].Description = "Configuration to apply during constellation upgrade."
|
ConfigDoc.Fields[8].Description = "Supported cloud providers and their specific configurations."
|
||||||
ConfigDoc.Fields[8].Comments[encoder.LineComment] = "Configuration to apply during constellation upgrade."
|
ConfigDoc.Fields[8].Comments[encoder.LineComment] = "Supported cloud providers and their specific configurations."
|
||||||
|
ConfigDoc.Fields[9].Name = "upgrade"
|
||||||
|
ConfigDoc.Fields[9].Type = "UpgradeConfig"
|
||||||
|
ConfigDoc.Fields[9].Note = ""
|
||||||
|
ConfigDoc.Fields[9].Description = "Configuration to apply during constellation upgrade."
|
||||||
|
ConfigDoc.Fields[9].Comments[encoder.LineComment] = "Configuration to apply during constellation upgrade."
|
||||||
|
|
||||||
ConfigDoc.Fields[8].AddExample("", UpgradeConfig{Image: "", Measurements: Measurements{}})
|
ConfigDoc.Fields[9].AddExample("", UpgradeConfig{Image: "", Measurements: Measurements{}})
|
||||||
|
|
||||||
UpgradeConfigDoc.Type = "UpgradeConfig"
|
UpgradeConfigDoc.Type = "UpgradeConfig"
|
||||||
UpgradeConfigDoc.Comments[encoder.LineComment] = "UpgradeConfig defines configuration used during constellation upgrade."
|
UpgradeConfigDoc.Comments[encoder.LineComment] = "UpgradeConfig defines configuration used during constellation upgrade."
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/go-playground/locales/en"
|
"github.com/go-playground/locales/en"
|
||||||
ut "github.com/go-playground/universal-translator"
|
ut "github.com/go-playground/universal-translator"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
@ -122,6 +123,7 @@ func TestNewWithDefaultOptions(t *testing.T) {
|
|||||||
c := Default()
|
c := Default()
|
||||||
c.RemoveProviderExcept(cloudprovider.Azure)
|
c.RemoveProviderExcept(cloudprovider.Azure)
|
||||||
c.Image = "v" + constants.VersionInfo()
|
c.Image = "v" + constants.VersionInfo()
|
||||||
|
c.AttestationVariant = oid.AzureSEVSNP{}.String()
|
||||||
c.Provider.Azure.SubscriptionID = "f4278079-288c-4766-a98c-ab9d5dba01a5"
|
c.Provider.Azure.SubscriptionID = "f4278079-288c-4766-a98c-ab9d5dba01a5"
|
||||||
c.Provider.Azure.TenantID = "d4ff9d63-6d6d-4042-8f6a-21e804add5aa"
|
c.Provider.Azure.TenantID = "d4ff9d63-6d6d-4042-8f6a-21e804add5aa"
|
||||||
c.Provider.Azure.Location = "westus"
|
c.Provider.Azure.Location = "westus"
|
||||||
@ -141,6 +143,7 @@ func TestNewWithDefaultOptions(t *testing.T) {
|
|||||||
c := Default()
|
c := Default()
|
||||||
c.RemoveProviderExcept(cloudprovider.Azure)
|
c.RemoveProviderExcept(cloudprovider.Azure)
|
||||||
c.Image = "v" + constants.VersionInfo()
|
c.Image = "v" + constants.VersionInfo()
|
||||||
|
c.AttestationVariant = oid.AzureSEVSNP{}.String()
|
||||||
c.Provider.Azure.SubscriptionID = "f4278079-288c-4766-a98c-ab9d5dba01a5"
|
c.Provider.Azure.SubscriptionID = "f4278079-288c-4766-a98c-ab9d5dba01a5"
|
||||||
c.Provider.Azure.TenantID = "d4ff9d63-6d6d-4042-8f6a-21e804add5aa"
|
c.Provider.Azure.TenantID = "d4ff9d63-6d6d-4042-8f6a-21e804add5aa"
|
||||||
c.Provider.Azure.Location = "westus"
|
c.Provider.Azure.Location = "westus"
|
||||||
@ -232,6 +235,7 @@ func TestValidate(t *testing.T) {
|
|||||||
cnf: func() *Config {
|
cnf: func() *Config {
|
||||||
cnf := Default()
|
cnf := Default()
|
||||||
cnf.Image = "v" + constants.VersionInfo()
|
cnf.Image = "v" + constants.VersionInfo()
|
||||||
|
cnf.AttestationVariant = oid.AzureSEVSNP{}.String()
|
||||||
az := cnf.Provider.Azure
|
az := cnf.Provider.Azure
|
||||||
az.SubscriptionID = "01234567-0123-0123-0123-0123456789ab"
|
az.SubscriptionID = "01234567-0123-0123-0123-0123456789ab"
|
||||||
az.TenantID = "01234567-0123-0123-0123-0123456789ab"
|
az.TenantID = "01234567-0123-0123-0123-0123456789ab"
|
||||||
@ -261,6 +265,7 @@ func TestValidate(t *testing.T) {
|
|||||||
cnf: func() *Config {
|
cnf: func() *Config {
|
||||||
cnf := Default()
|
cnf := Default()
|
||||||
cnf.Image = "v" + constants.VersionInfo()
|
cnf.Image = "v" + constants.VersionInfo()
|
||||||
|
cnf.AttestationVariant = oid.GCPSEVES{}.String()
|
||||||
gcp := cnf.Provider.GCP
|
gcp := cnf.Provider.GCP
|
||||||
gcp.Region = "test-region"
|
gcp.Region = "test-region"
|
||||||
gcp.Project = "test-project"
|
gcp.Project = "test-project"
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versionsapi"
|
"github.com/edgelesssys/constellation/v2/internal/versionsapi"
|
||||||
ut "github.com/go-playground/universal-translator"
|
ut "github.com/go-playground/universal-translator"
|
||||||
@ -466,3 +467,55 @@ func (c *Config) validateName(fl validator.FieldLevel) bool {
|
|||||||
}
|
}
|
||||||
return len(fl.Field().String()) <= constants.ConstellationNameLength
|
return len(fl.Field().String()) <= constants.ConstellationNameLength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerValidAttestVariantError(ut ut.Translator) error {
|
||||||
|
return ut.Add("valid_attestation_variant", `"{0}" is not a valid attestation variant for CSP {1}`, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) translateValidAttestVariantError(ut ut.Translator, fe validator.FieldError) string {
|
||||||
|
csp := c.GetProvider()
|
||||||
|
t, _ := ut.T("valid_attestation_variant", c.AttestationVariant, csp.String())
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) validAttestVariant(fl validator.FieldLevel) bool {
|
||||||
|
// TODO: v2.8: remove variant fallback and make variant a required field
|
||||||
|
c.addMissingVariant()
|
||||||
|
|
||||||
|
variant, err := oid.FromString(c.AttestationVariant)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the variant is valid for the chosen CSP
|
||||||
|
switch variant {
|
||||||
|
case oid.AWSNitroTPM{}:
|
||||||
|
return c.Provider.AWS != nil
|
||||||
|
case oid.AzureSEVSNP{}, oid.AzureTrustedLaunch{}:
|
||||||
|
return c.Provider.Azure != nil
|
||||||
|
case oid.GCPSEVES{}:
|
||||||
|
return c.Provider.GCP != nil
|
||||||
|
case oid.QEMUVTPM{}:
|
||||||
|
return c.Provider.QEMU != nil
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) addMissingVariant() {
|
||||||
|
if c.AttestationVariant != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintln(os.Stderr, "WARNING: the config key `attestationVariant` is not set. This key will be required in the next version.")
|
||||||
|
|
||||||
|
switch c.GetProvider() {
|
||||||
|
case cloudprovider.AWS:
|
||||||
|
c.AttestationVariant = oid.AWSNitroTPM{}.String()
|
||||||
|
case cloudprovider.Azure:
|
||||||
|
c.AttestationVariant = oid.AzureTrustedLaunch{}.String()
|
||||||
|
case cloudprovider.GCP:
|
||||||
|
c.AttestationVariant = oid.GCPSEVES{}.String()
|
||||||
|
case cloudprovider.QEMU:
|
||||||
|
c.AttestationVariant = oid.QEMUVTPM{}.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -108,8 +108,6 @@ const (
|
|||||||
ServiceBasePath = "/var/config"
|
ServiceBasePath = "/var/config"
|
||||||
// MeasurementsFilename is the filename of CC measurements.
|
// MeasurementsFilename is the filename of CC measurements.
|
||||||
MeasurementsFilename = "measurements"
|
MeasurementsFilename = "measurements"
|
||||||
// EnforcedPCRsFilename is the filename for a list PCRs that are required to pass attestation.
|
|
||||||
EnforcedPCRsFilename = "enforcedPCRs"
|
|
||||||
// MeasurementSaltFilename is the filename of the salt used in creation of the clusterID.
|
// MeasurementSaltFilename is the filename of the salt used in creation of the clusterID.
|
||||||
MeasurementSaltFilename = "measurementSalt"
|
MeasurementSaltFilename = "measurementSalt"
|
||||||
// MeasurementSecretFilename is the filename of the secret used in creation of the clusterID.
|
// MeasurementSecretFilename is the filename of the secret used in creation of the clusterID.
|
||||||
@ -118,8 +116,6 @@ const (
|
|||||||
IDKeyDigestFilename = "idkeydigests"
|
IDKeyDigestFilename = "idkeydigests"
|
||||||
// EnforceIDKeyDigestFilename is the name of the file configuring whether idkeydigest is enforced or not.
|
// EnforceIDKeyDigestFilename is the name of the file configuring whether idkeydigest is enforced or not.
|
||||||
EnforceIDKeyDigestFilename = "enforceIdKeyDigest"
|
EnforceIDKeyDigestFilename = "enforceIdKeyDigest"
|
||||||
// AzureCVM is the name of the file indicating whether the cluster is expected to run on CVMs or not.
|
|
||||||
AzureCVM = "azureCVM"
|
|
||||||
|
|
||||||
// K8sVersionFieldName is the name of the of the key holding the wanted Kubernetes version.
|
// K8sVersionFieldName is the name of the of the key holding the wanted Kubernetes version.
|
||||||
K8sVersionFieldName = "cluster-version"
|
K8sVersionFieldName = "cluster-version"
|
||||||
|
@ -11,17 +11,13 @@ go_library(
|
|||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/atls",
|
"//internal/atls",
|
||||||
"//internal/attestation/aws",
|
"//internal/attestation/choose",
|
||||||
"//internal/attestation/azure/snp",
|
|
||||||
"//internal/attestation/azure/trustedlaunch",
|
|
||||||
"//internal/attestation/gcp",
|
|
||||||
"//internal/attestation/idkeydigest",
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/attestation/qemu",
|
|
||||||
"//internal/cloud/cloudprovider",
|
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/oid",
|
||||||
"@com_github_fsnotify_fsnotify//:fsnotify",
|
"@com_github_fsnotify_fsnotify//:fsnotify",
|
||||||
"@org_uber_go_zap//:zap",
|
"@org_uber_go_zap//:zap",
|
||||||
],
|
],
|
||||||
@ -38,9 +34,11 @@ go_test(
|
|||||||
"//internal/atls",
|
"//internal/atls",
|
||||||
"//internal/attestation/idkeydigest",
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/oid",
|
||||||
"@com_github_fsnotify_fsnotify//:fsnotify",
|
"@com_github_fsnotify_fsnotify//:fsnotify",
|
||||||
"@com_github_spf13_afero//:afero",
|
"@com_github_spf13_afero//:afero",
|
||||||
"@com_github_stretchr_testify//assert",
|
"@com_github_stretchr_testify//assert",
|
||||||
|
@ -9,74 +9,36 @@ package watcher
|
|||||||
import (
|
import (
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/aws"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
|
||||||
"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/idkeydigest"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/qemu"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Updatable implements an updatable atls.Validator.
|
// Updatable implements an updatable atls.Validator.
|
||||||
type Updatable struct {
|
type Updatable struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
mux sync.Mutex
|
mux sync.Mutex
|
||||||
newValidator newValidatorFunc
|
fileHandler file.Handler
|
||||||
fileHandler file.Handler
|
variant oid.Getter
|
||||||
csp cloudprovider.Provider
|
|
||||||
azureCVM bool
|
|
||||||
atls.Validator
|
atls.Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidator initializes a new updatable validator.
|
// NewValidator initializes a new updatable validator.
|
||||||
func NewValidator(log *logger.Logger, csp string, fileHandler file.Handler, azureCVM bool) (*Updatable, error) {
|
func NewValidator(log *logger.Logger, variant oid.Getter, fileHandler file.Handler) (*Updatable, error) {
|
||||||
var newValidator newValidatorFunc
|
|
||||||
switch cloudprovider.FromString(csp) {
|
|
||||||
case cloudprovider.AWS:
|
|
||||||
newValidator = func(m measurements.M, _ idkeydigest.IDKeyDigests, _ bool, log *logger.Logger) atls.Validator {
|
|
||||||
return aws.NewValidator(m, log)
|
|
||||||
}
|
|
||||||
case cloudprovider.Azure:
|
|
||||||
if azureCVM {
|
|
||||||
newValidator = func(m measurements.M, idkeydigest idkeydigest.IDKeyDigests, enforceIdKeyDigest bool, log *logger.Logger) atls.Validator {
|
|
||||||
return snp.NewValidator(m, idkeydigest, enforceIdKeyDigest, log)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newValidator = func(m measurements.M, idkeydigest idkeydigest.IDKeyDigests, enforceIdKeyDigest bool, log *logger.Logger) atls.Validator {
|
|
||||||
return trustedlaunch.NewValidator(m, log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case cloudprovider.GCP:
|
|
||||||
newValidator = func(m measurements.M, _ idkeydigest.IDKeyDigests, _ bool, log *logger.Logger) atls.Validator {
|
|
||||||
return gcp.NewValidator(m, log)
|
|
||||||
}
|
|
||||||
case cloudprovider.QEMU:
|
|
||||||
newValidator = func(m measurements.M, _ idkeydigest.IDKeyDigests, _ bool, log *logger.Logger) atls.Validator {
|
|
||||||
return qemu.NewValidator(m, log)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown cloud service provider: %q", csp)
|
|
||||||
}
|
|
||||||
|
|
||||||
u := &Updatable{
|
u := &Updatable{
|
||||||
log: log,
|
log: log,
|
||||||
newValidator: newValidator,
|
fileHandler: fileHandler,
|
||||||
fileHandler: fileHandler,
|
variant: variant,
|
||||||
csp: cloudprovider.FromString(csp),
|
|
||||||
azureCVM: azureCVM,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := u.Update(); err != nil {
|
if err := u.Update(); err != nil {
|
||||||
@ -112,22 +74,9 @@ func (u *Updatable) Update() error {
|
|||||||
}
|
}
|
||||||
u.log.Debugf("New measurements: %+v", measurements)
|
u.log.Debugf("New measurements: %+v", measurements)
|
||||||
|
|
||||||
// handle legacy measurement format, where expected measurements and enforced measurements were stored in separate data structures
|
|
||||||
// TODO: remove with v2.4.0
|
|
||||||
var enforced []uint32
|
|
||||||
if err := u.fileHandler.ReadJSON(filepath.Join(constants.ServiceBasePath, constants.EnforcedPCRsFilename), &enforced); err == nil {
|
|
||||||
u.log.Debugf("Detected legacy format. Loading enforced PCRs...")
|
|
||||||
if err := measurements.SetEnforced(enforced); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
u.log.Debugf("Merged measurements with enforced values: %+v", measurements)
|
|
||||||
} else if !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var digest idkeydigest.IDKeyDigests
|
var digest idkeydigest.IDKeyDigests
|
||||||
var enforceIDKeyDigest bool
|
var enforceIDKeyDigest bool
|
||||||
if u.csp == cloudprovider.Azure && u.azureCVM {
|
if u.variant.OID().Equal(oid.AzureSEVSNP{}.OID()) {
|
||||||
u.log.Infof("Updating encforceIdKeyDigest value")
|
u.log.Infof("Updating encforceIdKeyDigest value")
|
||||||
enforceRaw, err := u.fileHandler.Read(filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename))
|
enforceRaw, err := u.fileHandler.Read(filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -150,9 +99,11 @@ func (u *Updatable) Update() error {
|
|||||||
u.log.Debugf("New idkeydigest: %v", digest)
|
u.log.Debugf("New idkeydigest: %v", digest)
|
||||||
}
|
}
|
||||||
|
|
||||||
u.Validator = u.newValidator(measurements, digest, enforceIDKeyDigest, u.log)
|
validator, err := choose.Validator(u.variant, measurements, digest, enforceIDKeyDigest, u.log)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("updating validator: %w", err)
|
||||||
|
}
|
||||||
|
u.Validator = validator
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type newValidatorFunc func(measurements measurements.M, idkeydigest idkeydigest.IDKeyDigests, enforceIdKeyDigest bool, log *logger.Logger) atls.Validator
|
|
||||||
|
@ -7,11 +7,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
package watcher
|
package watcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@ -22,9 +20,11 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -40,29 +40,29 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
func TestNewUpdateableValidator(t *testing.T) {
|
func TestNewUpdateableValidator(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
provider string
|
variant oid.Getter
|
||||||
writeFile bool
|
writeFile bool
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"azure": {
|
"azure": {
|
||||||
provider: "azure",
|
variant: oid.AzureSEVSNP{},
|
||||||
writeFile: true,
|
writeFile: true,
|
||||||
},
|
},
|
||||||
"gcp": {
|
"gcp": {
|
||||||
provider: "gcp",
|
variant: oid.GCPSEVES{},
|
||||||
writeFile: true,
|
writeFile: true,
|
||||||
},
|
},
|
||||||
"qemu": {
|
"qemu": {
|
||||||
provider: "qemu",
|
variant: oid.QEMUVTPM{},
|
||||||
writeFile: true,
|
writeFile: true,
|
||||||
},
|
},
|
||||||
"no file": {
|
"no file": {
|
||||||
provider: "azure",
|
variant: oid.AzureSEVSNP{},
|
||||||
writeFile: false,
|
writeFile: false,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"invalid provider": {
|
"invalid provider": {
|
||||||
provider: "invalid",
|
variant: fakeOID{1, 3, 9900, 9999, 9999},
|
||||||
writeFile: true,
|
writeFile: true,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
@ -77,33 +77,24 @@ func TestNewUpdateableValidator(t *testing.T) {
|
|||||||
if tc.writeFile {
|
if tc.writeFile {
|
||||||
require.NoError(handler.WriteJSON(
|
require.NoError(handler.WriteJSON(
|
||||||
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
||||||
map[uint32][]byte{
|
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
||||||
11: {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
|
||||||
},
|
|
||||||
))
|
|
||||||
require.NoError(handler.WriteJSON(
|
|
||||||
filepath.Join(constants.ServiceBasePath, constants.EnforcedPCRsFilename),
|
|
||||||
[]uint32{11},
|
|
||||||
))
|
))
|
||||||
|
keyDigest, err := json.Marshal(idkeydigest.DefaultsFor(cloudprovider.Azure))
|
||||||
|
require.NoError(err)
|
||||||
require.NoError(handler.Write(
|
require.NoError(handler.Write(
|
||||||
filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename),
|
filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename),
|
||||||
[]byte{},
|
keyDigest,
|
||||||
))
|
))
|
||||||
require.NoError(handler.Write(
|
require.NoError(handler.Write(
|
||||||
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
||||||
[]byte("false"),
|
[]byte("false"),
|
||||||
))
|
))
|
||||||
require.NoError(handler.Write(
|
|
||||||
filepath.Join(constants.ServiceBasePath, constants.AzureCVM),
|
|
||||||
[]byte("true"),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := NewValidator(
|
_, err := NewValidator(
|
||||||
logger.NewTest(t),
|
logger.NewTest(t),
|
||||||
tc.provider,
|
tc.variant,
|
||||||
handler,
|
handler,
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
@ -118,26 +109,13 @@ func TestUpdate(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
// we need safe access for overwriting the fake validator OID
|
|
||||||
oid := fakeOID{1, 3, 9900, 1}
|
|
||||||
var oidLock sync.Mutex
|
|
||||||
updatedOID := func(newOID fakeOID) {
|
|
||||||
oidLock.Lock()
|
|
||||||
defer oidLock.Unlock()
|
|
||||||
oid = newOID
|
|
||||||
}
|
|
||||||
newValidator := func(m measurements.M, digest idkeydigest.IDKeyDigests, enforceIdKeyDigest bool, _ *logger.Logger) atls.Validator {
|
|
||||||
oidLock.Lock()
|
|
||||||
defer oidLock.Unlock()
|
|
||||||
return fakeValidator{fakeOID: oid}
|
|
||||||
}
|
|
||||||
handler := file.NewHandler(afero.NewMemMapFs())
|
handler := file.NewHandler(afero.NewMemMapFs())
|
||||||
|
|
||||||
// create server
|
// create server
|
||||||
validator := &Updatable{
|
validator := &Updatable{
|
||||||
log: logger.NewTest(t),
|
log: logger.NewTest(t),
|
||||||
newValidator: newValidator,
|
variant: oid.Dummy{},
|
||||||
fileHandler: handler,
|
fileHandler: handler,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update should fail if the file does not exist
|
// Update should fail if the file does not exist
|
||||||
@ -156,10 +134,6 @@ func TestUpdate(t *testing.T) {
|
|||||||
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
||||||
[]byte("false"),
|
[]byte("false"),
|
||||||
))
|
))
|
||||||
require.NoError(handler.Write(
|
|
||||||
filepath.Join(constants.ServiceBasePath, constants.AzureCVM),
|
|
||||||
[]byte("true"),
|
|
||||||
))
|
|
||||||
|
|
||||||
// call update once to initialize the server's validator
|
// call update once to initialize the server's validator
|
||||||
require.NoError(validator.Update())
|
require.NoError(validator.Update())
|
||||||
@ -175,7 +149,7 @@ func TestUpdate(t *testing.T) {
|
|||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
// test connection to server
|
// test connection to server
|
||||||
clientOID := fakeOID{1, 3, 9900, 1}
|
clientOID := oid.Dummy{}
|
||||||
resp, err := testConnection(require, server.URL, clientOID)
|
resp, err := testConnection(require, server.URL, clientOID)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -184,7 +158,7 @@ func TestUpdate(t *testing.T) {
|
|||||||
assert.EqualValues("hello", body)
|
assert.EqualValues("hello", body)
|
||||||
|
|
||||||
// update the server's validator
|
// update the server's validator
|
||||||
updatedOID(fakeOID{1, 3, 9900, 2})
|
validator.variant = oid.QEMUVTPM{}
|
||||||
require.NoError(validator.Update())
|
require.NoError(validator.Update())
|
||||||
|
|
||||||
// client connection should fail now, since the server's validator expects a different OID from the client
|
// client connection should fail now, since the server's validator expects a different OID from the client
|
||||||
@ -193,23 +167,6 @@ func TestUpdate(t *testing.T) {
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
}
|
}
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
|
|
||||||
// update should work for legacy measurement format
|
|
||||||
// TODO: remove with v2.4.0
|
|
||||||
require.NoError(handler.WriteJSON(
|
|
||||||
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
|
||||||
map[uint32][]byte{
|
|
||||||
11: bytes.Repeat([]byte{0x0}, 32),
|
|
||||||
12: bytes.Repeat([]byte{0x1}, 32),
|
|
||||||
},
|
|
||||||
file.OptOverwrite,
|
|
||||||
))
|
|
||||||
require.NoError(handler.WriteJSON(
|
|
||||||
filepath.Join(constants.ServiceBasePath, constants.EnforcedPCRsFilename),
|
|
||||||
[]uint32{11},
|
|
||||||
))
|
|
||||||
|
|
||||||
assert.NoError(validator.Update())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOIDConcurrency(t *testing.T) {
|
func TestOIDConcurrency(t *testing.T) {
|
||||||
@ -226,14 +183,11 @@ func TestOIDConcurrency(t *testing.T) {
|
|||||||
[]byte{},
|
[]byte{},
|
||||||
))
|
))
|
||||||
|
|
||||||
newValidator := func(m measurements.M, digest idkeydigest.IDKeyDigests, enforceIdKeyDigest bool, _ *logger.Logger) atls.Validator {
|
|
||||||
return fakeValidator{fakeOID: fakeOID{1, 3, 9900, 1}}
|
|
||||||
}
|
|
||||||
// create server
|
// create server
|
||||||
validator := &Updatable{
|
validator := &Updatable{
|
||||||
log: logger.NewTest(t),
|
log: logger.NewTest(t),
|
||||||
newValidator: newValidator,
|
variant: oid.Dummy{},
|
||||||
fileHandler: handler,
|
fileHandler: handler,
|
||||||
}
|
}
|
||||||
|
|
||||||
// call update once to initialize the server's validator
|
// call update once to initialize the server's validator
|
||||||
@ -262,21 +216,13 @@ func TestUpdateConcurrency(t *testing.T) {
|
|||||||
validator := &Updatable{
|
validator := &Updatable{
|
||||||
log: logger.NewTest(t),
|
log: logger.NewTest(t),
|
||||||
fileHandler: handler,
|
fileHandler: handler,
|
||||||
newValidator: func(m measurements.M, digest idkeydigest.IDKeyDigests, enforceIdKeyDigest bool, _ *logger.Logger) atls.Validator {
|
variant: oid.Dummy{},
|
||||||
return fakeValidator{fakeOID: fakeOID{1, 3, 9900, 1}}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
require.NoError(handler.WriteJSON(
|
require.NoError(handler.WriteJSON(
|
||||||
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
||||||
map[uint32][]byte{
|
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
||||||
11: {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
|
||||||
},
|
|
||||||
file.OptNone,
|
file.OptNone,
|
||||||
))
|
))
|
||||||
require.NoError(handler.WriteJSON(
|
|
||||||
filepath.Join(constants.ServiceBasePath, constants.EnforcedPCRsFilename),
|
|
||||||
[]uint32{11},
|
|
||||||
))
|
|
||||||
require.NoError(handler.Write(
|
require.NoError(handler.Write(
|
||||||
filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename),
|
filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename),
|
||||||
[]byte{},
|
[]byte{},
|
||||||
@ -285,10 +231,6 @@ func TestUpdateConcurrency(t *testing.T) {
|
|||||||
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
||||||
[]byte("false"),
|
[]byte("false"),
|
||||||
))
|
))
|
||||||
require.NoError(handler.Write(
|
|
||||||
filepath.Join(constants.ServiceBasePath, constants.AzureCVM),
|
|
||||||
[]byte("true"),
|
|
||||||
))
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
@ -303,8 +245,8 @@ func TestUpdateConcurrency(t *testing.T) {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testConnection(require *require.Assertions, url string, oid fakeOID) (*http.Response, error) {
|
func testConnection(require *require.Assertions, url string, oid oid.Getter) (*http.Response, error) {
|
||||||
clientConfig, err := atls.CreateAttestationClientTLSConfig(fakeIssuer{fakeOID: oid}, nil)
|
clientConfig, err := atls.CreateAttestationClientTLSConfig(fakeIssuer{oid}, nil)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
client := http.Client{Transport: &http.Transport{TLSClientConfig: clientConfig}}
|
client := http.Client{Transport: &http.Transport{TLSClientConfig: clientConfig}}
|
||||||
|
|
||||||
@ -314,29 +256,13 @@ func testConnection(require *require.Assertions, url string, oid fakeOID) (*http
|
|||||||
}
|
}
|
||||||
|
|
||||||
type fakeIssuer struct {
|
type fakeIssuer struct {
|
||||||
fakeOID
|
oid.Getter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeIssuer) Issue(userData []byte, nonce []byte) ([]byte, error) {
|
func (fakeIssuer) Issue(userData []byte, nonce []byte) ([]byte, error) {
|
||||||
return json.Marshal(fakeDoc{UserData: userData, Nonce: nonce})
|
return json.Marshal(fakeDoc{UserData: userData, Nonce: nonce})
|
||||||
}
|
}
|
||||||
|
|
||||||
type fakeValidator struct {
|
|
||||||
fakeOID
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v fakeValidator) Validate(attDoc []byte, nonce []byte) ([]byte, error) {
|
|
||||||
var doc fakeDoc
|
|
||||||
if err := json.Unmarshal(attDoc, &doc); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !bytes.Equal(doc.Nonce, nonce) {
|
|
||||||
return nil, errors.New("invalid nonce")
|
|
||||||
}
|
|
||||||
return doc.UserData, v.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type fakeOID asn1.ObjectIdentifier
|
type fakeOID asn1.ObjectIdentifier
|
||||||
|
|
||||||
func (o fakeOID) OID() asn1.ObjectIdentifier {
|
func (o fakeOID) OID() asn1.ObjectIdentifier {
|
||||||
|
@ -18,6 +18,7 @@ go_library(
|
|||||||
"//internal/file",
|
"//internal/file",
|
||||||
"//internal/grpc/atlscredentials",
|
"//internal/grpc/atlscredentials",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/oid",
|
||||||
"//internal/watcher",
|
"//internal/watcher",
|
||||||
"//joinservice/internal/kms",
|
"//joinservice/internal/kms",
|
||||||
"//joinservice/internal/kubeadm",
|
"//joinservice/internal/kubeadm",
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/grpc/atlscredentials"
|
"github.com/edgelesssys/constellation/v2/internal/grpc/atlscredentials"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/watcher"
|
"github.com/edgelesssys/constellation/v2/internal/watcher"
|
||||||
"github.com/edgelesssys/constellation/v2/joinservice/internal/kms"
|
"github.com/edgelesssys/constellation/v2/joinservice/internal/kms"
|
||||||
"github.com/edgelesssys/constellation/v2/joinservice/internal/kubeadm"
|
"github.com/edgelesssys/constellation/v2/joinservice/internal/kubeadm"
|
||||||
@ -42,25 +43,24 @@ const vpcIPTimeout = 30 * time.Second
|
|||||||
func main() {
|
func main() {
|
||||||
provider := flag.String("cloud-provider", "", "cloud service provider this binary is running on")
|
provider := flag.String("cloud-provider", "", "cloud service provider this binary is running on")
|
||||||
keyServiceEndpoint := flag.String("key-service-endpoint", "", "endpoint of Constellations key management service")
|
keyServiceEndpoint := flag.String("key-service-endpoint", "", "endpoint of Constellations key management service")
|
||||||
|
attestationVariant := flag.String("attestation-variant", "", "attestation variant to use for aTLS connections")
|
||||||
verbosity := flag.Int("v", 0, logger.CmdLineVerbosityDescription)
|
verbosity := flag.Int("v", 0, logger.CmdLineVerbosityDescription)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
||||||
log.With(zap.String("version", constants.VersionInfo()), zap.String("cloudProvider", *provider)).
|
log.With(
|
||||||
Infof("Constellation Node Join Service")
|
zap.String("version", constants.VersionInfo()),
|
||||||
|
zap.String("cloudProvider", *provider),
|
||||||
|
zap.String("attestationVariant", *attestationVariant),
|
||||||
|
).Infof("Constellation Node Join Service")
|
||||||
|
|
||||||
handler := file.NewHandler(afero.NewOsFs())
|
handler := file.NewHandler(afero.NewOsFs())
|
||||||
|
|
||||||
cvmRaw, err := handler.Read(filepath.Join(constants.ServiceBasePath, constants.AzureCVM))
|
variant, err := oid.FromString(*attestationVariant)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.With(zap.Error(err)).Fatalf("Failed to get azureCVM from config map")
|
log.With(zap.Error(err)).Fatalf("Failed to parse attestation variant")
|
||||||
}
|
}
|
||||||
azureCVM, err := strconv.ParseBool(string(cvmRaw))
|
validator, err := watcher.NewValidator(log.Named("validator"), variant, handler)
|
||||||
if err != nil {
|
|
||||||
log.With(zap.Error(err)).Fatalf("Failed to parse content of AzureCVM: %s", cvmRaw)
|
|
||||||
}
|
|
||||||
|
|
||||||
validator, err := watcher.NewValidator(log.Named("validator"), *provider, handler, azureCVM)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
log.With(zap.Error(err)).Fatalf("Failed to create validator")
|
log.With(zap.Error(err)).Fatalf("Failed to create validator")
|
||||||
|
@ -6,13 +6,10 @@ go_library(
|
|||||||
importpath = "github.com/edgelesssys/constellation/v2/verify/cmd",
|
importpath = "github.com/edgelesssys/constellation/v2/verify/cmd",
|
||||||
visibility = ["//visibility:private"],
|
visibility = ["//visibility:private"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/attestation/aws",
|
"//internal/attestation/choose",
|
||||||
"//internal/attestation/azure/snp",
|
|
||||||
"//internal/attestation/gcp",
|
|
||||||
"//internal/attestation/qemu",
|
|
||||||
"//internal/cloud/cloudprovider",
|
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/oid",
|
||||||
"//verify/server",
|
"//verify/server",
|
||||||
"@org_uber_go_zap//:zap",
|
"@org_uber_go_zap//:zap",
|
||||||
],
|
],
|
||||||
|
@ -11,39 +11,31 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/aws"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/gcp"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/qemu"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/edgelesssys/constellation/v2/verify/server"
|
"github.com/edgelesssys/constellation/v2/verify/server"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
provider := flag.String("cloud-provider", "", "cloud service provider this binary is running on")
|
attestationVariant := flag.String("attestation-variant", "", "attestation variant to use for aTLS connections")
|
||||||
verbosity := flag.Int("v", 0, logger.CmdLineVerbosityDescription)
|
verbosity := flag.Int("v", 0, logger.CmdLineVerbosityDescription)
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
||||||
|
|
||||||
log.With(zap.String("version", constants.VersionInfo()), zap.String("cloudProvider", *provider)).
|
log.With(zap.String("version", constants.VersionInfo()), zap.String("attestationVariant", *attestationVariant)).
|
||||||
Infof("Constellation Verification Service")
|
Infof("Constellation Verification Service")
|
||||||
|
|
||||||
var issuer server.AttestationIssuer
|
variant, err := oid.FromString(*attestationVariant)
|
||||||
switch cloudprovider.FromString(*provider) {
|
if err != nil {
|
||||||
case cloudprovider.AWS:
|
log.With(zap.Error(err)).Fatalf("Failed to parse attestation variant")
|
||||||
issuer = aws.NewIssuer(log)
|
}
|
||||||
case cloudprovider.GCP:
|
issuer, err := choose.Issuer(variant, log.Named("issuer"))
|
||||||
issuer = gcp.NewIssuer(log)
|
if err != nil {
|
||||||
case cloudprovider.Azure:
|
log.With(zap.Error(err)).Fatalf("Failed to create issuer")
|
||||||
issuer = snp.NewIssuer(log) // TODO: dynamic selection
|
|
||||||
case cloudprovider.QEMU:
|
|
||||||
issuer = qemu.NewIssuer(log)
|
|
||||||
default:
|
|
||||||
log.With(zap.String("cloudProvider", *provider)).Fatalf("Unknown cloud provider")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
server := server.New(log.Named("server"), issuer)
|
server := server.New(log.Named("server"), issuer)
|
||||||
|
Loading…
Reference in New Issue
Block a user