image: OpenStack vTPM (#1616)

* cli: allow vpc traffic between nodes on OpenStack
* image: enable vTPM on OpenStack
* cli: add create tests for OpenStack
This commit is contained in:
Malte Poll 2023-04-05 16:49:03 +02:00 committed by GitHub
parent 509b3d5d58
commit 69de06dd1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 151 additions and 41 deletions

View File

@ -13,6 +13,9 @@ import (
"os" "os"
"strconv" "strconv"
"github.com/spf13/afero"
"go.uber.org/zap"
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/helm" "github.com/edgelesssys/constellation/v2/bootstrapper/internal/helm"
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes" "github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes"
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi" "github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi"
@ -32,8 +35,6 @@ import (
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl" "github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
"github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/logger"
"github.com/edgelesssys/constellation/v2/internal/variant" "github.com/edgelesssys/constellation/v2/internal/variant"
"github.com/spf13/afero"
"go.uber.org/zap"
) )
const ( const (
@ -161,8 +162,7 @@ func main() {
) )
metadataAPI = metadata metadataAPI = metadata
// TODO(malt3): add OpenStack TPM support openTPM = vtpm.OpenVTPM
openTPM = vtpm.OpenNOPTPM
fs = afero.NewOsFs() fs = afero.NewOsFs()
default: default:
clusterInitJoiner = &clusterFake{} clusterInitJoiner = &clusterFake{}

View File

@ -23,6 +23,7 @@ import (
"github.com/Azure/azure-sdk-for-go/profiles/latest/attestation/attestation" "github.com/Azure/azure-sdk-for-go/profiles/latest/attestation/attestation"
azpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" azpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid" "github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
"github.com/edgelesssys/constellation/v2/cli/internal/image" "github.com/edgelesssys/constellation/v2/cli/internal/image"
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt" "github.com/edgelesssys/constellation/v2/cli/internal/libvirt"

View File

@ -13,14 +13,17 @@ import (
"runtime" "runtime"
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/cli/internal/terraform"
"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/variant" "github.com/edgelesssys/constellation/v2/internal/variant"
"github.com/stretchr/testify/assert"
) )
func TestCreator(t *testing.T) { func TestCreator(t *testing.T) {
// TODO(malt3): remove once OpenStack is fully supported.
t.Setenv("CONSTELLATION_OPENSTACK_DEV", "1")
failOnNonAMD64 := (runtime.GOARCH != "amd64") || (runtime.GOOS != "linux") failOnNonAMD64 := (runtime.GOARCH != "amd64") || (runtime.GOOS != "linux")
ip := "192.0.2.1" ip := "192.0.2.1"
someErr := errors.New("failed") someErr := errors.New("failed")
@ -110,6 +113,47 @@ func TestCreator(t *testing.T) {
wantRollback: true, wantRollback: true,
wantTerraformRollback: true, wantTerraformRollback: true,
}, },
"openstack": {
tfClient: &stubTerraformClient{ip: ip},
libvirt: &stubLibvirtRunner{},
provider: cloudprovider.OpenStack,
config: func() *config.Config {
cfg := config.Default()
cfg.Provider.OpenStack.Cloud = "testcloud"
return cfg
}(),
},
"openstack without clouds.yaml": {
tfClient: &stubTerraformClient{ip: ip},
libvirt: &stubLibvirtRunner{},
provider: cloudprovider.OpenStack,
config: config.Default(),
wantErr: true,
},
"openstack newTerraformClient error": {
newTfClientErr: someErr,
libvirt: &stubLibvirtRunner{},
provider: cloudprovider.OpenStack,
config: func() *config.Config {
cfg := config.Default()
cfg.Provider.OpenStack.Cloud = "testcloud"
return cfg
}(),
wantErr: true,
},
"openstack create cluster error": {
tfClient: &stubTerraformClient{createClusterErr: someErr},
libvirt: &stubLibvirtRunner{},
provider: cloudprovider.OpenStack,
config: func() *config.Config {
cfg := config.Default()
cfg.Provider.OpenStack.Cloud = "testcloud"
return cfg
}(),
wantErr: true,
wantRollback: true,
wantTerraformRollback: true,
},
"qemu": { "qemu": {
tfClient: &stubTerraformClient{ip: ip}, tfClient: &stubTerraformClient{ip: ip},
libvirt: &stubLibvirtRunner{}, libvirt: &stubLibvirtRunner{},
@ -152,7 +196,6 @@ func TestCreator(t *testing.T) {
for name, tc := range testCases { for name, tc := range testCases {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
creator := &Creator{ creator := &Creator{
out: &bytes.Buffer{}, out: &bytes.Buffer{},
image: &stubImageFetcher{ image: &stubImageFetcher{

View File

@ -12,6 +12,10 @@ import (
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/edgelesssys/constellation/v2/internal/atls" "github.com/edgelesssys/constellation/v2/internal/atls"
"github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp" "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/azure/trustedlaunch"
@ -22,9 +26,6 @@ import (
"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/variant" "github.com/edgelesssys/constellation/v2/internal/variant"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestNewValidator(t *testing.T) { func TestNewValidator(t *testing.T) {
@ -71,6 +72,16 @@ func TestNewValidator(t *testing.T) {
}, },
}, },
}, },
"openstack": {
config: &config.Config{
AttestationVariant: variant.QEMUVTPM{}.String(),
Provider: config.ProviderConfig{
OpenStack: &config.OpenStackConfig{
Measurements: testPCRs,
},
},
},
},
"qemu": { "qemu": {
config: &config.Config{ config: &config.Config{
AttestationVariant: variant.QEMUVTPM{}.String(), AttestationVariant: variant.QEMUVTPM{}.String(),

View File

@ -18,18 +18,19 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/config"
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
"github.com/edgelesssys/constellation/v2/internal/variant"
"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"
"helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/engine" "helm.sh/helm/v3/pkg/engine"
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/config"
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
"github.com/edgelesssys/constellation/v2/internal/variant"
) )
// TestLoad checks if the serialized format that Load returns correctly preserves the dependencies of the loaded chart. // TestLoad checks if the serialized format that Load returns correctly preserves the dependencies of the loaded chart.
@ -97,7 +98,7 @@ func TestConstellationServices(t *testing.T) {
}, },
"OpenStack": { "OpenStack": {
config: &config.Config{ config: &config.Config{
AttestationVariant: variant.Dummy{}.String(), AttestationVariant: variant.QEMUVTPM{}.String(),
Provider: config.ProviderConfig{OpenStack: &config.OpenStackConfig{}}, Provider: config.ProviderConfig{OpenStack: &config.OpenStackConfig{}},
}, },
valuesModifier: prepareOpenStackValues, valuesModifier: prepareOpenStackValues,

View File

@ -39,7 +39,7 @@ spec:
args: args:
- --cloud-provider=OpenStack - --cloud-provider=OpenStack
- --key-service-endpoint=key-service.testNamespace:9000 - --key-service-endpoint=key-service.testNamespace:9000
- --attestation-variant=dummy - --attestation-variant=qemu-vtpm
volumeMounts: volumeMounts:
- mountPath: /var/config - mountPath: /var/config
name: config name: config

View File

@ -17,7 +17,7 @@ spec:
spec: spec:
containers: containers:
- args: - args:
- --attestation-variant=dummy - --attestation-variant=qemu-vtpm
image: verificationImage image: verificationImage
name: verification-service name: verification-service
ports: ports:

View File

@ -112,6 +112,20 @@ resource "openstack_compute_secgroup_v2" "vpc_secgroup" {
self = true self = true
} }
rule {
from_port = 1
to_port = 65535
ip_protocol = "udp"
cidr = local.cidr_vpc_subnet_nodes
}
rule {
from_port = 1
to_port = 65535
ip_protocol = "tcp"
cidr = local.cidr_vpc_subnet_nodes
}
rule { rule {
from_port = local.ports_node_range_start from_port = local.ports_node_range_start
to_port = local.ports_node_range_end to_port = local.ports_node_range_end
@ -119,6 +133,13 @@ resource "openstack_compute_secgroup_v2" "vpc_secgroup" {
cidr = "0.0.0.0/0" cidr = "0.0.0.0/0"
} }
rule {
from_port = local.ports_node_range_start
to_port = local.ports_node_range_end
ip_protocol = "udp"
cidr = "0.0.0.0/0"
}
dynamic "rule" { dynamic "rule" {
for_each = flatten([ for_each = flatten([
local.ports_kubernetes, local.ports_kubernetes,

View File

@ -14,6 +14,9 @@ import (
"os" "os"
"sync" "sync"
"github.com/spf13/afero"
"go.uber.org/zap"
"github.com/edgelesssys/constellation/v2/debugd/internal/debugd/deploy" "github.com/edgelesssys/constellation/v2/debugd/internal/debugd/deploy"
"github.com/edgelesssys/constellation/v2/debugd/internal/debugd/info" "github.com/edgelesssys/constellation/v2/debugd/internal/debugd/info"
"github.com/edgelesssys/constellation/v2/debugd/internal/debugd/logcollector" "github.com/edgelesssys/constellation/v2/debugd/internal/debugd/logcollector"
@ -30,8 +33,6 @@ import (
openstackcloud "github.com/edgelesssys/constellation/v2/internal/cloud/openstack" openstackcloud "github.com/edgelesssys/constellation/v2/internal/cloud/openstack"
qemucloud "github.com/edgelesssys/constellation/v2/internal/cloud/qemu" qemucloud "github.com/edgelesssys/constellation/v2/internal/cloud/qemu"
"github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/logger"
"github.com/spf13/afero"
"go.uber.org/zap"
) )
const debugBanner = ` const debugBanner = `

View File

@ -1,5 +1,5 @@
[Output] [Output]
KernelCommandLine=constel.csp=openstack constel.attestation-variant=dummy mem_encrypt=on kvm_amd.sev=1 module_blacklist=qemu_fw_cfg console=tty0 console=ttyS0 KernelCommandLine=constel.csp=openstack constel.attestation-variant=qemu-vtpm mem_encrypt=on kvm_amd.sev=1 module_blacklist=qemu_fw_cfg console=tty0 console=ttyS0
OutputDirectory=mkosi.output.openstack OutputDirectory=mkosi.output.openstack
[Content] [Content]

View File

@ -53,6 +53,16 @@ func DefaultsFor(provider cloudprovider.Provider) M {
13: WithAllBytes(0x00, Enforce), 13: WithAllBytes(0x00, Enforce),
uint32(PCRIndexClusterID): WithAllBytes(0x00, Enforce), uint32(PCRIndexClusterID): WithAllBytes(0x00, Enforce),
} }
case cloudprovider.OpenStack:
return M{
4: PlaceHolderMeasurement(),
8: WithAllBytes(0x00, Enforce),
9: PlaceHolderMeasurement(),
11: WithAllBytes(0x00, Enforce),
12: PlaceHolderMeasurement(),
13: WithAllBytes(0x00, Enforce),
uint32(PCRIndexClusterID): WithAllBytes(0x00, Enforce),
}
default: default:
return nil return nil
} }

View File

@ -26,6 +26,11 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/go-playground/locales/en"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translations "github.com/go-playground/validator/v10/translations/en"
"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/cloud/cloudprovider"
@ -33,10 +38,6 @@ 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/versions" "github.com/edgelesssys/constellation/v2/internal/versions"
"github.com/go-playground/locales/en"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translations "github.com/go-playground/validator/v10/translations/en"
) )
// Measurements is a required alias since docgen is not able to work with // Measurements is a required alias since docgen is not able to work with
@ -249,6 +250,9 @@ type OpenStackConfig struct {
// description: | // description: |
// If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack. // If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack.
DirectDownload *bool `yaml:"directDownload" validate:"required"` DirectDownload *bool `yaml:"directDownload" validate:"required"`
// description: |
// Measurement used to enable measured boot.
Measurements Measurements `yaml:"measurements" validate:"required,no_placeholders"`
} }
// QEMUConfig holds config information for QEMU based Constellation deployments. // QEMUConfig holds config information for QEMU based Constellation deployments.
@ -327,6 +331,7 @@ func Default() *Config {
}, },
OpenStack: &OpenStackConfig{ OpenStack: &OpenStackConfig{
DirectDownload: toPtr(true), DirectDownload: toPtr(true),
Measurements: measurements.DefaultsFor(cloudprovider.OpenStack),
}, },
QEMU: &QEMUConfig{ QEMU: &QEMUConfig{
ImageFormat: "raw", ImageFormat: "raw",
@ -396,6 +401,8 @@ func (c *Config) HasProvider(provider cloudprovider.Provider) bool {
return c.Provider.Azure != nil return c.Provider.Azure != nil
case cloudprovider.GCP: case cloudprovider.GCP:
return c.Provider.GCP != nil return c.Provider.GCP != nil
case cloudprovider.OpenStack:
return c.Provider.OpenStack != nil
case cloudprovider.QEMU: case cloudprovider.QEMU:
return c.Provider.QEMU != nil return c.Provider.QEMU != nil
} }
@ -413,6 +420,9 @@ func (c *Config) UpdateMeasurements(newMeasurements Measurements) {
if c.Provider.GCP != nil { if c.Provider.GCP != nil {
c.Provider.GCP.Measurements.CopyFrom(newMeasurements) c.Provider.GCP.Measurements.CopyFrom(newMeasurements)
} }
if c.Provider.OpenStack != nil {
c.Provider.OpenStack.Measurements.CopyFrom(newMeasurements)
}
if c.Provider.QEMU != nil { if c.Provider.QEMU != nil {
c.Provider.QEMU.Measurements.CopyFrom(newMeasurements) c.Provider.QEMU.Measurements.CopyFrom(newMeasurements)
} }
@ -484,6 +494,9 @@ func (c *Config) GetMeasurements() measurements.M {
if c.Provider.GCP != nil { if c.Provider.GCP != nil {
return c.Provider.GCP.Measurements return c.Provider.GCP.Measurements
} }
if c.Provider.OpenStack != nil {
return c.Provider.OpenStack.Measurements
}
if c.Provider.QEMU != nil { if c.Provider.QEMU != nil {
return c.Provider.QEMU.Measurements return c.Provider.QEMU.Measurements
} }

View File

@ -299,7 +299,7 @@ func init() {
FieldName: "openstack", FieldName: "openstack",
}, },
} }
OpenStackConfigDoc.Fields = make([]encoder.Doc, 13) OpenStackConfigDoc.Fields = make([]encoder.Doc, 14)
OpenStackConfigDoc.Fields[0].Name = "cloud" OpenStackConfigDoc.Fields[0].Name = "cloud"
OpenStackConfigDoc.Fields[0].Type = "string" OpenStackConfigDoc.Fields[0].Type = "string"
OpenStackConfigDoc.Fields[0].Note = "" OpenStackConfigDoc.Fields[0].Note = ""
@ -365,6 +365,11 @@ func init() {
OpenStackConfigDoc.Fields[12].Note = "" OpenStackConfigDoc.Fields[12].Note = ""
OpenStackConfigDoc.Fields[12].Description = "If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack." OpenStackConfigDoc.Fields[12].Description = "If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack."
OpenStackConfigDoc.Fields[12].Comments[encoder.LineComment] = "If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack." OpenStackConfigDoc.Fields[12].Comments[encoder.LineComment] = "If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack."
OpenStackConfigDoc.Fields[13].Name = "measurements"
OpenStackConfigDoc.Fields[13].Type = "Measurements"
OpenStackConfigDoc.Fields[13].Note = ""
OpenStackConfigDoc.Fields[13].Description = "Measurement used to enable measured boot."
OpenStackConfigDoc.Fields[13].Comments[encoder.LineComment] = "Measurement used to enable measured boot."
QEMUConfigDoc.Type = "QEMUConfig" QEMUConfigDoc.Type = "QEMUConfig"
QEMUConfigDoc.Comments[encoder.LineComment] = "QEMUConfig holds config information for QEMU based Constellation deployments." QEMUConfigDoc.Comments[encoder.LineComment] = "QEMUConfig holds config information for QEMU based Constellation deployments."

View File

@ -10,13 +10,6 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/file"
"github.com/edgelesssys/constellation/v2/internal/variant"
"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"
@ -24,6 +17,14 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/goleak" "go.uber.org/goleak"
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/file"
"github.com/edgelesssys/constellation/v2/internal/variant"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -187,7 +188,7 @@ func TestNewWithDefaultOptions(t *testing.T) {
} }
func TestValidate(t *testing.T) { func TestValidate(t *testing.T) {
const defaultErrCount = 31 // expect this number of error messages by default because user-specific values are not set and multiple providers are defined by default const defaultErrCount = 32 // expect this number of error messages by default because user-specific values are not set and multiple providers are defined by default
const azErrCount = 9 const azErrCount = 9
const gcpErrCount = 6 const gcpErrCount = 6

View File

@ -15,6 +15,10 @@ import (
"strconv" "strconv"
"strings" "strings"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
"golang.org/x/mod/semver"
"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/cloud/cloudprovider"
"github.com/edgelesssys/constellation/v2/internal/compatibility" "github.com/edgelesssys/constellation/v2/internal/compatibility"
@ -23,9 +27,6 @@ import (
"github.com/edgelesssys/constellation/v2/internal/variant" "github.com/edgelesssys/constellation/v2/internal/variant"
"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"
"github.com/go-playground/validator/v10"
"golang.org/x/mod/semver"
) )
// ValidationError occurs when the validation of a config fails. // ValidationError occurs when the validation of a config fails.
@ -191,6 +192,9 @@ func (c *Config) translateMoreThanOneProviderError(ut ut.Translator, fe validato
if c.Provider.GCP != nil { if c.Provider.GCP != nil {
definedProviders = append(definedProviders, "GCP") definedProviders = append(definedProviders, "GCP")
} }
if c.Provider.OpenStack != nil {
definedProviders = append(definedProviders, "OpenStack")
}
if c.Provider.QEMU != nil { if c.Provider.QEMU != nil {
definedProviders = append(definedProviders, "QEMU") definedProviders = append(definedProviders, "QEMU")
} }
@ -477,13 +481,10 @@ func (c *Config) validAttestVariant(_ validator.FieldLevel) bool {
return c.Provider.AWS != nil return c.Provider.AWS != nil
case variant.AzureSEVSNP{}, variant.AzureTrustedLaunch{}: case variant.AzureSEVSNP{}, variant.AzureTrustedLaunch{}:
return c.Provider.Azure != nil return c.Provider.Azure != nil
// TODO(malt3): remove this case once we have a vTPM for OpenStack
case variant.Dummy{}:
return c.Provider.OpenStack != nil
case variant.GCPSEVES{}: case variant.GCPSEVES{}:
return c.Provider.GCP != nil return c.Provider.GCP != nil
case variant.QEMUVTPM{}: case variant.QEMUVTPM{}:
return c.Provider.QEMU != nil return c.Provider.QEMU != nil || c.Provider.OpenStack != nil
default: default:
return false return false
} }
@ -502,6 +503,8 @@ func (c *Config) addMissingVariant() {
c.AttestationVariant = variant.GCPSEVES{}.String() c.AttestationVariant = variant.GCPSEVES{}.String()
case cloudprovider.QEMU: case cloudprovider.QEMU:
c.AttestationVariant = variant.QEMUVTPM{}.String() c.AttestationVariant = variant.QEMUVTPM{}.String()
case cloudprovider.OpenStack:
c.AttestationVariant = variant.QEMUVTPM{}.String()
} }
} }