From dcdfae141daa2484f6f6be50e248ad4fcda43eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Wei=C3=9Fe?= Date: Thu, 21 Apr 2022 16:28:37 +0200 Subject: [PATCH] Add qemu CSP for Coordinator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Weiße --- coordinator/attestation/vtpm/attestation.go | 9 ++- coordinator/cloudprovider/qemu/autoscaler.go | 40 +++++++++++ coordinator/cloudprovider/qemu/ccm.go | 70 +++++++++++++++++++ .../cloudprovider/qemu/cloudnodemanager.go | 27 +++++++ coordinator/cloudprovider/qemu/metadata.go | 41 +++++++++++ coordinator/cmd/coordinator/main.go | 26 +++++++ 6 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 coordinator/cloudprovider/qemu/autoscaler.go create mode 100644 coordinator/cloudprovider/qemu/ccm.go create mode 100644 coordinator/cloudprovider/qemu/cloudnodemanager.go create mode 100644 coordinator/cloudprovider/qemu/metadata.go diff --git a/coordinator/attestation/vtpm/attestation.go b/coordinator/attestation/vtpm/attestation.go index 89eb34d77..ee0740ea6 100644 --- a/coordinator/attestation/vtpm/attestation.go +++ b/coordinator/attestation/vtpm/attestation.go @@ -21,7 +21,7 @@ var ( // AzurePCRSelection are the PCR values verified for Azure Constellations. // PCR[0] is excluded due to changing rarely, but unpredictably. // PCR[6] is excluded due to being different for any 2 VMs. See: https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf#%5B%7B%22num%22%3A157%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C33%2C400%2C0%5D - // PCR[10] is excluded due to being different for any 2 VMs. + // PCR[10] is excluded since its value is derived from a digest of PCR[0-7]. See: https://sourceforge.net/p/linux-ima/wiki/Home/#ima-measurement-list AzurePCRSelection = tpm2.PCRSelection{ Hash: tpm2.AlgSHA256, PCRs: []int{1, 2, 3, 4, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}, @@ -29,6 +29,13 @@ var ( // GCPPCRSelection are the PCR values verified for GCP Constellations. // On GCP firmware and other host controlled systems are static. This results in the same PCRs for any 2 VMs using the same image. GCPPCRSelection = tpmClient.FullPcrSel(tpm2.AlgSHA256) + // QEMUPCRSelection are the PCR values verified for QEMU based Contellations. + // PCR[1] is excluded. See: https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf#%5B%7B%22num%22:157,%22gen%22:0%7D,%7B%22name%22:%22XYZ%22%7D,33,400,0%5D + // PCR[10] is excluded since its value is derived from a digest of PCR[0-7]. See: https://sourceforge.net/p/linux-ima/wiki/Home/#ima-measurement-list + QEMUPCRSelection = tpm2.PCRSelection{ + Hash: tpm2.AlgSHA256, + PCRs: []int{0, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}, + } ) type ( diff --git a/coordinator/cloudprovider/qemu/autoscaler.go b/coordinator/cloudprovider/qemu/autoscaler.go new file mode 100644 index 000000000..4ad86bbb3 --- /dev/null +++ b/coordinator/cloudprovider/qemu/autoscaler.go @@ -0,0 +1,40 @@ +package qemu + +import ( + "github.com/edgelesssys/constellation/coordinator/core" + "github.com/edgelesssys/constellation/coordinator/kubernetes/k8sapi/resources" + k8s "k8s.io/api/core/v1" +) + +// Autoscaler holds the QEMU cluster-autoscaler configuration. +type Autoscaler struct{} + +// Name returns the cloud-provider name as used by k8s cluster-autoscaler. +func (a Autoscaler) Name() string { + return "qemu" +} + +// Secrets returns a list of secrets to deploy together with the k8s cluster-autoscaler. +func (a Autoscaler) Secrets(instance core.Instance, cloudServiceAccountURI string) (resources.Secrets, error) { + return resources.Secrets{}, nil +} + +// Volumes returns a list of volumes to deploy together with the k8s cluster-autoscaler. +func (a Autoscaler) Volumes() []k8s.Volume { + return []k8s.Volume{} +} + +// VolumeMounts returns a list of volume mounts to deploy together with the k8s cluster-autoscaler. +func (a Autoscaler) VolumeMounts() []k8s.VolumeMount { + return []k8s.VolumeMount{} +} + +// Env returns a list of k8s environment key-value pairs to deploy together with the k8s cluster-autoscaler. +func (a Autoscaler) Env() []k8s.EnvVar { + return []k8s.EnvVar{} +} + +// Supported is used to determine if we support autoscaling for the cloud provider. +func (a Autoscaler) Supported() bool { + return false +} diff --git a/coordinator/cloudprovider/qemu/ccm.go b/coordinator/cloudprovider/qemu/ccm.go new file mode 100644 index 000000000..6a2361234 --- /dev/null +++ b/coordinator/cloudprovider/qemu/ccm.go @@ -0,0 +1,70 @@ +package qemu + +import ( + "github.com/edgelesssys/constellation/coordinator/core" + "github.com/edgelesssys/constellation/coordinator/kubernetes/k8sapi/resources" + k8s "k8s.io/api/core/v1" +) + +// CloudControllerManager holds the QEMU cloud-controller-manager configuration. +type CloudControllerManager struct{} + +// Image returns the container image used to provide cloud-controller-manager for the cloud-provider. +func (c CloudControllerManager) Image() string { + return "" +} + +// Path returns the path used by cloud-controller-manager executable within the container image. +func (c CloudControllerManager) Path() string { + return "/qemu-cloud-controller-manager" +} + +// Name returns the cloud-provider name as used by k8s cloud-controller-manager (k8s.gcr.io/cloud-controller-manager). +func (c CloudControllerManager) Name() string { + return "qemu" +} + +// ExtraArgs returns a list of arguments to append to the cloud-controller-manager command. +func (c CloudControllerManager) ExtraArgs() []string { + return []string{} +} + +// ConfigMaps returns a list of ConfigMaps to deploy together with the k8s cloud-controller-manager +// Reference: https://kubernetes.io/docs/concepts/configuration/configmap/ . +func (c CloudControllerManager) ConfigMaps(instance core.Instance) (resources.ConfigMaps, error) { + return resources.ConfigMaps{}, nil +} + +// Secrets returns a list of secrets to deploy together with the k8s cloud-controller-manager. +// Reference: https://kubernetes.io/docs/concepts/configuration/secret/ . +func (c CloudControllerManager) Secrets(instance core.Instance, cloudServiceAccountURI string) (resources.Secrets, error) { + return resources.Secrets{}, nil +} + +// Volumes returns a list of volumes to deploy together with the k8s cloud-controller-manager. +// Reference: https://kubernetes.io/docs/concepts/storage/volumes/ . +func (c CloudControllerManager) Volumes() []k8s.Volume { + return []k8s.Volume{} +} + +// VolumeMounts a list of of volume mounts to deploy together with the k8s cloud-controller-manager. +func (c CloudControllerManager) VolumeMounts() []k8s.VolumeMount { + return []k8s.VolumeMount{} +} + +// Env returns a list of k8s environment key-value pairs to deploy together with the k8s cloud-controller-manager. +func (c CloudControllerManager) Env() []k8s.EnvVar { + return []k8s.EnvVar{} +} + +// PrepareInstance is called on every instance before deploying the cloud-controller-manager. +// Allows for cloud-provider specific hooks. +func (c CloudControllerManager) PrepareInstance(instance core.Instance, vpnIP string) error { + // no specific hook required. + return nil +} + +// Supported is used to determine if cloud controller manager is implemented for this cloud provider. +func (c CloudControllerManager) Supported() bool { + return false +} diff --git a/coordinator/cloudprovider/qemu/cloudnodemanager.go b/coordinator/cloudprovider/qemu/cloudnodemanager.go new file mode 100644 index 000000000..3e4175371 --- /dev/null +++ b/coordinator/cloudprovider/qemu/cloudnodemanager.go @@ -0,0 +1,27 @@ +package qemu + +// CloudNodeManager holds the QEMU cloud-node-manager configuration. +type CloudNodeManager struct{} + +// Image returns the container image used to provide cloud-node-manager for the cloud-provider. +// Not used on QEMU. +func (c *CloudNodeManager) Image() string { + return "" +} + +// Path returns the path used by cloud-node-manager executable within the container image. +// Not used on QEMU. +func (c *CloudNodeManager) Path() string { + return "" +} + +// ExtraArgs returns a list of arguments to append to the cloud-node-manager command. +// Not used on QEMU. +func (c *CloudNodeManager) ExtraArgs() []string { + return []string{} +} + +// Supported is used to determine if cloud node manager is implemented for this cloud provider. +func (c *CloudNodeManager) Supported() bool { + return false +} diff --git a/coordinator/cloudprovider/qemu/metadata.go b/coordinator/cloudprovider/qemu/metadata.go new file mode 100644 index 000000000..e5fb9c14d --- /dev/null +++ b/coordinator/cloudprovider/qemu/metadata.go @@ -0,0 +1,41 @@ +package qemu + +import ( + "context" + + "github.com/edgelesssys/constellation/coordinator/core" + "github.com/edgelesssys/constellation/coordinator/role" +) + +// Metadata implements core.ProviderMetadata interface for QEMU (currently not supported). +type Metadata struct{} + +// Supported is used to determine if metadata API is implemented for this cloud provider. +func (m *Metadata) Supported() bool { + return false +} + +// List retrieves all instances belonging to the current constellation. +func (m *Metadata) List(ctx context.Context) ([]core.Instance, error) { + panic("function *Metadata.List not implemented") +} + +// Self retrieves the current instance. +func (m *Metadata) Self(ctx context.Context) (core.Instance, error) { + panic("function *Metdata.Self not implemented") +} + +// GetInstance retrieves an instance using its providerID. +func (m Metadata) GetInstance(ctx context.Context, providerID string) (core.Instance, error) { + panic("function *Metadata.GetInstance not implemented") +} + +// SignalRole signals the constellation role via cloud provider metadata (if supported by the CSP and deployment type, otherwise does nothing). +func (m Metadata) SignalRole(ctx context.Context, role role.Role) error { + panic("function *Metadata.SignalRole not implemented") +} + +// SetVPNIP stores the internally used VPN IP in cloud provider metadata (if supported and required for autoscaling by the CSP, otherwise does nothing). +func (m Metadata) SetVPNIP(ctx context.Context, vpnIP string) error { + panic("function *Metadata.SetVPNIP not implemented") +} diff --git a/coordinator/cmd/coordinator/main.go b/coordinator/cmd/coordinator/main.go index 80a6fa4ce..c6b0cb74c 100644 --- a/coordinator/cmd/coordinator/main.go +++ b/coordinator/cmd/coordinator/main.go @@ -12,10 +12,12 @@ import ( "github.com/edgelesssys/constellation/cli/file" "github.com/edgelesssys/constellation/coordinator/attestation/azure" "github.com/edgelesssys/constellation/coordinator/attestation/gcp" + "github.com/edgelesssys/constellation/coordinator/attestation/qemu" "github.com/edgelesssys/constellation/coordinator/attestation/simulator" "github.com/edgelesssys/constellation/coordinator/attestation/vtpm" azurecloud "github.com/edgelesssys/constellation/coordinator/cloudprovider/azure" gcpcloud "github.com/edgelesssys/constellation/coordinator/cloudprovider/gcp" + qemucloud "github.com/edgelesssys/constellation/coordinator/cloudprovider/qemu" "github.com/edgelesssys/constellation/coordinator/config" "github.com/edgelesssys/constellation/coordinator/core" "github.com/edgelesssys/constellation/coordinator/diskencryption" @@ -127,6 +129,30 @@ func main() { cloudControllerManager = &azurecloud.CloudControllerManager{} cloudNodeManager = &azurecloud.CloudNodeManager{} autoscaler = &azurecloud.Autoscaler{} + encryptedDisk = diskencryption.New() + bindIP = defaultIP + bindPort = defaultPort + etcdEndpoint = defaultEtcdEndpoint + enforceEtcdTls = true + openTPM = vtpm.OpenVTPM + fs = afero.NewOsFs() + case "qemu": + pcrs, err := vtpm.GetSelectedPCRs(vtpm.OpenVTPM, vtpm.QEMUPCRSelection) + if err != nil { + log.Fatal(err) + } + + issuer = qemu.NewIssuer() + validator = qemu.NewValidator(pcrs) + + kube = kubernetes.New(&k8sapi.KubernetesUtil{}, &k8sapi.CoreOSConfiguration{}, kubectl.New()) + + // no support for cloud services in qemu + metadata = &qemucloud.Metadata{} + cloudControllerManager = &qemucloud.CloudControllerManager{} + cloudNodeManager = &qemucloud.CloudNodeManager{} + autoscaler = &qemucloud.Autoscaler{} + encryptedDisk = diskencryption.New() bindIP = defaultIP bindPort = defaultPort