mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
Deploy KMS server image in Constellation
Add image pull secret for ghcr.io
This commit is contained in:
parent
4dcb3aa062
commit
db5468a886
29
Dockerfile.kms
Normal file
29
Dockerfile.kms
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
FROM ubuntu@sha256:7cc0576c7c0ec2384de5cbf245f41567e922aab1b075f3e8ad565f508032df17 as build
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND="noninteractive"
|
||||||
|
RUN apt-get update && apt-get install wget git -y
|
||||||
|
|
||||||
|
# Install Go
|
||||||
|
ARG GO_VER=1.18
|
||||||
|
RUN wget https://go.dev/dl/go${GO_VER}.linux-amd64.tar.gz
|
||||||
|
RUN tar -C /usr/local -xzf go${GO_VER}.linux-amd64.tar.gz && rm go${GO_VER}.linux-amd64.tar.gz
|
||||||
|
ENV PATH ${PATH}:/usr/local/go/bin
|
||||||
|
|
||||||
|
# Download go dependencies
|
||||||
|
WORKDIR /constellation/
|
||||||
|
COPY go.mod ./
|
||||||
|
COPY go.sum ./
|
||||||
|
RUN go mod download all
|
||||||
|
|
||||||
|
# Copy Repo
|
||||||
|
COPY . /constellation
|
||||||
|
RUN rm -rf ./hack/ go.work.sum go.work
|
||||||
|
|
||||||
|
# Build
|
||||||
|
RUN mkdir -p /constellation/build
|
||||||
|
WORKDIR /constellation/kms/server/cmd
|
||||||
|
RUN CGO_ENABLED=0 go build -o /constellation/build/kmsserver
|
||||||
|
|
||||||
|
FROM scratch as release
|
||||||
|
COPY --from=build /constellation/build/kmsserver /kmsserver
|
||||||
|
ENTRYPOINT ["/kmsserver"]
|
@ -1,17 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
const (
|
|
||||||
// wireguardAdminMTU is the MTU designated for the admin's WireGuard interface.
|
|
||||||
//
|
|
||||||
// WireGuard doesn't support Path MTU Discovery. Thus, its default MTU can be too high on some networks.
|
|
||||||
wireguardAdminMTU = 1300
|
|
||||||
|
|
||||||
// masterSecretLengthDefault is the default length in bytes for CLI generated master secrets.
|
|
||||||
masterSecretLengthDefault = 32
|
|
||||||
|
|
||||||
// masterSecretLengthMin is the minimal length in bytes for user provided master secrets.
|
|
||||||
masterSecretLengthMin = 16
|
|
||||||
|
|
||||||
// constellationNameLength is the maximum length of a Constellation's name.
|
|
||||||
constellationNameLength = 37
|
|
||||||
)
|
|
@ -133,10 +133,10 @@ func parseCreateFlags(cmd *cobra.Command, provider cloudprovider.Provider) (crea
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return createFlags{}, err
|
return createFlags{}, err
|
||||||
}
|
}
|
||||||
if len(name) > constellationNameLength {
|
if len(name) > constants.ConstellationNameLength {
|
||||||
return createFlags{}, fmt.Errorf(
|
return createFlags{}, fmt.Errorf(
|
||||||
"name for Constellation cluster too long, maximum length is %d, got %d: %s",
|
"name for Constellation cluster too long, maximum length is %d, got %d: %s",
|
||||||
constellationNameLength, len(name), name,
|
constants.ConstellationNameLength, len(name), name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ func TestCreate(t *testing.T) {
|
|||||||
provider: cloudprovider.GCP,
|
provider: cloudprovider.GCP,
|
||||||
controllerCountFlag: intPtr(1),
|
controllerCountFlag: intPtr(1),
|
||||||
workerCountFlag: intPtr(1),
|
workerCountFlag: intPtr(1),
|
||||||
nameFlag: strings.Repeat("a", constellationNameLength+1),
|
nameFlag: strings.Repeat("a", constants.ConstellationNameLength+1),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"flag control-plane-count invalid": {
|
"flag control-plane-count invalid": {
|
||||||
|
@ -153,7 +153,7 @@ func initialize(ctx context.Context, cmd *cobra.Command, protCl protoClient, ser
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
vpnConfig, err := vpnHandler.Create(result.coordinatorPubKey, result.coordinatorPubIP, string(flags.userPrivKey), result.clientVpnIP, wireguardAdminMTU)
|
vpnConfig, err := vpnHandler.Create(result.coordinatorPubKey, result.coordinatorPubIP, string(flags.userPrivKey), result.clientVpnIP, constants.WireguardAdminMTU)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -374,14 +374,14 @@ func readOrGeneratedMasterSecret(w io.Writer, fileHandler file.Handler, filename
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(decoded) < masterSecretLengthMin {
|
if len(decoded) < constants.MasterSecretLengthMin {
|
||||||
return nil, errors.New("provided master secret is smaller than the required minimum of 16 Bytes")
|
return nil, errors.New("provided master secret is smaller than the required minimum of 16 Bytes")
|
||||||
}
|
}
|
||||||
return decoded, nil
|
return decoded, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// No file given, generate a new secret, and save it to disk
|
// No file given, generate a new secret, and save it to disk
|
||||||
masterSecret, err := util.GenerateRandomBytes(masterSecretLengthDefault)
|
masterSecret, err := util.GenerateRandomBytes(constants.MasterSecretLengthDefault)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ func (c *Core) GetK8SCertificateKey() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InitCluster initializes the cluster, stores the join args, and returns the kubeconfig.
|
// InitCluster initializes the cluster, stores the join args, and returns the kubeconfig.
|
||||||
func (c *Core) InitCluster(autoscalingNodeGroups []string, cloudServiceAccountURI string) ([]byte, error) {
|
func (c *Core) InitCluster(autoscalingNodeGroups []string, cloudServiceAccountURI string, masterSecret []byte) ([]byte, error) {
|
||||||
var nodeName string
|
var nodeName string
|
||||||
var providerID string
|
var providerID string
|
||||||
var instance Instance
|
var instance Instance
|
||||||
@ -99,6 +99,7 @@ func (c *Core) InitCluster(autoscalingNodeGroups []string, cloudServiceAccountUR
|
|||||||
CloudNodeManagerImage: c.cloudNodeManager.Image(),
|
CloudNodeManagerImage: c.cloudNodeManager.Image(),
|
||||||
CloudNodeManagerPath: c.cloudNodeManager.Path(),
|
CloudNodeManagerPath: c.cloudNodeManager.Path(),
|
||||||
CloudNodeManagerExtraArgs: c.cloudNodeManager.ExtraArgs(),
|
CloudNodeManagerExtraArgs: c.cloudNodeManager.ExtraArgs(),
|
||||||
|
MasterSecret: masterSecret,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
c.zaplogger.Error("Initializing cluster failed", zap.Error(err))
|
c.zaplogger.Error("Initializing cluster failed", zap.Error(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -23,12 +23,15 @@ import (
|
|||||||
func TestInitCluster(t *testing.T) {
|
func TestInitCluster(t *testing.T) {
|
||||||
someErr := errors.New("someErr")
|
someErr := errors.New("someErr")
|
||||||
|
|
||||||
|
testMS := []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
cluster clusterStub
|
cluster clusterStub
|
||||||
metadata stubMetadata
|
metadata stubMetadata
|
||||||
cloudControllerManager stubCloudControllerManager
|
cloudControllerManager stubCloudControllerManager
|
||||||
cloudNodeManager stubCloudNodeManager
|
cloudNodeManager stubCloudNodeManager
|
||||||
clusterAutoscaler stubClusterAutoscaler
|
clusterAutoscaler stubClusterAutoscaler
|
||||||
|
masterSecret []byte
|
||||||
autoscalingNodeGroups []string
|
autoscalingNodeGroups []string
|
||||||
wantErr bool
|
wantErr bool
|
||||||
wantInitClusterInput kubernetes.InitClusterInput
|
wantInitClusterInput kubernetes.InitClusterInput
|
||||||
@ -38,6 +41,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
kubeconfig: []byte("kubeconfig"),
|
kubeconfig: []byte("kubeconfig"),
|
||||||
},
|
},
|
||||||
autoscalingNodeGroups: []string{"someNodeGroup"},
|
autoscalingNodeGroups: []string{"someNodeGroup"},
|
||||||
|
masterSecret: testMS,
|
||||||
wantInitClusterInput: kubernetes.InitClusterInput{
|
wantInitClusterInput: kubernetes.InitClusterInput{
|
||||||
APIServerAdvertiseIP: "10.118.0.1",
|
APIServerAdvertiseIP: "10.118.0.1",
|
||||||
NodeIP: "10.118.0.1",
|
NodeIP: "10.118.0.1",
|
||||||
@ -45,6 +49,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
SupportsCloudControllerManager: false,
|
SupportsCloudControllerManager: false,
|
||||||
SupportClusterAutoscaler: false,
|
SupportClusterAutoscaler: false,
|
||||||
AutoscalingNodeGroups: []string{"someNodeGroup"},
|
AutoscalingNodeGroups: []string{"someNodeGroup"},
|
||||||
|
MasterSecret: testMS,
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
@ -52,6 +57,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
cluster: clusterStub{
|
cluster: clusterStub{
|
||||||
kubeconfig: []byte("kubeconfig"),
|
kubeconfig: []byte("kubeconfig"),
|
||||||
},
|
},
|
||||||
|
masterSecret: testMS,
|
||||||
metadata: stubMetadata{
|
metadata: stubMetadata{
|
||||||
selfRes: Instance{
|
selfRes: Instance{
|
||||||
Name: "some-name",
|
Name: "some-name",
|
||||||
@ -66,6 +72,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
ProviderID: "fake://providerid",
|
ProviderID: "fake://providerid",
|
||||||
SupportsCloudControllerManager: false,
|
SupportsCloudControllerManager: false,
|
||||||
SupportClusterAutoscaler: false,
|
SupportClusterAutoscaler: false,
|
||||||
|
MasterSecret: testMS,
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
@ -87,6 +94,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
nameRes: "some-name",
|
nameRes: "some-name",
|
||||||
supportedRes: true,
|
supportedRes: true,
|
||||||
},
|
},
|
||||||
|
masterSecret: testMS,
|
||||||
autoscalingNodeGroups: []string{"someNodeGroup"},
|
autoscalingNodeGroups: []string{"someNodeGroup"},
|
||||||
wantInitClusterInput: kubernetes.InitClusterInput{
|
wantInitClusterInput: kubernetes.InitClusterInput{
|
||||||
APIServerAdvertiseIP: "10.118.0.1",
|
APIServerAdvertiseIP: "10.118.0.1",
|
||||||
@ -96,6 +104,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
SupportClusterAutoscaler: true,
|
SupportClusterAutoscaler: true,
|
||||||
AutoscalingCloudprovider: "some-name",
|
AutoscalingCloudprovider: "some-name",
|
||||||
AutoscalingNodeGroups: []string{"someNodeGroup"},
|
AutoscalingNodeGroups: []string{"someNodeGroup"},
|
||||||
|
MasterSecret: testMS,
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
@ -103,6 +112,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
cluster: clusterStub{
|
cluster: clusterStub{
|
||||||
kubeconfig: []byte("kubeconfig"),
|
kubeconfig: []byte("kubeconfig"),
|
||||||
},
|
},
|
||||||
|
masterSecret: testMS,
|
||||||
cloudControllerManager: stubCloudControllerManager{
|
cloudControllerManager: stubCloudControllerManager{
|
||||||
supportedRes: true,
|
supportedRes: true,
|
||||||
nameRes: "some-name",
|
nameRes: "some-name",
|
||||||
@ -118,6 +128,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
CloudControllerManagerName: "some-name",
|
CloudControllerManagerName: "some-name",
|
||||||
CloudControllerManagerImage: "someImage",
|
CloudControllerManagerImage: "someImage",
|
||||||
CloudControllerManagerPath: "/some/path",
|
CloudControllerManagerPath: "/some/path",
|
||||||
|
MasterSecret: testMS,
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
@ -141,6 +152,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
cluster: clusterStub{
|
cluster: clusterStub{
|
||||||
kubeconfig: []byte("kubeconfig"),
|
kubeconfig: []byte("kubeconfig"),
|
||||||
},
|
},
|
||||||
|
masterSecret: testMS,
|
||||||
metadata: stubMetadata{
|
metadata: stubMetadata{
|
||||||
signalRoleErr: errors.New("updating role fails"),
|
signalRoleErr: errors.New("updating role fails"),
|
||||||
supportedRes: true,
|
supportedRes: true,
|
||||||
@ -149,6 +161,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
wantInitClusterInput: kubernetes.InitClusterInput{
|
wantInitClusterInput: kubernetes.InitClusterInput{
|
||||||
APIServerAdvertiseIP: "10.118.0.1",
|
APIServerAdvertiseIP: "10.118.0.1",
|
||||||
NodeIP: "10.118.0.1",
|
NodeIP: "10.118.0.1",
|
||||||
|
MasterSecret: testMS,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"getting kubeconfig fail detected": {
|
"getting kubeconfig fail detected": {
|
||||||
@ -176,7 +189,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
core, err := NewCore(&stubVPN{}, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, nil, zapLogger, simulator.OpenSimulatedTPM, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
core, err := NewCore(&stubVPN{}, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, nil, zapLogger, simulator.OpenSimulatedTPM, nil, file.NewHandler(fs), user.NewLinuxUserManagerFake(fs))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
kubeconfig, err := core.InitCluster(tc.autoscalingNodeGroups, "cloud-service-account-uri")
|
kubeconfig, err := core.InitCluster(tc.autoscalingNodeGroups, "cloud-service-account-uri", tc.masterSecret)
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
|
@ -32,4 +32,5 @@ type InitClusterInput struct {
|
|||||||
CloudNodeManagerImage string
|
CloudNodeManagerImage string
|
||||||
CloudNodeManagerPath string
|
CloudNodeManagerPath string
|
||||||
CloudNodeManagerExtraArgs []string
|
CloudNodeManagerExtraArgs []string
|
||||||
|
MasterSecret []byte
|
||||||
}
|
}
|
||||||
|
32
coordinator/kubernetes/k8sapi/resources/image_pull_secret.go
Normal file
32
coordinator/kubernetes/k8sapi/resources/image_pull_secret.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/internal/secrets"
|
||||||
|
k8s "k8s.io/api/core/v1"
|
||||||
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewImagePullSecret creates a new k8s.Secret from the config for authenticating when pulling images.
|
||||||
|
func NewImagePullSecret() k8s.Secret {
|
||||||
|
base64EncodedSecret := base64.StdEncoding.EncodeToString(
|
||||||
|
[]byte(fmt.Sprintf("%s:%s", secrets.PullSecretUser, secrets.PullSecretToken)),
|
||||||
|
)
|
||||||
|
|
||||||
|
pullSecretDockerCfgJson := fmt.Sprintf(`{"auths":{"ghcr.io":{"auth":"%s"}}}`, base64EncodedSecret)
|
||||||
|
|
||||||
|
return k8s.Secret{
|
||||||
|
TypeMeta: meta.TypeMeta{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
Name: secrets.PullSecretName,
|
||||||
|
Namespace: "kube-system",
|
||||||
|
},
|
||||||
|
StringData: map[string]string{".dockerconfigjson": pullSecretDockerCfgJson},
|
||||||
|
Type: "kubernetes.io/dockerconfigjson",
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestImagePullSecret(t *testing.T) {
|
||||||
|
imgPullSec := NewImagePullSecret()
|
||||||
|
_, err := imgPullSec.Marshal()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
162
coordinator/kubernetes/k8sapi/resources/kms.go
Normal file
162
coordinator/kubernetes/k8sapi/resources/kms.go
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
package resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/edgelesssys/constellation/internal/constants"
|
||||||
|
"github.com/edgelesssys/constellation/internal/secrets"
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type kmsDeployment struct {
|
||||||
|
ServiceAccount k8s.ServiceAccount
|
||||||
|
ClusterRole rbac.ClusterRole
|
||||||
|
ClusterRoleBinding rbac.ClusterRoleBinding
|
||||||
|
Deployment apps.Deployment
|
||||||
|
MasterSecret k8s.Secret
|
||||||
|
ImagePullSecret k8s.Secret
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
kmsImage = "ghcr.io/edgelesssys/constellation/kmsserver:latest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewKMSDeployment creates a new *kmsDeployment to use as the key management system inside Constellation.
|
||||||
|
func NewKMSDeployment(masterSecret []byte) *kmsDeployment {
|
||||||
|
return &kmsDeployment{
|
||||||
|
ServiceAccount: k8s.ServiceAccount{
|
||||||
|
TypeMeta: meta.TypeMeta{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "ServiceAccount",
|
||||||
|
},
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
Name: "kms",
|
||||||
|
Namespace: "kube-system",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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: "kube-system",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Deployment: apps.Deployment{
|
||||||
|
TypeMeta: meta.TypeMeta{
|
||||||
|
APIVersion: "apps/v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
},
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"k8s-app": "kms",
|
||||||
|
},
|
||||||
|
Name: "kms",
|
||||||
|
Namespace: "kube-system",
|
||||||
|
},
|
||||||
|
Spec: apps.DeploymentSpec{
|
||||||
|
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{
|
||||||
|
ImagePullSecrets: []k8s.LocalObjectReference{
|
||||||
|
{
|
||||||
|
Name: secrets.PullSecretName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Volumes: []k8s.Volume{
|
||||||
|
{
|
||||||
|
Name: "mastersecret",
|
||||||
|
VolumeSource: k8s.VolumeSource{
|
||||||
|
Secret: &k8s.SecretVolumeSource{
|
||||||
|
SecretName: constants.ConstellationMasterSecretStoreName,
|
||||||
|
Items: []k8s.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: constants.ConstellationMasterSecretKey,
|
||||||
|
Path: "constellation-mastersecret.base64",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServiceAccountName: "kms",
|
||||||
|
Containers: []k8s.Container{
|
||||||
|
{
|
||||||
|
Name: "kms",
|
||||||
|
Image: kmsImage,
|
||||||
|
VolumeMounts: []k8s.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "mastersecret",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/constellation/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MasterSecret: k8s.Secret{
|
||||||
|
TypeMeta: meta.TypeMeta{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
},
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
Name: constants.ConstellationMasterSecretStoreName,
|
||||||
|
Namespace: "kube-system",
|
||||||
|
},
|
||||||
|
Data: map[string][]byte{
|
||||||
|
constants.ConstellationMasterSecretKey: masterSecret,
|
||||||
|
},
|
||||||
|
Type: "Opaque",
|
||||||
|
},
|
||||||
|
ImagePullSecret: NewImagePullSecret(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *kmsDeployment) Marshal() ([]byte, error) {
|
||||||
|
return MarshalK8SResources(c)
|
||||||
|
}
|
22
coordinator/kubernetes/k8sapi/resources/kms_test.go
Normal file
22
coordinator/kubernetes/k8sapi/resources/kms_test.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestKMSMarshalUnmarshal(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
testMS := []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}
|
||||||
|
kmsDepl := NewKMSDeployment(testMS)
|
||||||
|
data, err := kmsDepl.Marshal()
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
var recreated kmsDeployment
|
||||||
|
require.NoError(UnmarshalK8SResources(data, &recreated))
|
||||||
|
assert.Equal(kmsDepl, &recreated)
|
||||||
|
}
|
@ -35,6 +35,7 @@ type ClusterUtil interface {
|
|||||||
SetupAutoscaling(kubectl Client, clusterAutoscalerConfiguration resources.Marshaler, secrets resources.Marshaler) error
|
SetupAutoscaling(kubectl Client, clusterAutoscalerConfiguration resources.Marshaler, secrets resources.Marshaler) error
|
||||||
SetupCloudControllerManager(kubectl Client, cloudControllerManagerConfiguration resources.Marshaler, configMaps resources.Marshaler, secrets resources.Marshaler) error
|
SetupCloudControllerManager(kubectl Client, cloudControllerManagerConfiguration resources.Marshaler, configMaps resources.Marshaler, secrets resources.Marshaler) error
|
||||||
SetupCloudNodeManager(kubectl Client, cloudNodeManagerConfiguration resources.Marshaler) error
|
SetupCloudNodeManager(kubectl Client, cloudNodeManagerConfiguration resources.Marshaler) error
|
||||||
|
SetupKMS(kubectl Client, kmsConfiguration resources.Marshaler) error
|
||||||
StartKubelet() error
|
StartKubelet() error
|
||||||
RestartKubelet() error
|
RestartKubelet() error
|
||||||
GetControlPlaneJoinCertificateKey() (string, error)
|
GetControlPlaneJoinCertificateKey() (string, error)
|
||||||
@ -173,6 +174,14 @@ func (k *KubernetesUtil) JoinCluster(joinConfig []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetupKMS deploys the KMS deployment.
|
||||||
|
func (k *KubernetesUtil) SetupKMS(kubectl Client, kmsConfiguration resources.Marshaler) error {
|
||||||
|
if err := kubectl.Apply(kmsConfiguration, true); err != nil {
|
||||||
|
return fmt.Errorf("applying KMS configuration failed: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// StartKubelet enables and starts the kubelet systemd unit.
|
// StartKubelet enables and starts the kubelet systemd unit.
|
||||||
func (k *KubernetesUtil) StartKubelet() error {
|
func (k *KubernetesUtil) StartKubelet() error {
|
||||||
ctx, cancel := context.WithTimeout(context.TODO(), kubeletStartTimeout)
|
ctx, cancel := context.WithTimeout(context.TODO(), kubeletStartTimeout)
|
||||||
|
@ -79,6 +79,11 @@ func (k *KubeWrapper) InitCluster(in InitClusterInput) error {
|
|||||||
return fmt.Errorf("setup of pod network failed: %w", err)
|
return fmt.Errorf("setup of pod network failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kms := resources.NewKMSDeployment(in.MasterSecret)
|
||||||
|
if err = k.clusterUtil.SetupKMS(k.client, kms); err != nil {
|
||||||
|
return fmt.Errorf("setup of kms failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if in.SupportsCloudControllerManager {
|
if in.SupportsCloudControllerManager {
|
||||||
cloudControllerManagerConfiguration := resources.NewDefaultCloudControllerManagerDeployment(
|
cloudControllerManagerConfiguration := resources.NewDefaultCloudControllerManagerDeployment(
|
||||||
in.CloudControllerManagerName, in.CloudControllerManagerImage, in.CloudControllerManagerPath, in.CloudControllerManagerExtraArgs,
|
in.CloudControllerManagerName, in.CloudControllerManagerImage, in.CloudControllerManagerPath, in.CloudControllerManagerExtraArgs,
|
||||||
|
@ -27,6 +27,7 @@ type stubClusterUtil struct {
|
|||||||
setupAutoscalingError error
|
setupAutoscalingError error
|
||||||
setupCloudControllerManagerError error
|
setupCloudControllerManagerError error
|
||||||
setupCloudNodeManagerError error
|
setupCloudNodeManagerError error
|
||||||
|
setupKMSError error
|
||||||
joinClusterErr error
|
joinClusterErr error
|
||||||
startKubeletErr error
|
startKubeletErr error
|
||||||
restartKubeletErr error
|
restartKubeletErr error
|
||||||
@ -58,6 +59,10 @@ func (s *stubClusterUtil) SetupCloudControllerManager(kubectl k8sapi.Client, clo
|
|||||||
return s.setupCloudControllerManagerError
|
return s.setupCloudControllerManagerError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stubClusterUtil) SetupKMS(kubectl k8sapi.Client, kmsDeployment resources.Marshaler) error {
|
||||||
|
return s.setupKMSError
|
||||||
|
}
|
||||||
|
|
||||||
func (s *stubClusterUtil) SetupCloudNodeManager(kubectl k8sapi.Client, cloudNodeManagerConfiguration resources.Marshaler) error {
|
func (s *stubClusterUtil) SetupCloudNodeManager(kubectl k8sapi.Client, cloudNodeManagerConfiguration resources.Marshaler) error {
|
||||||
return s.setupCloudNodeManagerError
|
return s.setupCloudNodeManagerError
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ func (a *API) ActivateAsCoordinator(in *pubproto.ActivateAsCoordinatorRequest, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
logToCLI("Initializing Kubernetes ...")
|
logToCLI("Initializing Kubernetes ...")
|
||||||
kubeconfig, err := a.core.InitCluster(in.AutoscalingNodeGroups, in.CloudServiceAccountUri)
|
kubeconfig, err := a.core.InitCluster(in.AutoscalingNodeGroups, in.CloudServiceAccountUri, in.MasterSecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status.Errorf(codes.Internal, "initializing Kubernetes cluster failed: %v", err)
|
return status.Errorf(codes.Internal, "initializing Kubernetes cluster failed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,6 @@ type Core interface {
|
|||||||
|
|
||||||
CreateSSHUsers([]ssh.UserKey) error
|
CreateSSHUsers([]ssh.UserKey) error
|
||||||
|
|
||||||
InitCluster(autoscalingNodeGroups []string, cloudServiceAccountURI string) ([]byte, error)
|
InitCluster(autoscalingNodeGroups []string, cloudServiceAccountURI string, masterSecret []byte) ([]byte, error)
|
||||||
JoinCluster(joinToken *kubeadm.BootstrapTokenDiscovery, certificateKey string, role role.Role) error
|
JoinCluster(joinToken *kubeadm.BootstrapTokenDiscovery, certificateKey string, role role.Role) error
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ func (c *fakeCore) UpdatePeers(peers []peer.Peer) error {
|
|||||||
return c.UpdatePeersErr
|
return c.UpdatePeersErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeCore) InitCluster(autoscalingNodeGroups []string, cloudServiceAccountURI string) ([]byte, error) {
|
func (c *fakeCore) InitCluster(autoscalingNodeGroups []string, cloudServiceAccountURI string, masterSecret []byte) ([]byte, error) {
|
||||||
c.autoscalingNodeGroups = autoscalingNodeGroups
|
c.autoscalingNodeGroups = autoscalingNodeGroups
|
||||||
return c.kubeconfig, nil
|
return c.kubeconfig, nil
|
||||||
}
|
}
|
||||||
|
21
go.work.sum
21
go.work.sum
@ -1,5 +1,26 @@
|
|||||||
|
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||||
|
github.com/containerd/containerd v1.4.11/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
|
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
|
||||||
|
github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
|
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
|
||||||
|
github.com/google/cadvisor v0.43.0/go.mod h1:+RdMSbc3FVr5NYCD2dOEJy/LI0jYJ/0xJXkzWXEyiFQ=
|
||||||
github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww=
|
github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww=
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
|
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||||
|
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
|
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||||
|
github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||||
|
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM=
|
||||||
|
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
|
||||||
|
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||||
|
k8s.io/kubernetes v1.23.5/go.mod h1:avI3LUTUYZugxwh52KMVM7v9ZjB5gYJ6D3FIoZ1SHUo=
|
||||||
|
k8s.io/system-validators v1.6.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q=
|
||||||
|
k8s.io/utils v0.0.0-20220127004650-9b3446523e65/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
|
@ -7,6 +7,17 @@ package constants
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
//
|
||||||
|
// Constellation.
|
||||||
|
//
|
||||||
|
|
||||||
|
// ConstellationNameLength is the maximum length of a Constellation's name.
|
||||||
|
ConstellationNameLength = 37
|
||||||
|
// ConstellationMasterSecretStoreName is the name for the Constellation secrets in Kubernetes.
|
||||||
|
ConstellationMasterSecretStoreName = "constellation-mastersecret"
|
||||||
|
// ConstellationMasterSecretKey is the name of the key for master secret in the master secret store secret.
|
||||||
|
ConstellationMasterSecretKey = "mastersecret"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Ports.
|
// Ports.
|
||||||
//
|
//
|
||||||
@ -35,8 +46,14 @@ const (
|
|||||||
//
|
//
|
||||||
// Cryptographic constants.
|
// Cryptographic constants.
|
||||||
//
|
//
|
||||||
|
|
||||||
StateDiskKeyLength = 32
|
StateDiskKeyLength = 32
|
||||||
|
// DerivedKeyLengthDefault is the default length in bytes for KMS derived keys.
|
||||||
DerivedKeyLengthDefault = 32
|
DerivedKeyLengthDefault = 32
|
||||||
|
// MasterSecretLengthDefault is the default length in bytes for CLI generated master secrets.
|
||||||
|
MasterSecretLengthDefault = 32
|
||||||
|
// MasterSecretLengthMin is the minimal length in bytes for user provided master secrets.
|
||||||
|
MasterSecretLengthMin = 16
|
||||||
|
|
||||||
//
|
//
|
||||||
// CLI.
|
// CLI.
|
||||||
@ -52,6 +69,14 @@ const (
|
|||||||
// KubernetesVersion installed by kubeadm.
|
// KubernetesVersion installed by kubeadm.
|
||||||
KubernetesVersion = "stable-1.23"
|
KubernetesVersion = "stable-1.23"
|
||||||
KubernetesJoinTokenTTL = 15 * time.Minute
|
KubernetesJoinTokenTTL = 15 * time.Minute
|
||||||
|
|
||||||
|
//
|
||||||
|
// VPN.
|
||||||
|
//
|
||||||
|
|
||||||
|
// WireguardAdminMTU is the MTU designated for the admin's WireGuard interface.
|
||||||
|
// WireGuard doesn't support Path MTU Discovery. Thus, its default MTU can be too high on some networks.
|
||||||
|
WireguardAdminMTU = 1300
|
||||||
)
|
)
|
||||||
|
|
||||||
// CliVersion is the version of the CLI. Left as a separate variable to allow override during build.
|
// CliVersion is the version of the CLI. Left as a separate variable to allow override during build.
|
||||||
|
7
internal/secrets/secrets.go
Normal file
7
internal/secrets/secrets.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package secrets
|
||||||
|
|
||||||
|
const (
|
||||||
|
PullSecretName = "***REMOVED***"
|
||||||
|
PullSecretToken = "***REMOVED***"
|
||||||
|
PullSecretUser = "***REMOVED***"
|
||||||
|
)
|
@ -2,14 +2,18 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/coordinator/util"
|
"github.com/edgelesssys/constellation/internal/constants"
|
||||||
|
"github.com/edgelesssys/constellation/internal/file"
|
||||||
"github.com/edgelesssys/constellation/kms/server/kmsapi"
|
"github.com/edgelesssys/constellation/kms/server/kmsapi"
|
||||||
"github.com/edgelesssys/constellation/kms/server/kmsapi/kmsproto"
|
"github.com/edgelesssys/constellation/kms/server/kmsapi/kmsproto"
|
||||||
"github.com/edgelesssys/constellation/kms/server/setup"
|
"github.com/edgelesssys/constellation/kms/server/setup"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@ -17,12 +21,12 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
port := flag.String("p", "9000", "Port gRPC server listens on")
|
port := flag.String("p", "9000", "Port gRPC server listens on")
|
||||||
|
masterSecretPath := flag.String("master-secret", "/constellation/constellation-mastersecret.base64", "Path to the Constellation master secret")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// TODO: Get masterSecret from Constellation CLI / after activation from cluster.
|
masterKey, err := readMainSecret(*masterSecretPath)
|
||||||
masterKey, err := util.GenerateRandomBytes(32)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to generate key: %v", err)
|
log.Fatalf("Failed to read master secret: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
conKMS, err := setup.SetUpKMS(context.Background(), setup.NoStoreURI, setup.ClusterKMSURI)
|
conKMS, err := setup.SetUpKMS(context.Background(), setup.NoStoreURI, setup.ClusterKMSURI)
|
||||||
@ -50,3 +54,22 @@ func main() {
|
|||||||
log.Fatalf("Failed to serve: %s", err)
|
log.Fatalf("Failed to serve: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// readMainSecret reads the base64 encoded main secret file from specified path and returns the secret as bytes.
|
||||||
|
func readMainSecret(fileName string) ([]byte, error) {
|
||||||
|
if fileName == "" {
|
||||||
|
return nil, errors.New("no filename to master secret provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileHandler := file.NewHandler(afero.NewOsFs())
|
||||||
|
|
||||||
|
secretBytes, err := fileHandler.Read(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(secretBytes) < constants.MasterSecretLengthMin {
|
||||||
|
return nil, fmt.Errorf("provided master secret is smaller than the required minimum of %d bytes", constants.MasterSecretLengthMin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return secretBytes, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user