mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-01-11 07:29:29 -05:00
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:
parent
509b3d5d58
commit
69de06dd1f
@ -13,6 +13,9 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/helm"
|
||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes"
|
||||
"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/logger"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/spf13/afero"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -161,8 +162,7 @@ func main() {
|
||||
)
|
||||
metadataAPI = metadata
|
||||
|
||||
// TODO(malt3): add OpenStack TPM support
|
||||
openTPM = vtpm.OpenNOPTPM
|
||||
openTPM = vtpm.OpenVTPM
|
||||
fs = afero.NewOsFs()
|
||||
default:
|
||||
clusterInitJoiner = &clusterFake{}
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/Azure/azure-sdk-for-go/profiles/latest/attestation/attestation"
|
||||
azpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/image"
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
|
||||
|
@ -13,14 +13,17 @@ import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/variant"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
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")
|
||||
ip := "192.0.2.1"
|
||||
someErr := errors.New("failed")
|
||||
@ -110,6 +113,47 @@ func TestCreator(t *testing.T) {
|
||||
wantRollback: 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": {
|
||||
tfClient: &stubTerraformClient{ip: ip},
|
||||
libvirt: &stubLibvirtRunner{},
|
||||
@ -152,7 +196,6 @@ func TestCreator(t *testing.T) {
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
creator := &Creator{
|
||||
out: &bytes.Buffer{},
|
||||
image: &stubImageFetcher{
|
||||
|
@ -12,6 +12,10 @@ import (
|
||||
"encoding/hex"
|
||||
"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/attestation/azure/snp"
|
||||
"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/logger"
|
||||
"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) {
|
||||
@ -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": {
|
||||
config: &config.Config{
|
||||
AttestationVariant: variant.QEMUVTPM{}.String(),
|
||||
|
@ -18,18 +18,19 @@ import (
|
||||
"strings"
|
||||
"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/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
"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.
|
||||
@ -97,7 +98,7 @@ func TestConstellationServices(t *testing.T) {
|
||||
},
|
||||
"OpenStack": {
|
||||
config: &config.Config{
|
||||
AttestationVariant: variant.Dummy{}.String(),
|
||||
AttestationVariant: variant.QEMUVTPM{}.String(),
|
||||
Provider: config.ProviderConfig{OpenStack: &config.OpenStackConfig{}},
|
||||
},
|
||||
valuesModifier: prepareOpenStackValues,
|
||||
|
@ -39,7 +39,7 @@ spec:
|
||||
args:
|
||||
- --cloud-provider=OpenStack
|
||||
- --key-service-endpoint=key-service.testNamespace:9000
|
||||
- --attestation-variant=dummy
|
||||
- --attestation-variant=qemu-vtpm
|
||||
volumeMounts:
|
||||
- mountPath: /var/config
|
||||
name: config
|
||||
|
@ -17,7 +17,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --attestation-variant=dummy
|
||||
- --attestation-variant=qemu-vtpm
|
||||
image: verificationImage
|
||||
name: verification-service
|
||||
ports:
|
||||
|
@ -112,6 +112,20 @@ resource "openstack_compute_secgroup_v2" "vpc_secgroup" {
|
||||
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 {
|
||||
from_port = local.ports_node_range_start
|
||||
to_port = local.ports_node_range_end
|
||||
@ -119,6 +133,13 @@ resource "openstack_compute_secgroup_v2" "vpc_secgroup" {
|
||||
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" {
|
||||
for_each = flatten([
|
||||
local.ports_kubernetes,
|
||||
|
@ -14,6 +14,9 @@ import (
|
||||
"os"
|
||||
"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/info"
|
||||
"github.com/edgelesssys/constellation/v2/debugd/internal/debugd/logcollector"
|
||||
@ -30,8 +33,6 @@ import (
|
||||
openstackcloud "github.com/edgelesssys/constellation/v2/internal/cloud/openstack"
|
||||
qemucloud "github.com/edgelesssys/constellation/v2/internal/cloud/qemu"
|
||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||
"github.com/spf13/afero"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const debugBanner = `
|
||||
|
@ -1,5 +1,5 @@
|
||||
[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
|
||||
|
||||
[Content]
|
||||
|
@ -53,6 +53,16 @@ func DefaultsFor(provider cloudprovider.Provider) M {
|
||||
13: 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:
|
||||
return nil
|
||||
}
|
||||
|
@ -26,6 +26,11 @@ import (
|
||||
"reflect"
|
||||
"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/measurements"
|
||||
"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/file"
|
||||
"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
|
||||
@ -249,6 +250,9 @@ type OpenStackConfig struct {
|
||||
// description: |
|
||||
// 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"`
|
||||
// description: |
|
||||
// Measurement used to enable measured boot.
|
||||
Measurements Measurements `yaml:"measurements" validate:"required,no_placeholders"`
|
||||
}
|
||||
|
||||
// QEMUConfig holds config information for QEMU based Constellation deployments.
|
||||
@ -327,6 +331,7 @@ func Default() *Config {
|
||||
},
|
||||
OpenStack: &OpenStackConfig{
|
||||
DirectDownload: toPtr(true),
|
||||
Measurements: measurements.DefaultsFor(cloudprovider.OpenStack),
|
||||
},
|
||||
QEMU: &QEMUConfig{
|
||||
ImageFormat: "raw",
|
||||
@ -396,6 +401,8 @@ func (c *Config) HasProvider(provider cloudprovider.Provider) bool {
|
||||
return c.Provider.Azure != nil
|
||||
case cloudprovider.GCP:
|
||||
return c.Provider.GCP != nil
|
||||
case cloudprovider.OpenStack:
|
||||
return c.Provider.OpenStack != nil
|
||||
case cloudprovider.QEMU:
|
||||
return c.Provider.QEMU != nil
|
||||
}
|
||||
@ -413,6 +420,9 @@ func (c *Config) UpdateMeasurements(newMeasurements Measurements) {
|
||||
if c.Provider.GCP != nil {
|
||||
c.Provider.GCP.Measurements.CopyFrom(newMeasurements)
|
||||
}
|
||||
if c.Provider.OpenStack != nil {
|
||||
c.Provider.OpenStack.Measurements.CopyFrom(newMeasurements)
|
||||
}
|
||||
if c.Provider.QEMU != nil {
|
||||
c.Provider.QEMU.Measurements.CopyFrom(newMeasurements)
|
||||
}
|
||||
@ -484,6 +494,9 @@ func (c *Config) GetMeasurements() measurements.M {
|
||||
if c.Provider.GCP != nil {
|
||||
return c.Provider.GCP.Measurements
|
||||
}
|
||||
if c.Provider.OpenStack != nil {
|
||||
return c.Provider.OpenStack.Measurements
|
||||
}
|
||||
if c.Provider.QEMU != nil {
|
||||
return c.Provider.QEMU.Measurements
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ func init() {
|
||||
FieldName: "openstack",
|
||||
},
|
||||
}
|
||||
OpenStackConfigDoc.Fields = make([]encoder.Doc, 13)
|
||||
OpenStackConfigDoc.Fields = make([]encoder.Doc, 14)
|
||||
OpenStackConfigDoc.Fields[0].Name = "cloud"
|
||||
OpenStackConfigDoc.Fields[0].Type = "string"
|
||||
OpenStackConfigDoc.Fields[0].Note = ""
|
||||
@ -365,6 +365,11 @@ func init() {
|
||||
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].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.Comments[encoder.LineComment] = "QEMUConfig holds config information for QEMU based Constellation deployments."
|
||||
|
@ -10,13 +10,6 @@ import (
|
||||
"reflect"
|
||||
"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"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
@ -24,6 +17,14 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"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) {
|
||||
@ -187,7 +188,7 @@ func TestNewWithDefaultOptions(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 gcpErrCount = 6
|
||||
|
||||
|
@ -15,6 +15,10 @@ import (
|
||||
"strconv"
|
||||
"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/cloud/cloudprovider"
|
||||
"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/versions"
|
||||
"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.
|
||||
@ -191,6 +192,9 @@ func (c *Config) translateMoreThanOneProviderError(ut ut.Translator, fe validato
|
||||
if c.Provider.GCP != nil {
|
||||
definedProviders = append(definedProviders, "GCP")
|
||||
}
|
||||
if c.Provider.OpenStack != nil {
|
||||
definedProviders = append(definedProviders, "OpenStack")
|
||||
}
|
||||
if c.Provider.QEMU != nil {
|
||||
definedProviders = append(definedProviders, "QEMU")
|
||||
}
|
||||
@ -477,13 +481,10 @@ func (c *Config) validAttestVariant(_ validator.FieldLevel) bool {
|
||||
return c.Provider.AWS != nil
|
||||
case variant.AzureSEVSNP{}, variant.AzureTrustedLaunch{}:
|
||||
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{}:
|
||||
return c.Provider.GCP != nil
|
||||
case variant.QEMUVTPM{}:
|
||||
return c.Provider.QEMU != nil
|
||||
return c.Provider.QEMU != nil || c.Provider.OpenStack != nil
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@ -502,6 +503,8 @@ func (c *Config) addMissingVariant() {
|
||||
c.AttestationVariant = variant.GCPSEVES{}.String()
|
||||
case cloudprovider.QEMU:
|
||||
c.AttestationVariant = variant.QEMUVTPM{}.String()
|
||||
case cloudprovider.OpenStack:
|
||||
c.AttestationVariant = variant.QEMUVTPM{}.String()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user