mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-05-02 14:26:23 -04:00
Refactor Helm deployments (#341)
* Wrap KMS deployment in one main chart that deploys all other services. Other services will follow. * Use .tgz via helm-package as serialization format * Change Release type to carry chart as byte slice * Remove KMSConfig * Use json-schema to validate values * Extend release.md to mention updating helm charts
This commit is contained in:
parent
10a207c7ec
commit
07f02a442c
31 changed files with 261 additions and 119 deletions
|
@ -0,0 +1,9 @@
|
|||
apiVersion: v2
|
||||
name: constellation-services
|
||||
description: A chart to deploy all microservices that are part of a valid constellation cluster
|
||||
type: application
|
||||
version: 2.2.0-pre
|
||||
|
||||
dependencies:
|
||||
- name: kms
|
||||
version: 2.2.0-pre
|
|
@ -0,0 +1,23 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
|
@ -2,5 +2,4 @@ apiVersion: v2
|
|||
name: kms
|
||||
description: A Helm chart to deploy the Constellation Key Management Service
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "2.1.0"
|
||||
version: 2.2.0-pre
|
|
@ -18,8 +18,8 @@ spec:
|
|||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --port={{ .Values.kmsPort }}
|
||||
image: {{ .Values.kmsImage }}
|
||||
- --port={{ .Values.port }}
|
||||
image: {{ .Values.image }}
|
||||
name: kms
|
||||
resources: {}
|
||||
volumeMounts:
|
|
@ -6,9 +6,9 @@ metadata:
|
|||
spec:
|
||||
ports:
|
||||
- name: grpc
|
||||
port: {{ .Values.kmsPort }}
|
||||
port: {{ .Values.port }}
|
||||
protocol: TCP
|
||||
targetPort: {{ .Values.kmsPort }}
|
||||
targetPort: {{ .Values.port }}
|
||||
selector:
|
||||
k8s-app: kms
|
||||
type: ClusterIP
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"image": {
|
||||
"description": "Container image to use for the spawned pods.",
|
||||
"type": "string",
|
||||
"examples": ["ghcr.io/edgelesssys/constellation/kms:latest"],
|
||||
"pattern": "ghcr.io/edgelesssys/constellation/kms:*"
|
||||
},
|
||||
"masterSecret": {
|
||||
"description": "Secret used to derive key material within the cluster",
|
||||
"type": "string",
|
||||
"examples": ["h1ydxM+1LKhL6kfj3XJnCYvTPnQGUgU0stk91ebEVqM="],
|
||||
"minLength": 44
|
||||
},
|
||||
"salt": {
|
||||
"description": "Salt for key derivation within the cluster",
|
||||
"type": "string",
|
||||
"examples": ["loC4hhWwFH5rHAKq5/EshSWk1jwkrf22VuHc2SGsWdc="],
|
||||
"minLength": 44
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"image",
|
||||
"salt",
|
||||
"masterSecret"
|
||||
],
|
||||
"title": "Values",
|
||||
"type": "object"
|
||||
}
|
|
@ -1,19 +1,13 @@
|
|||
# Namespace to which KMS will be deployed.
|
||||
namespace: "kube-system"
|
||||
# Port on which the service will listen.
|
||||
kmsPort: 9000
|
||||
port: 9000
|
||||
# Name of the ConfigMap that holds measurements and other info.
|
||||
joinConfigCMName: join-config
|
||||
# Path to which secrets/CMs are mounted.
|
||||
serviceBasePath: /var/config
|
||||
# Container image.
|
||||
kmsImage: setFullImagePathHere
|
||||
# Salt for key derivation.
|
||||
salt: ""
|
||||
# Name of the key within the respective secret that holds the salt.
|
||||
saltKeyName: salt
|
||||
# MasterSecret for the cluster.
|
||||
masterSecret: ""
|
||||
# Name of the secret that contains the master secret.
|
||||
masterSecretName: constellation-mastersecret
|
||||
# Name of the key within the respective secret that holds the master secret.
|
|
@ -9,9 +9,11 @@ package helm
|
|||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
@ -23,6 +25,7 @@ import (
|
|||
"helm.sh/helm/pkg/ignore"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
)
|
||||
|
||||
// Run `go generate` to deterministically create the patched Helm deployment for cilium
|
||||
|
@ -33,17 +36,18 @@ var HelmFS embed.FS
|
|||
|
||||
type ChartLoader struct{}
|
||||
|
||||
func (i *ChartLoader) Load(csp cloudprovider.Provider, conformanceMode bool) ([]byte, error) {
|
||||
func (i *ChartLoader) Load(csp cloudprovider.Provider, conformanceMode bool, masterSecret []byte, salt []byte) ([]byte, error) {
|
||||
ciliumRelease, err := i.loadCilium(csp, conformanceMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kmsRelease, err := i.loadKMS()
|
||||
conServicesRelease, err := i.loadConstellationServices(masterSecret, salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
releases := helm.Releases{Cilium: ciliumRelease, KMS: kmsRelease}
|
||||
releases := helm.Releases{Cilium: ciliumRelease, ConstellationServices: conServicesRelease}
|
||||
|
||||
rel, err := json.Marshal(releases)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -54,8 +58,14 @@ func (i *ChartLoader) Load(csp cloudprovider.Provider, conformanceMode bool) ([]
|
|||
func (i *ChartLoader) loadCilium(csp cloudprovider.Provider, conformanceMode bool) (helm.Release, error) {
|
||||
chart, err := loadChartsDir(HelmFS, "charts/cilium")
|
||||
if err != nil {
|
||||
return helm.Release{}, err
|
||||
return helm.Release{}, fmt.Errorf("loading cilium chart: %w", err)
|
||||
}
|
||||
|
||||
chartRaw, err := i.marshalChart(chart)
|
||||
if err != nil {
|
||||
return helm.Release{}, fmt.Errorf("packaging chart: %w", err)
|
||||
}
|
||||
|
||||
var ciliumVals map[string]interface{}
|
||||
switch csp {
|
||||
case cloudprovider.GCP:
|
||||
|
@ -77,27 +87,54 @@ func (i *ChartLoader) loadCilium(csp cloudprovider.Provider, conformanceMode boo
|
|||
|
||||
}
|
||||
|
||||
return helm.Release{Chart: chart, Values: ciliumVals, ReleaseName: "cilium", Wait: true}, nil
|
||||
return helm.Release{Chart: chartRaw, Values: ciliumVals, ReleaseName: "cilium", Wait: true}, nil
|
||||
}
|
||||
|
||||
func (i *ChartLoader) loadKMS() (helm.Release, error) {
|
||||
chart, err := loadChartsDir(HelmFS, "charts/edgeless/kms")
|
||||
func (i *ChartLoader) loadConstellationServices(masterSecret []byte, salt []byte) (helm.Release, error) {
|
||||
chart, err := loadChartsDir(HelmFS, "charts/edgeless/constellation-services")
|
||||
if err != nil {
|
||||
return helm.Release{}, err
|
||||
}
|
||||
kmsVals := map[string]interface{}{
|
||||
"namespace": constants.ConstellationNamespace,
|
||||
"kmsPort": constants.KMSPort,
|
||||
"joinConfigCMName": constants.JoinConfigMap,
|
||||
"serviceBasePath": constants.ServiceBasePath,
|
||||
"kmsImage": versions.KmsImage,
|
||||
"masterSecretName": constants.ConstellationMasterSecretStoreName,
|
||||
"masterSecretKeyName": constants.ConstellationMasterSecretKey,
|
||||
"saltKeyName": constants.ConstellationSaltKey,
|
||||
"measurementsFilename": constants.MeasurementsFilename,
|
||||
return helm.Release{}, fmt.Errorf("loading constellation-services chart: %w", err)
|
||||
}
|
||||
|
||||
return helm.Release{Chart: chart, Values: kmsVals, ReleaseName: "kms", Wait: true}, nil
|
||||
chartRaw, err := i.marshalChart(chart)
|
||||
if err != nil {
|
||||
return helm.Release{}, fmt.Errorf("packaging chart: %w", err)
|
||||
}
|
||||
|
||||
vals := map[string]interface{}{
|
||||
"kms": map[string]interface{}{
|
||||
"namespace": constants.ConstellationNamespace,
|
||||
"port": constants.KMSPort,
|
||||
"joinConfigCMName": constants.JoinConfigMap,
|
||||
"serviceBasePath": constants.ServiceBasePath,
|
||||
"image": versions.KmsImage,
|
||||
"masterSecretName": constants.ConstellationMasterSecretStoreName,
|
||||
"masterSecretKeyName": constants.ConstellationMasterSecretKey,
|
||||
"saltKeyName": constants.ConstellationSaltKey,
|
||||
"measurementsFilename": constants.MeasurementsFilename,
|
||||
"masterSecret": base64.StdEncoding.EncodeToString(masterSecret),
|
||||
"salt": base64.StdEncoding.EncodeToString(salt),
|
||||
},
|
||||
}
|
||||
|
||||
return helm.Release{Chart: chartRaw, Values: vals, ReleaseName: "constellation-services", Wait: true}, nil
|
||||
}
|
||||
|
||||
// marshalChart takes a Chart object, packages it to a temporary file and returns the content of that file.
|
||||
// We currently need to take this approach of marshaling as dependencies are not marshaled correctly with json.Marshal.
|
||||
// This stems from the fact that chart.Chart does not export the dependencies property.
|
||||
// See: https://github.com/helm/helm/issues/11454
|
||||
func (i *ChartLoader) marshalChart(chart *chart.Chart) ([]byte, error) {
|
||||
path, err := chartutil.Save(chart, os.TempDir())
|
||||
defer os.Remove(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("packaging chart: %w", err)
|
||||
}
|
||||
chartRaw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading packaged chart: %w", err)
|
||||
}
|
||||
return chartRaw, nil
|
||||
}
|
||||
|
||||
// taken from loader.LoadDir from the helm go module
|
||||
|
|
34
cli/internal/helm/loader_test.go
Normal file
34
cli/internal/helm/loader_test.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package helm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
)
|
||||
|
||||
func TestLoad(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
chartLoader := ChartLoader{}
|
||||
release, err := chartLoader.Load(cloudprovider.GCP, true, []byte("secret"), []byte("salt"))
|
||||
assert.NoError(err)
|
||||
|
||||
var helmReleases helm.Releases
|
||||
err = json.Unmarshal(release, &helmReleases)
|
||||
assert.NoError(err)
|
||||
reader := bytes.NewReader(helmReleases.ConstellationServices.Chart)
|
||||
chart, err := loader.LoadArchive(reader)
|
||||
assert.NoError(err)
|
||||
assert.NotNil(chart.Dependencies())
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue