From c057fac315445788a1cd6ebb6f5563bf7b450e3d Mon Sep 17 00:00:00 2001 From: Otto Bittner Date: Thu, 23 Mar 2023 09:53:23 +0100 Subject: [PATCH] cli: idkeycfg upgrade migration TODO: revert this commit after v2.7 is released. --- cli/internal/helm/BUILD.bazel | 1 + cli/internal/helm/client.go | 84 ++++++++++++++++++++++++-------- cli/internal/helm/client_test.go | 5 +- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/cli/internal/helm/BUILD.bazel b/cli/internal/helm/BUILD.bazel index d5b2243e3..2056d4b9e 100644 --- a/cli/internal/helm/BUILD.bazel +++ b/cli/internal/helm/BUILD.bazel @@ -319,6 +319,7 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/cli/internal/helm", visibility = ["//cli:__subpackages__"], deps = [ + "//cli/internal/clusterid", "//internal/attestation/idkeydigest", "//internal/cloud/cloudprovider", "//internal/compatibility", diff --git a/cli/internal/helm/client.go b/cli/internal/helm/client.go index e7008d57e..2107be723 100644 --- a/cli/internal/helm/client.go +++ b/cli/internal/helm/client.go @@ -8,11 +8,14 @@ package helm import ( "context" + "encoding/json" "errors" "fmt" "strings" "time" + "github.com/edgelesssys/constellation/v2/cli/internal/clusterid" + "github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest" "github.com/edgelesssys/constellation/v2/internal/compatibility" "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/constants" @@ -128,8 +131,10 @@ func (c *Client) Upgrade(ctx context.Context, config *config.Config, timeout tim return fmt.Errorf("creating CR backup: %w", err) } + // TODO: v2.8: remove fileHanlder. + fileHandler := file.NewHandler(afero.NewOsFs()) for _, chart := range upgradeReleases { - err = c.upgradeRelease(ctx, timeout, config, chart, allowDestructive) + err = c.upgradeRelease(ctx, timeout, config, chart, allowDestructive, fileHandler) if err != nil { return fmt.Errorf("upgrading %s: %w", chart.Metadata.Name, err) } @@ -172,26 +177,9 @@ func (c *Client) currentVersion(release string) (string, error) { // ErrConfirmationMissing signals that an action requires user confirmation. var ErrConfirmationMissing = errors.New("action requires user confirmation") -// TODO: v2.8: remove. This function is only temporarily needed as a migration from 2.6 to 2.7. -// setAttestationVariant sets the attesationVariant value on verification-service and join-service value maps. -func setAttestationVariant(values map[string]any, variant string) error { - joinServiceVals, ok := values["join-service"].(map[string]any) - if !ok { - return errors.New("invalid join-service values") - } - joinServiceVals["attestationVariant"] = variant - - verifyServiceVals, ok := values["verification-service"].(map[string]any) - if !ok { - return errors.New("invalid verification-service values") - } - verifyServiceVals["attestationVariant"] = variant - - return nil -} - +// TODO: v2.8: remove fileHandler argument. func (c *Client) upgradeRelease( - ctx context.Context, timeout time.Duration, conf *config.Config, chart *chart.Chart, allowDestructive bool, + ctx context.Context, timeout time.Duration, conf *config.Config, chart *chart.Chart, allowDestructive bool, fileHandler file.Handler, ) error { // We need to load all values that can be statically loaded before merging them with the cluster // values. Otherwise the templates are not rendered correctly. @@ -232,6 +220,22 @@ func (c *Client) upgradeRelease( if err := setAttestationVariant(values, conf.AttestationVariant); err != nil { return fmt.Errorf("setting attestationVariant: %w", err) } + + // TODO: v2.8: remove from here... + // Manually setting idKeyConfig is required here since upgrade normally isn't allowed to change this value. + // However, to introduce the value into a 2.6 cluster for the first time we have to set it nevertheless. + var idFile clusterid.File + if err := fileHandler.ReadJSON(constants.ClusterIDsFileName, &idFile); err != nil { + return fmt.Errorf("reading cluster ID file: %w", err) + } + // Disallow users to set MAAFallback as ID key digest policy for upgrades, since it requires extra cloud resources. + if conf.IDKeyDigestPolicy() == idkeydigest.MAAFallback { + return fmt.Errorf("ID key digest policy %s is not supported for upgrades", conf.IDKeyDigestPolicy()) + } + if err := setIdkeyConfig(values, conf, idFile.AttestationURL); err != nil { + return fmt.Errorf("setting id key config: %w", err) + } + // TODO: v2.8: to here. default: return fmt.Errorf("unknown chart name: %s", chart.Metadata.Name) } @@ -301,6 +305,46 @@ func (c *Client) updateCRDs(ctx context.Context, chart *chart.Chart) error { return nil } +// TODO: v2.8: remove. This function is only temporarily needed as a migration from 2.6 to 2.7. +// setAttestationVariant sets the attesationVariant value on verification-service and join-service value maps. +func setAttestationVariant(values map[string]any, variant string) error { + joinServiceVals, ok := values["join-service"].(map[string]any) + if !ok { + return errors.New("invalid join-service values") + } + joinServiceVals["attestationVariant"] = variant + + verifyServiceVals, ok := values["verification-service"].(map[string]any) + if !ok { + return errors.New("invalid verification-service values") + } + verifyServiceVals["attestationVariant"] = variant + + return nil +} + +// TODO: v2.8: remove. This function is only temporarily needed as a migration from 2.6 to 2.7. +// setIdkeyConfig sets the idkeyconfig value on the join-service value maps. +func setIdkeyConfig(values map[string]any, config *config.Config, maaURL string) error { + joinServiceVals, ok := values["join-service"].(map[string]any) + if !ok { + return errors.New("invalid join-service values") + } + + idKeyCfg := idkeydigest.Config{ + IDKeyDigests: config.IDKeyDigests(), + EnforcementPolicy: config.IDKeyDigestPolicy(), + MAAURL: maaURL, + } + marshalledCfg, err := json.Marshal(idKeyCfg) + if err != nil { + return fmt.Errorf("marshalling id key digest config: %w", err) + } + joinServiceVals["idKeyConfig"] = string(marshalledCfg) + + return nil +} + type debugLog interface { Debugf(format string, args ...any) Sync() diff --git a/cli/internal/helm/client_test.go b/cli/internal/helm/client_test.go index bb3cdae5b..b4c07c9ce 100644 --- a/cli/internal/helm/client_test.go +++ b/cli/internal/helm/client_test.go @@ -13,7 +13,9 @@ import ( "github.com/edgelesssys/constellation/v2/internal/compatibility" "github.com/edgelesssys/constellation/v2/internal/config" + "github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/logger" + "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "helm.sh/helm/v3/pkg/chart" @@ -88,7 +90,8 @@ func TestUpgradeRelease(t *testing.T) { chart, err := loadChartsDir(helmFS, certManagerInfo.path) require.NoError(err) - err = client.upgradeRelease(context.Background(), 0, config.Default(), chart, tc.allowDestructive) + fileHandler := file.NewHandler(afero.NewMemMapFs()) + err = client.upgradeRelease(context.Background(), 0, config.Default(), chart, tc.allowDestructive, fileHandler) if tc.wantError { tc.assertCorrectError(t, err) return