constellation/bootstrapper/internal/kubernetes/k8sapi/resources/kms.go
Daniel Weiße f8c01a0298
AB#2394 Change KMS to be deployed as DaemonSet (#69)
Signed-off-by: Daniel Weiße <dw@edgeless.systems>
2022-09-05 10:22:40 +02:00

260 lines
6.5 KiB
Go

/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package resources
import (
"fmt"
"github.com/edgelesssys/constellation/internal/constants"
"github.com/edgelesssys/constellation/internal/kubernetes"
"github.com/edgelesssys/constellation/internal/versions"
apps "k8s.io/api/apps/v1"
k8s "k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
const kmsNamespace = "kube-system"
type kmsDeployment struct {
ServiceAccount k8s.ServiceAccount
Service k8s.Service
ClusterRole rbac.ClusterRole
ClusterRoleBinding rbac.ClusterRoleBinding
Deployment apps.DaemonSet
MasterSecret k8s.Secret
}
// KMSConfig is the configuration needed to set up Constellation's key management service.
type KMSConfig struct {
MasterSecret []byte
Salt []byte
KMSURI string
StorageURI string
KeyEncryptionKeyID string
UseExistingKEK bool
}
// NewKMSDeployment creates a new *kmsDeployment to use as the key management system inside Constellation.
func NewKMSDeployment(csp string, config KMSConfig) *kmsDeployment {
return &kmsDeployment{
ServiceAccount: k8s.ServiceAccount{
TypeMeta: meta.TypeMeta{
APIVersion: "v1",
Kind: "ServiceAccount",
},
ObjectMeta: meta.ObjectMeta{
Name: "kms",
Namespace: kmsNamespace,
},
},
Service: k8s.Service{
TypeMeta: meta.TypeMeta{
APIVersion: "v1",
Kind: "Service",
},
ObjectMeta: meta.ObjectMeta{
Name: "kms",
Namespace: kmsNamespace,
},
Spec: k8s.ServiceSpec{
Type: k8s.ServiceTypeClusterIP,
Ports: []k8s.ServicePort{
{
Name: "grpc",
Protocol: k8s.ProtocolTCP,
Port: constants.KMSPort,
TargetPort: intstr.FromInt(constants.KMSPort),
},
},
Selector: map[string]string{
"k8s-app": "kms",
},
},
},
ClusterRole: rbac.ClusterRole{
TypeMeta: meta.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1",
Kind: "ClusterRole",
},
ObjectMeta: meta.ObjectMeta{
Name: "kms",
Labels: map[string]string{
"k8s-app": "kms",
},
},
Rules: []rbac.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"secrets"},
Verbs: []string{"get"},
},
},
},
ClusterRoleBinding: rbac.ClusterRoleBinding{
TypeMeta: meta.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1",
Kind: "ClusterRoleBinding",
},
ObjectMeta: meta.ObjectMeta{
Name: "kms",
},
RoleRef: rbac.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "kms",
},
Subjects: []rbac.Subject{
{
Kind: "ServiceAccount",
Name: "kms",
Namespace: kmsNamespace,
},
},
},
Deployment: apps.DaemonSet{
TypeMeta: meta.TypeMeta{
APIVersion: "apps/v1",
Kind: "DaemonSet",
},
ObjectMeta: meta.ObjectMeta{
Labels: map[string]string{
"k8s-app": "kms",
"component": "kms",
"kubernetes.io/cluster-service": "true",
},
Name: "kms",
Namespace: kmsNamespace,
},
Spec: apps.DaemonSetSpec{
Selector: &meta.LabelSelector{
MatchLabels: map[string]string{
"k8s-app": "kms",
},
},
Template: k8s.PodTemplateSpec{
ObjectMeta: meta.ObjectMeta{
Labels: map[string]string{
"k8s-app": "kms",
},
},
Spec: k8s.PodSpec{
PriorityClassName: "system-cluster-critical",
Tolerations: []k8s.Toleration{
{
Key: "CriticalAddonsOnly",
Operator: k8s.TolerationOpExists,
},
{
Key: "node-role.kubernetes.io/master",
Operator: k8s.TolerationOpEqual,
Value: "true",
Effect: k8s.TaintEffectNoSchedule,
},
{
Key: "node-role.kubernetes.io/control-plane",
Operator: k8s.TolerationOpExists,
Effect: k8s.TaintEffectNoSchedule,
},
{
Operator: k8s.TolerationOpExists,
Effect: k8s.TaintEffectNoExecute,
},
{
Operator: k8s.TolerationOpExists,
Effect: k8s.TaintEffectNoSchedule,
},
},
// Only run on control plane nodes
NodeSelector: map[string]string{
"node-role.kubernetes.io/control-plane": "",
},
Volumes: []k8s.Volume{
{
Name: "config",
VolumeSource: k8s.VolumeSource{
Projected: &k8s.ProjectedVolumeSource{
Sources: []k8s.VolumeProjection{
{
ConfigMap: &k8s.ConfigMapProjection{
LocalObjectReference: k8s.LocalObjectReference{
Name: "join-config",
},
Items: []k8s.KeyToPath{
{
Key: constants.MeasurementsFilename,
Path: constants.MeasurementsFilename,
},
},
},
},
{
Secret: &k8s.SecretProjection{
LocalObjectReference: k8s.LocalObjectReference{
Name: constants.ConstellationMasterSecretStoreName,
},
Items: []k8s.KeyToPath{
{
Key: constants.ConstellationMasterSecretKey,
Path: constants.ConstellationMasterSecretKey,
},
{
Key: constants.ConstellationMasterSecretSalt,
Path: constants.ConstellationMasterSecretSalt,
},
},
},
},
},
},
},
},
},
ServiceAccountName: "kms",
Containers: []k8s.Container{
{
Name: "kms",
Image: versions.KmsImage,
Args: []string{
fmt.Sprintf("--port=%d", constants.KMSPort),
},
VolumeMounts: []k8s.VolumeMount{
{
Name: "config",
ReadOnly: true,
MountPath: constants.ServiceBasePath,
},
},
},
},
},
},
},
},
MasterSecret: k8s.Secret{
TypeMeta: meta.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: meta.ObjectMeta{
Name: constants.ConstellationMasterSecretStoreName,
Namespace: kmsNamespace,
},
Data: map[string][]byte{
constants.ConstellationMasterSecretKey: config.MasterSecret,
constants.ConstellationMasterSecretSalt: config.Salt,
},
Type: "Opaque",
},
}
}
func (c *kmsDeployment) Marshal() ([]byte, error) {
return kubernetes.MarshalK8SResources(c)
}