From be618e41890dbd9311ef0b5e828c65f3599a56ea Mon Sep 17 00:00:00 2001 From: Andrew Lavery Date: Fri, 3 Dec 2021 17:19:20 -0500 Subject: [PATCH 1/2] move encryption keys to central store remove usages of 'cipher.Encrypt' change cipher.Decrypt to crypto.Decrypt make aesCipher struct private --- .../apis/kots/v1beta1/identityconfig_types.go | 20 +-- pkg/airgap/airgap.go | 3 +- pkg/airgap/update.go | 3 +- pkg/apiserver/bootstrap.go | 14 +- pkg/base/templates.go | 11 -- pkg/config/config.go | 1 - pkg/crypto/aes.go | 138 +++++++++++++++--- pkg/gitops/gitops.go | 13 +- pkg/handlers/config.go | 17 +-- pkg/handlers/identity.go | 23 +-- pkg/identity/deploy.go | 2 +- pkg/identity/deploy/deploy.go | 2 - pkg/identity/deploy/dex.go | 15 +- pkg/identity/deploy/postgres.go | 17 +-- pkg/kotsadm/secrets.go | 10 +- pkg/kotsadmidentity/identityconfig.go | 5 +- pkg/kotsadmupstream/upstream.go | 3 +- pkg/kotsutil/kots.go | 14 +- pkg/midstream/identity.go | 5 +- pkg/midstream/write.go | 2 - pkg/online/online.go | 3 +- pkg/pull/pull.go | 3 +- pkg/render/render.go | 3 +- pkg/rewrite/rewrite.go | 3 +- pkg/store/kotsstore/registry_store.go | 18 +-- pkg/template/builder.go | 6 +- pkg/template/config_context.go | 12 +- pkg/template/config_context_test.go | 11 +- pkg/template/identity_context.go | 9 +- pkg/template/identity_context_test.go | 5 +- pkg/upstream/fetch.go | 5 +- pkg/upstream/replicated.go | 28 ++-- pkg/upstream/replicated_test.go | 6 +- pkg/upstream/write.go | 34 ++--- 34 files changed, 209 insertions(+), 255 deletions(-) diff --git a/kotskinds/apis/kots/v1beta1/identityconfig_types.go b/kotskinds/apis/kots/v1beta1/identityconfig_types.go index 6675152f31..c82b7c91ef 100644 --- a/kotskinds/apis/kots/v1beta1/identityconfig_types.go +++ b/kotskinds/apis/kots/v1beta1/identityconfig_types.go @@ -47,13 +47,13 @@ type StringValueOrEncrypted struct { ValueEncrypted string `json:"valueEncrypted,omitempty" yaml:"valueEncrypted,omitempty"` } -func NewStringValueOrEncrypted(value string, cipher crypto.AESCipher) *StringValueOrEncrypted { +func NewStringValueOrEncrypted(value string) *StringValueOrEncrypted { v := &StringValueOrEncrypted{Value: value} - v.EncryptValue(cipher) + v.EncryptValue() return v } -func (v *StringValueOrEncrypted) GetValue(cipher crypto.AESCipher) (string, error) { +func (v *StringValueOrEncrypted) GetValue() (string, error) { if v == nil { return "", nil } @@ -62,17 +62,17 @@ func (v *StringValueOrEncrypted) GetValue(cipher crypto.AESCipher) (string, erro if err != nil { return "", errors.Wrap(err, "failed to base64 decode") } - result, err := cipher.Decrypt(b) + result, err := crypto.Decrypt(b) return string(result), errors.Wrap(err, "failed to decrypt") } return v.Value, nil } -func (v *StringValueOrEncrypted) EncryptValue(cipher crypto.AESCipher) { +func (v *StringValueOrEncrypted) EncryptValue() { if v.ValueEncrypted != "" && v.Value == "" { return } - v.ValueEncrypted = base64.StdEncoding.EncodeToString(cipher.Encrypt([]byte(v.Value))) + v.ValueEncrypted = base64.StdEncoding.EncodeToString(crypto.Encrypt([]byte(v.Value))) v.Value = "" } @@ -99,13 +99,13 @@ type DexConnectors struct { ValueFrom *DexConnectorsSource `json:"valueFrom,omitempty" yaml:"valueFrom,omitempty"` } -func (v *DexConnectors) GetValue(cipher crypto.AESCipher) ([]DexConnector, error) { +func (v *DexConnectors) GetValue() ([]DexConnector, error) { if v.ValueEncrypted != "" { b, err := base64.StdEncoding.DecodeString(v.ValueEncrypted) if err != nil { return nil, errors.Wrap(err, "failed to base64 decode") } - result, err := cipher.Decrypt(b) + result, err := crypto.Decrypt(b) if err != nil { return nil, errors.Wrap(err, "failed to decrypt") } @@ -118,7 +118,7 @@ func (v *DexConnectors) GetValue(cipher crypto.AESCipher) ([]DexConnector, error return v.Value, nil } -func (v *DexConnectors) EncryptValue(cipher crypto.AESCipher) error { +func (v *DexConnectors) EncryptValue() error { if v.ValueEncrypted != "" && len(v.Value) == 0 { return nil } @@ -127,7 +127,7 @@ func (v *DexConnectors) EncryptValue(cipher crypto.AESCipher) error { if err != nil { return err } - v.ValueEncrypted = base64.StdEncoding.EncodeToString(cipher.Encrypt(b)) + v.ValueEncrypted = base64.StdEncoding.EncodeToString(crypto.Encrypt(b)) v.Value = nil return nil } diff --git a/pkg/airgap/airgap.go b/pkg/airgap/airgap.go index 9f016812f3..cd51de9b89 100644 --- a/pkg/airgap/airgap.go +++ b/pkg/airgap/airgap.go @@ -16,7 +16,6 @@ import ( kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" "github.com/replicatedhq/kots/pkg/airgap/types" "github.com/replicatedhq/kots/pkg/archives" - "github.com/replicatedhq/kots/pkg/crypto" kotsadmconfig "github.com/replicatedhq/kots/pkg/kotsadmconfig" identity "github.com/replicatedhq/kots/pkg/kotsadmidentity" "github.com/replicatedhq/kots/pkg/kotsutil" @@ -180,7 +179,7 @@ func CreateAppFromAirgap(opts CreateAirgapAppOpts) (finalError error) { configFile = tmpFile.Name() } - identityConfigFile, err := identity.InitAppIdentityConfig(opts.PendingApp.Slug, kotsv1beta1.Storage{}, crypto.AESCipher{}) + identityConfigFile, err := identity.InitAppIdentityConfig(opts.PendingApp.Slug, kotsv1beta1.Storage{}) if err != nil { return errors.Wrap(err, "failed to init identity config") } diff --git a/pkg/airgap/update.go b/pkg/airgap/update.go index d58d709f87..805aaf7974 100644 --- a/pkg/airgap/update.go +++ b/pkg/airgap/update.go @@ -12,7 +12,6 @@ import ( "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" apptypes "github.com/replicatedhq/kots/pkg/app/types" - "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/cursor" identity "github.com/replicatedhq/kots/pkg/kotsadmidentity" "github.com/replicatedhq/kots/pkg/kotsutil" @@ -142,7 +141,7 @@ func UpdateAppFromPath(a *apptypes.App, airgapRoot string, airgapBundlePath stri identityConfigFile := filepath.Join(archiveDir, "upstream", "userdata", "identityconfig.yaml") if _, err := os.Stat(identityConfigFile); os.IsNotExist(err) { - file, err := identity.InitAppIdentityConfig(a.Slug, kotsv1beta1.Storage{}, crypto.AESCipher{}) + file, err := identity.InitAppIdentityConfig(a.Slug, kotsv1beta1.Storage{}) if err != nil { return errors.Wrap(err, "failed to init identity config") } diff --git a/pkg/apiserver/bootstrap.go b/pkg/apiserver/bootstrap.go index 4be7979698..aa3cd96cbc 100644 --- a/pkg/apiserver/bootstrap.go +++ b/pkg/apiserver/bootstrap.go @@ -7,10 +7,8 @@ import ( "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" identity "github.com/replicatedhq/kots/pkg/kotsadmidentity" identitystore "github.com/replicatedhq/kots/pkg/kotsadmidentity/store" - "github.com/replicatedhq/kots/pkg/kotsutil" "github.com/replicatedhq/kots/pkg/store" "k8s.io/client-go/kubernetes/scheme" ) @@ -113,17 +111,7 @@ func bootstrapIdentity() error { } identityConfig := obj.(*kotsv1beta1.IdentityConfig) - installation, err := kotsutil.LoadInstallationFromPath(filepath.Join(currentArchivePath, "upstream", "userdata", "installation.yaml")) - if err != nil { - return errors.Wrap(err, "failed to load installation from path") - } - - apiCipher, err := crypto.AESCipherFromString(installation.Spec.EncryptionKey) - if err != nil { - return errors.Wrap(err, "failed to create aes cipher") - } - - identityConfigFile, err = identity.InitAppIdentityConfig(app.Slug, identityConfig.Spec.Storage, *apiCipher) + identityConfigFile, err = identity.InitAppIdentityConfig(app.Slug, identityConfig.Spec.Storage) if err != nil { return errors.Wrap(err, "failed to init identity config") } diff --git a/pkg/base/templates.go b/pkg/base/templates.go index aa6c87d088..35774684cc 100644 --- a/pkg/base/templates.go +++ b/pkg/base/templates.go @@ -3,7 +3,6 @@ package base import ( "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/template" upstreamtypes "github.com/replicatedhq/kots/pkg/upstream/types" ) @@ -30,15 +29,6 @@ func NewConfigContextTemplateBuilder(u *upstreamtypes.Upstream, renderOptions *R templateContext = map[string]template.ItemValue{} } - var cipher *crypto.AESCipher - if u.EncryptionKey != "" { - c, err := crypto.AESCipherFromString(u.EncryptionKey) - if err != nil { - return nil, nil, errors.Wrap(err, "failed to create cipher") - } - cipher = c - } - configGroups := []kotsv1beta1.ConfigGroup{} if kotsKinds.Config != nil { configGroups = kotsKinds.Config.Spec.Groups @@ -69,7 +59,6 @@ func NewConfigContextTemplateBuilder(u *upstreamtypes.Upstream, renderOptions *R ConfigGroups: configGroups, ExistingValues: templateContext, LocalRegistry: localRegistry, - Cipher: cipher, License: kotsKinds.License, Application: &kotsKinds.KotsApplication, VersionInfo: &versionInfo, diff --git a/pkg/config/config.go b/pkg/config/config.go index e8928172f8..ca382383fb 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -47,7 +47,6 @@ func templateConfigObjects(configSpec *kotsv1beta1.Config, configValues map[stri ConfigGroups: configSpec.Spec.Groups, ExistingValues: configValues, LocalRegistry: localRegistry, - Cipher: nil, License: license, Application: app, VersionInfo: versionInfo, diff --git a/pkg/crypto/aes.go b/pkg/crypto/aes.go index d70d524a7c..09f6cb81a1 100644 --- a/pkg/crypto/aes.go +++ b/pkg/crypto/aes.go @@ -1,15 +1,21 @@ package crypto import ( + "bytes" + "context" "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" + "fmt" + "os" "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" ) -type AESCipher struct { +type aesCipher struct { key []byte cipher cipher.AEAD nonce []byte @@ -17,35 +23,112 @@ type AESCipher struct { const keyLength = 24 // 192 bit -func NewAESCipher() (*AESCipher, error) { +var decryptionCiphers []*aesCipher // used to decrypt data +var encryptionCipher *aesCipher // used to encrypt data + +// add cipher from API_ENCRYPTION_KEY environment variable if it is present (and set that key to be used for encryption) +func init() { + decryptionCiphers = []*aesCipher{} + if os.Getenv("API_ENCRYPTION_KEY") != "" { + envCipher, err := aesCipherFromString(os.Getenv("API_ENCRYPTION_KEY")) + if err != nil { + // do nothing + } else { + decryptionCiphers = append(decryptionCiphers, envCipher) + encryptionCipher = envCipher + } + } +} + +// InitFromSecret reads the encryption key from kubernetes and adds it to the list of decryptionCiphers, and sets this key to be used for encryption. +func InitFromSecret(clientset kubernetes.Interface, namespace string) error { + sec, err := clientset.CoreV1().Secrets(namespace).Get(context.Background(), "kotsadm-encryption", metav1.GetOptions{}) + if err != nil { + return errors.Wrap(err, "get kotsadm-encryption secret") + } + + secData, ok := sec.Data["encryptionKey"] + if !ok { + return fmt.Errorf("kotsadm-encryption secret in %s does not have member encryptionKey", namespace) + } + + secCipher, err := aesCipherFromString(string(secData)) + if err != nil { + return errors.Wrap(err, "parse kotsadm-encryption secret") + } + + addCipher(secCipher) + encryptionCipher = secCipher + + return nil +} + +// InitFromString parses the encryption key from the provided string and adds it to the list of decryptionCiphers +func InitFromString(data string) error { + if data == "" { + return nil + } + + newCipher, err := aesCipherFromString(data) + if err != nil { + return err + } + addCipher(newCipher) + return nil +} + +// check if a cipher exists in the array, if it does not then add it +func addCipher(aesCipher *aesCipher) { + foundMatch := false + for _, existingCipher := range decryptionCiphers { + if bytes.Compare(existingCipher.key, aesCipher.key) == 0 && bytes.Compare(existingCipher.nonce, aesCipher.nonce) == 0 { + foundMatch = true + } + } + + if !foundMatch { + decryptionCiphers = append(decryptionCiphers, aesCipher) + } +} + +// NewAESCipher creates a new AES cipher to be used for encryption and decryption. If one already exists, it is used instead. +func NewAESCipher() error { + if encryptionCipher != nil && len(decryptionCiphers) >= 1 { + return nil + } + key := make([]byte, keyLength) if _, err := rand.Read(key); err != nil { - return nil, errors.Wrap(err, "failed to read key") + return errors.Wrap(err, "failed to read key") } block, err := aes.NewCipher(key) if err != nil { - return nil, errors.Wrap(err, "failed ro create new cipher") + return errors.Wrap(err, "failed to create new cipher") } gcm, err := cipher.NewGCM(block) if err != nil { - return nil, errors.Wrap(err, "failed to wrap cipher gcm") + return errors.Wrap(err, "failed to wrap cipher gcm") } nonce := make([]byte, gcm.NonceSize()) if _, err := rand.Read(nonce); err != nil { - return nil, errors.Wrap(err, "failed to read nonce") + return errors.Wrap(err, "failed to read nonce") } - return &AESCipher{ + newCipher := &aesCipher{ key: key, cipher: gcm, nonce: nonce, - }, nil + } + + addCipher(newCipher) + encryptionCipher = newCipher + return nil } -func AESCipherFromString(data string) (aesCipher *AESCipher, initErr error) { +func aesCipherFromString(data string) (newCipher *aesCipher, initErr error) { defer func() { if r := recover(); r != nil { initErr = errors.Errorf("cipher init recovered from panic: %v", r) @@ -82,7 +165,7 @@ func AESCipherFromString(data string) (aesCipher *AESCipher, initErr error) { return } - aesCipher = &AESCipher{ + newCipher = &aesCipher{ key: key, cipher: gcm, nonce: decoded[keyLength:], @@ -91,18 +174,15 @@ func AESCipherFromString(data string) (aesCipher *AESCipher, initErr error) { return } -func (c *AESCipher) ToString() string { - if c == nil { +// ToString returns a string representation of the global encryption key +func ToString() string { + if encryptionCipher == nil { return "" } - return base64.StdEncoding.EncodeToString(append(c.key, c.nonce...)) + return base64.StdEncoding.EncodeToString(append(encryptionCipher.key, encryptionCipher.nonce...)) } -func (c *AESCipher) Encrypt(in []byte) []byte { - return c.cipher.Seal(nil, c.nonce, in, nil) -} - -func (c *AESCipher) Decrypt(in []byte) (result []byte, err error) { +func (c *aesCipher) decrypt(in []byte) (result []byte, err error) { defer func() { if r := recover(); r != nil { err = errors.Errorf("decrypt recovered from panic: %v", r) @@ -112,3 +192,25 @@ func (c *AESCipher) Decrypt(in []byte) (result []byte, err error) { result, err = c.cipher.Open(nil, c.nonce, in, nil) return } + +// Encrypt encrypts the data with the registered encryption key +func Encrypt(in []byte) []byte { + if encryptionCipher == nil { + _ = NewAESCipher() + } + + return encryptionCipher.cipher.Seal(nil, encryptionCipher.nonce, in, nil) +} + +// Decrypt attempts to decrypt the provided data with all registered keys +func Decrypt(in []byte) (result []byte, err error) { + for _, decryptCipher := range decryptionCiphers { + result, err = decryptCipher.decrypt(in) + if err != nil { + continue + } else { + return result, nil + } + } + return nil, err +} diff --git a/pkg/gitops/gitops.go b/pkg/gitops/gitops.go index 10b0813196..2a1ccf8d24 100644 --- a/pkg/gitops/gitops.go +++ b/pkg/gitops/gitops.go @@ -162,16 +162,12 @@ func GetDownstreamGitOps(appID string, clusterID string) (*GitOpsConfig, error) } provider, publicKey, privateKey, repoURI, hostname, httpPort, sshPort := gitOpsConfigFromSecretData(idx, secret.Data) - cipher, err := crypto.AESCipherFromString(os.Getenv("API_ENCRYPTION_KEY")) - if err != nil { - return nil, errors.Wrap(err, "failed to create aes cipher") - } decodedPrivateKey, err := base64.StdEncoding.DecodeString(privateKey) if err != nil { return nil, errors.Wrap(err, "failed to decode") } - decryptedPrivateKey, err := cipher.Decrypt([]byte(decodedPrivateKey)) + decryptedPrivateKey, err := crypto.Decrypt([]byte(decodedPrivateKey)) if err != nil { return nil, errors.Wrap(err, "failed to decrypt") } @@ -453,12 +449,7 @@ func CreateGitOps(provider string, repoURI string, hostname string, httpPort str if err != nil { return errors.Wrap(err, "failed to generate key pair") } - - cipher, err := crypto.AESCipherFromString(os.Getenv("API_ENCRYPTION_KEY")) - if err != nil { - return errors.Wrap(err, "failed to create aes cipher") - } - encryptedPrivateKey := cipher.Encrypt([]byte(keyPair.PrivateKeyPEM)) + encryptedPrivateKey := crypto.Encrypt([]byte(keyPair.PrivateKeyPEM)) encodedPrivateKey := base64.StdEncoding.EncodeToString(encryptedPrivateKey) // encoding here shouldn't be needed. moved logic from TS where ffi EncryptString function base64 encodes the value as well secretData[fmt.Sprintf("provider.%d.privateKey", repoIdx)] = []byte(encodedPrivateKey) diff --git a/pkg/handlers/config.go b/pkg/handlers/config.go index b47dffd159..fdd2ff2e75 100644 --- a/pkg/handlers/config.go +++ b/pkg/handlers/config.go @@ -612,15 +612,10 @@ func updateAppConfigValues(values map[string]kotsv1beta1.ConfigValue, configGrou updatedValue := item.Value.String() if item.Type == "password" { // encrypt using the key - cipher, err := crypto.AESCipherFromString(encryptionKey) - if err != nil { - return nil, errors.Wrap(err, "failed to load encryption cipher") - } - // if the decryption succeeds, don't encrypt again - _, err = decrypt(updatedValue, cipher) + _, err := decrypt(updatedValue) if err != nil { - updatedValue = base64.StdEncoding.EncodeToString(cipher.Encrypt([]byte(updatedValue))) + updatedValue = base64.StdEncoding.EncodeToString(crypto.Encrypt([]byte(updatedValue))) } } @@ -647,17 +642,13 @@ func updateAppConfigValues(values map[string]kotsv1beta1.ConfigValue, configGrou } return values, nil } -func decrypt(input string, cipher *crypto.AESCipher) (string, error) { - if cipher == nil { - return "", errors.New("cipher not defined") - } - +func decrypt(input string) (string, error) { decoded, err := base64.StdEncoding.DecodeString(input) if err != nil { return "", errors.Wrap(err, "failed to base64 decode") } - decrypted, err := cipher.Decrypt(decoded) + decrypted, err := crypto.Decrypt(decoded) if err != nil { return "", errors.Wrap(err, "failed to decrypt") } diff --git a/pkg/handlers/identity.go b/pkg/handlers/identity.go index 052a2532d8..5398a06862 100644 --- a/pkg/handlers/identity.go +++ b/pkg/handlers/identity.go @@ -13,7 +13,6 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/identity" identitydeploy "github.com/replicatedhq/kots/pkg/identity/deploy" dextypes "github.com/replicatedhq/kots/pkg/identity/types/dex" @@ -297,7 +296,7 @@ func (h *Handler) ConfigureAppIdentityService(w http.ResponseWriter, r *http.Req identityConfigFile := filepath.Join(archiveDir, "upstream", "userdata", "identityconfig.yaml") if _, err := os.Stat(identityConfigFile); os.IsNotExist(err) { - f, err := kotsadmidentity.InitAppIdentityConfig(a.Slug, kotsv1beta1.Storage{}, crypto.AESCipher{}) + f, err := kotsadmidentity.InitAppIdentityConfig(a.Slug, kotsv1beta1.Storage{}) if err != nil { err = errors.Wrap(err, "failed to init identity config") logger.Error(err) @@ -330,15 +329,7 @@ func (h *Handler) ConfigureAppIdentityService(w http.ResponseWriter, r *http.Req } identityConfig := *s - cipher, err := crypto.AESCipherFromString(kotsKinds.Installation.Spec.EncryptionKey) - if err != nil { - err = errors.Wrap(err, "failed to load encryption cipher") - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - dexConnectors, err := identityConfig.Spec.DexConnectors.GetValue(*cipher) + dexConnectors, err := identityConfig.Spec.DexConnectors.GetValue() if err != nil { err = errors.Wrap(err, "failed to decrypt dex connectors") logger.Error(err) @@ -718,15 +709,7 @@ func (h *Handler) GetAppIdentityServiceConfig(w http.ResponseWriter, r *http.Req response.Enabled = kotsKinds.IdentityConfig.Spec.Enabled response.Groups = kotsKinds.IdentityConfig.Spec.Groups - cipher, err := crypto.AESCipherFromString(kotsKinds.Installation.Spec.EncryptionKey) - if err != nil { - err = errors.Wrap(err, "failed to load encryption cipher") - logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - dexConnectors, err := kotsKinds.IdentityConfig.Spec.DexConnectors.GetValue(*cipher) + dexConnectors, err := kotsKinds.IdentityConfig.Spec.DexConnectors.GetValue() if err != nil { err = errors.Wrap(err, "failed to decrypt dex connectors") logger.Error(err) diff --git a/pkg/identity/deploy.go b/pkg/identity/deploy.go index 2fda2858d6..aa03ca4e5c 100644 --- a/pkg/identity/deploy.go +++ b/pkg/identity/deploy.go @@ -48,7 +48,7 @@ func Deploy(ctx context.Context, clientset kubernetes.Interface, namespace strin Database: "dex", User: "dex", } - if err := identitydeploy.EnsurePostgresSecret(context.TODO(), clientset, namespace, KotsadmNamePrefix, nil, postgresConfig, nil); err != nil { + if err := identitydeploy.EnsurePostgresSecret(context.TODO(), clientset, namespace, KotsadmNamePrefix, postgresConfig, nil); err != nil { return errors.Wrap(err, "failed to ensure postgres secret") } } diff --git a/pkg/identity/deploy/deploy.go b/pkg/identity/deploy/deploy.go index 8452254334..9d278c6b88 100644 --- a/pkg/identity/deploy/deploy.go +++ b/pkg/identity/deploy/deploy.go @@ -9,7 +9,6 @@ import ( "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/identity/types" "github.com/replicatedhq/kots/pkg/image" "github.com/replicatedhq/kots/pkg/ingress" @@ -40,7 +39,6 @@ type Options struct { ImageRewriteFn kotsadmversion.ImageRewriteFunc ProxyEnv map[string]string AdditionalLabels map[string]string - Cipher *crypto.AESCipher Builder *template.Builder } diff --git a/pkg/identity/deploy/dex.go b/pkg/identity/deploy/dex.go index 46f64603cd..6f38f8072c 100644 --- a/pkg/identity/deploy/dex.go +++ b/pkg/identity/deploy/dex.go @@ -21,7 +21,6 @@ func getDexConfig(ctx context.Context, issuerURL string, options Options) ([]byt identitySpec := options.IdentitySpec identityConfigSpec := options.IdentityConfigSpec builder := options.Builder - cipher := options.Cipher redirectURIs, err := buildIdentitySpecOIDCRedirectURIs(identitySpec.OIDCRedirectURIs, builder) if err != nil { @@ -88,17 +87,9 @@ func getDexConfig(ctx context.Context, issuerURL string, options Options) ([]byt EnablePasswordDB: false, } - dexConnectors := []kotsv1beta1.DexConnector{} - if cipher != nil { - dexConnectors, err = identityConfigSpec.DexConnectors.GetValue(*cipher) - if err != nil { - return nil, errors.Wrap(err, "failed to decrypt dex connectors") - } - } else if identityConfigSpec.DexConnectors.ValueEncrypted != "" { - return nil, errors.New("cipher required") - } else { - // NOTE: we do not encrypt kotsadm config - dexConnectors = identityConfigSpec.DexConnectors.Value + dexConnectors, err := identityConfigSpec.DexConnectors.GetValue() + if err != nil { + return nil, errors.Wrap(err, "failed to decrypt dex connectors") } connectors := []kotsv1beta1.DexConnector{} diff --git a/pkg/identity/deploy/postgres.go b/pkg/identity/deploy/postgres.go index 2bf7fa24f2..d0832aed5c 100644 --- a/pkg/identity/deploy/postgres.go +++ b/pkg/identity/deploy/postgres.go @@ -6,7 +6,6 @@ import ( "github.com/pkg/errors" kotsv1beta "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" kotsadmtypes "github.com/replicatedhq/kots/pkg/kotsadm/types" "github.com/segmentio/ksuid" corev1 "k8s.io/api/core/v1" @@ -17,8 +16,8 @@ import ( "k8s.io/client-go/kubernetes/scheme" ) -func EnsurePostgresSecret(ctx context.Context, clientset kubernetes.Interface, namespace, namePrefix string, cipher *crypto.AESCipher, config kotsv1beta.IdentityPostgresConfig, additionalLabels map[string]string) error { - secret, err := postgresSecretResource(namePrefix, cipher, config, additionalLabels) +func EnsurePostgresSecret(ctx context.Context, clientset kubernetes.Interface, namespace, namePrefix string, config kotsv1beta.IdentityPostgresConfig, additionalLabels map[string]string) error { + secret, err := postgresSecretResource(namePrefix, config, additionalLabels) if err != nil { return err } @@ -47,10 +46,10 @@ func EnsurePostgresSecret(ctx context.Context, clientset kubernetes.Interface, n return nil } -func RenderPostgresSecret(ctx context.Context, namePrefix string, cipher *crypto.AESCipher, config kotsv1beta.IdentityPostgresConfig, additionalLabels map[string]string) ([]byte, error) { +func RenderPostgresSecret(ctx context.Context, namePrefix string, config kotsv1beta.IdentityPostgresConfig, additionalLabels map[string]string) ([]byte, error) { s := serializer.NewYAMLSerializer(serializer.DefaultMetaFactory, scheme.Scheme, scheme.Scheme) - secret, err := postgresSecretResource(namePrefix, cipher, config, additionalLabels) + secret, err := postgresSecretResource(namePrefix, config, additionalLabels) if err != nil { return nil, err } @@ -67,15 +66,11 @@ func GetPostgresSecret(ctx context.Context, clientset kubernetes.Interface, name return clientset.CoreV1().Secrets(namespace).Get(ctx, prefixName(namePrefix, "dex-postgres"), metav1.GetOptions{}) } -func postgresSecretResource(namePrefix string, cipher *crypto.AESCipher, config kotsv1beta.IdentityPostgresConfig, additionalLabels map[string]string) (*corev1.Secret, error) { +func postgresSecretResource(namePrefix string, config kotsv1beta.IdentityPostgresConfig, additionalLabels map[string]string) (*corev1.Secret, error) { password := "" if config.Password != nil { // NOTE: we do not encrypt kotsadm config - if cipher == nil && config.Password.ValueEncrypted != "" { - return nil, errors.New("cannot decrypt password without cipher") - } - - p, err := config.Password.GetValue(*cipher) + p, err := config.Password.GetValue() if err != nil { return nil, errors.Wrap(err, "failed to decrypt password") } diff --git a/pkg/kotsadm/secrets.go b/pkg/kotsadm/secrets.go index 52a7a73a13..f5a176b614 100644 --- a/pkg/kotsadm/secrets.go +++ b/pkg/kotsadm/secrets.go @@ -53,11 +53,11 @@ func getSecretsYAML(deployOptions *types.DeployOptions) (map[string][]byte, erro docs["secret-shared-password.yaml"] = sharedPassword.Bytes() if deployOptions.APIEncryptionKey == "" { - cipher, err := crypto.NewAESCipher() + err := crypto.NewAESCipher() if err != nil { return nil, errors.Wrap(err, "failed to create new API encryption key") } - deployOptions.APIEncryptionKey = cipher.ToString() + deployOptions.APIEncryptionKey = crypto.ToString() } var apiEncryptionBuffer bytes.Buffer if err := s.Encode(kotsadmobjects.ApiEncryptionKeySecret(deployOptions.Namespace, deployOptions.APIEncryptionKey), &apiEncryptionBuffer); err != nil { @@ -113,7 +113,7 @@ func ensureSecrets(deployOptions *types.DeployOptions, clientset *kubernetes.Cli Database: "dex", User: "dex", } - if err := identitydeploy.EnsurePostgresSecret(context.TODO(), clientset, deployOptions.Namespace, "kotsadm", nil, postgresConfig, nil); err != nil { + if err := identitydeploy.EnsurePostgresSecret(context.TODO(), clientset, deployOptions.Namespace, "kotsadm", postgresConfig, nil); err != nil { return errors.Wrap(err, "failed to ensure postgres secret for identity") } } @@ -320,11 +320,11 @@ func ensureAPIEncryptionSecret(deployOptions *types.DeployOptions, clientset *ku } if deployOptions.APIEncryptionKey == "" { - cipher, err := crypto.NewAESCipher() + err = crypto.NewAESCipher() if err != nil { return errors.Wrap(err, "failed to create new AES cipher") } - deployOptions.APIEncryptionKey = cipher.ToString() + deployOptions.APIEncryptionKey = crypto.ToString() } _, err = clientset.CoreV1().Secrets(deployOptions.Namespace).Create(context.TODO(), kotsadmobjects.ApiEncryptionKeySecret(deployOptions.Namespace, deployOptions.APIEncryptionKey), metav1.CreateOptions{}) diff --git a/pkg/kotsadmidentity/identityconfig.go b/pkg/kotsadmidentity/identityconfig.go index 5870d83020..076dd303c6 100644 --- a/pkg/kotsadmidentity/identityconfig.go +++ b/pkg/kotsadmidentity/identityconfig.go @@ -8,7 +8,6 @@ import ( "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/kotsadmidentity/store" "github.com/replicatedhq/kots/pkg/util" "github.com/segmentio/ksuid" @@ -31,7 +30,7 @@ func AppIdentityNeedsBootstrap(appSlug string) (bool, error) { return true, nil } -func InitAppIdentityConfig(appSlug string, storage kotsv1beta1.Storage, cipher crypto.AESCipher) (string, error) { +func InitAppIdentityConfig(appSlug string, storage kotsv1beta1.Storage) (string, error) { // support for the dev environment where app is in "test" namespace host := "kotsadm-postgres" if kotsadmNamespace := util.PodNamespace; kotsadmNamespace != "" { @@ -41,7 +40,7 @@ func InitAppIdentityConfig(appSlug string, storage kotsv1beta1.Storage, cipher c var postgresPassword string if storage.PostgresConfig != nil { var err error - postgresPassword, err = storage.PostgresConfig.Password.GetValue(cipher) + postgresPassword, err = storage.PostgresConfig.Password.GetValue() if err != nil { return "", errors.Wrap(err, "failed to get password value") } diff --git a/pkg/kotsadmupstream/upstream.go b/pkg/kotsadmupstream/upstream.go index 23c083475e..01e1f3ceec 100644 --- a/pkg/kotsadmupstream/upstream.go +++ b/pkg/kotsadmupstream/upstream.go @@ -10,7 +10,6 @@ import ( "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" identity "github.com/replicatedhq/kots/pkg/kotsadmidentity" "github.com/replicatedhq/kots/pkg/kotsutil" "github.com/replicatedhq/kots/pkg/logger" @@ -108,7 +107,7 @@ func DownloadUpdate(appID string, update types.Update, skipPreflights bool) (seq identityConfigFile := filepath.Join(archiveDir, "upstream", "userdata", "identityconfig.yaml") if _, err := os.Stat(identityConfigFile); os.IsNotExist(err) { - file, err := identity.InitAppIdentityConfig(a.Slug, kotsv1beta1.Storage{}, crypto.AESCipher{}) + file, err := identity.InitAppIdentityConfig(a.Slug, kotsv1beta1.Storage{}) if err != nil { return 0, errors.Wrap(err, "failed to init identity config") } diff --git a/pkg/kotsutil/kots.go b/pkg/kotsutil/kots.go index 474fedfd33..f24f37ad45 100644 --- a/pkg/kotsutil/kots.go +++ b/pkg/kotsutil/kots.go @@ -69,11 +69,6 @@ func (k *KotsKinds) EncryptConfigValues() error { return nil } - cipher, err := crypto.AESCipherFromString(k.Installation.Spec.EncryptionKey) - if err != nil { - return errors.Wrap(err, "failed to create cipher from installation spec") - } - updated := map[string]kotsv1beta1.ConfigValue{} for name, configValue := range k.ConfigValues.Spec.Values { @@ -100,7 +95,7 @@ func (k *KotsKinds) EncryptConfigValues() error { return errors.Errorf("Cannot encrypt item %q because item type was %q (not password)", name, configItemType) } - encrypted := cipher.Encrypt([]byte(configValue.ValuePlaintext)) + encrypted := crypto.Encrypt([]byte(configValue.ValuePlaintext)) encoded := base64.StdEncoding.EncodeToString(encrypted) configValue.Value = encoded @@ -120,11 +115,6 @@ func (k *KotsKinds) DecryptConfigValues() error { return nil } - cipher, err := crypto.AESCipherFromString(k.Installation.Spec.EncryptionKey) - if err != nil { - return errors.Wrap(err, "failed to create cipher from installation spec") - } - updated := map[string]kotsv1beta1.ConfigValue{} for name, configValue := range k.ConfigValues.Spec.Values { @@ -139,7 +129,7 @@ func (k *KotsKinds) DecryptConfigValues() error { if err != nil { continue } - decrypted, err := cipher.Decrypt(decoded) + decrypted, err := crypto.Decrypt(decoded) if err != nil { continue } diff --git a/pkg/midstream/identity.go b/pkg/midstream/identity.go index 73385404be..3683a678a1 100644 --- a/pkg/midstream/identity.go +++ b/pkg/midstream/identity.go @@ -42,7 +42,6 @@ func (m *Midstream) writeIdentityService(ctx context.Context, options WriteOptio ImageRewriteFn: nil, // TODO (ethan): do we rewrite in kustomization.images? ProxyEnv: proxyEnv, AdditionalLabels: additionalLabels, - Cipher: &options.Cipher, Builder: &options.Builder, } @@ -52,7 +51,7 @@ func (m *Midstream) writeIdentityService(ctx context.Context, options WriteOptio } if m.IdentityConfig.Spec.Storage.PostgresConfig != nil { - postgresSecretResource, err := identitydeploy.RenderPostgresSecret(ctx, options.AppSlug, &options.Cipher, *m.IdentityConfig.Spec.Storage.PostgresConfig, additionalLabels) + postgresSecretResource, err := identitydeploy.RenderPostgresSecret(ctx, options.AppSlug, *m.IdentityConfig.Spec.Storage.PostgresConfig, additionalLabels) if err != nil { return "", errors.Wrap(err, "failed to render postgres secret") } @@ -60,7 +59,7 @@ func (m *Midstream) writeIdentityService(ctx context.Context, options WriteOptio } if m.IdentityConfig.Spec.ClientID != "" { - clientSecret, err := m.IdentityConfig.Spec.ClientSecret.GetValue(options.Cipher) + clientSecret, err := m.IdentityConfig.Spec.ClientSecret.GetValue() if err != nil { return "", errors.Wrap(err, "failed to decrypt client secret") } diff --git a/pkg/midstream/write.go b/pkg/midstream/write.go index 3af8b8d3a2..29e5a610bc 100644 --- a/pkg/midstream/write.go +++ b/pkg/midstream/write.go @@ -8,7 +8,6 @@ import ( "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/disasterrecovery" "github.com/replicatedhq/kots/pkg/k8sutil" "github.com/replicatedhq/kots/pkg/template" @@ -29,7 +28,6 @@ type WriteOptions struct { AppSlug string IsGitOps bool IsOpenShift bool - Cipher crypto.AESCipher Builder template.Builder HTTPProxyEnvValue string HTTPSProxyEnvValue string diff --git a/pkg/online/online.go b/pkg/online/online.go index 4580025c43..770350086e 100644 --- a/pkg/online/online.go +++ b/pkg/online/online.go @@ -9,7 +9,6 @@ import ( "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" kotsadmconfig "github.com/replicatedhq/kots/pkg/kotsadmconfig" identity "github.com/replicatedhq/kots/pkg/kotsadmidentity" "github.com/replicatedhq/kots/pkg/kotsutil" @@ -119,7 +118,7 @@ func CreateAppFromOnline(pendingApp *types.PendingApp, upstreamURI string, isAut configFile = tmpFile.Name() } - identityConfigFile, err := identity.InitAppIdentityConfig(pendingApp.Slug, kotsv1beta1.Storage{}, crypto.AESCipher{}) + identityConfigFile, err := identity.InitAppIdentityConfig(pendingApp.Slug, kotsv1beta1.Storage{}) if err != nil { return nil, errors.Wrap(err, "failed to init identity config") } diff --git a/pkg/pull/pull.go b/pkg/pull/pull.go index a7161703c6..dec2fdc524 100644 --- a/pkg/pull/pull.go +++ b/pkg/pull/pull.go @@ -401,7 +401,7 @@ func Pull(upstreamURI string, pullOptions PullOptions) (string, error) { return "", errors.Wrap(err, "failed to load installation") } - cipher, err := crypto.AESCipherFromString(newInstallation.Spec.EncryptionKey) + err = crypto.InitFromString(newInstallation.Spec.EncryptionKey) if err != nil { return "", errors.Wrap(err, "failed to load encryption cipher") } @@ -410,7 +410,6 @@ func Pull(upstreamURI string, pullOptions PullOptions) (string, error) { AppSlug: pullOptions.AppSlug, IsGitOps: pullOptions.IsGitOps, IsOpenShift: k8sutil.IsOpenShift(clientset), - Cipher: *cipher, Builder: *builder, HTTPProxyEnvValue: pullOptions.HTTPProxyEnvValue, HTTPSProxyEnvValue: pullOptions.HTTPSProxyEnvValue, diff --git a/pkg/render/render.go b/pkg/render/render.go index 5298e35592..1fc3ba2970 100644 --- a/pkg/render/render.go +++ b/pkg/render/render.go @@ -71,7 +71,7 @@ func NewBuilder(kotsKinds *kotsutil.KotsKinds, registrySettings registrytypes.Re } } - appCipher, err := crypto.AESCipherFromString(kotsKinds.Installation.Spec.EncryptionKey) + err := crypto.InitFromString(kotsKinds.Installation.Spec.EncryptionKey) if err != nil { return nil, errors.Wrap(err, "failed to load encryption cipher") } @@ -91,7 +91,6 @@ func NewBuilder(kotsKinds *kotsutil.KotsKinds, registrySettings registrytypes.Re ConfigGroups: configGroups, ExistingValues: templateContextValues, LocalRegistry: localRegistry, - Cipher: appCipher, License: kotsKinds.License, Application: &kotsKinds.KotsApplication, ApplicationInfo: &appInfo, diff --git a/pkg/rewrite/rewrite.go b/pkg/rewrite/rewrite.go index 0e15aae47d..9a8a089127 100644 --- a/pkg/rewrite/rewrite.go +++ b/pkg/rewrite/rewrite.go @@ -200,7 +200,7 @@ func Rewrite(rewriteOptions RewriteOptions) error { return errors.Wrap(err, "failed to create new config context template builder") } - cipher, err := crypto.AESCipherFromString(rewriteOptions.Installation.Spec.EncryptionKey) + err = crypto.InitFromString(rewriteOptions.Installation.Spec.EncryptionKey) if err != nil { return errors.Wrap(err, "failed to create cipher from installation spec") } @@ -215,7 +215,6 @@ func Rewrite(rewriteOptions RewriteOptions) error { AppSlug: rewriteOptions.AppSlug, IsGitOps: rewriteOptions.IsGitOps, IsOpenShift: k8sutil.IsOpenShift(clientset), - Cipher: *cipher, Builder: *builder, HTTPProxyEnvValue: rewriteOptions.HTTPProxyEnvValue, HTTPSProxyEnvValue: rewriteOptions.HTTPSProxyEnvValue, diff --git a/pkg/store/kotsstore/registry_store.go b/pkg/store/kotsstore/registry_store.go index 24a2a9580e..b0e4b1c487 100644 --- a/pkg/store/kotsstore/registry_store.go +++ b/pkg/store/kotsstore/registry_store.go @@ -3,8 +3,6 @@ package kotsstore import ( "database/sql" "encoding/base64" - "os" - "github.com/pkg/errors" "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/logger" @@ -40,17 +38,12 @@ func (s *KOTSStore) GetRegistryDetailsForApp(appID string) (registrytypes.Regist return registrySettings, nil } - apiCipher, err := crypto.AESCipherFromString(os.Getenv("API_ENCRYPTION_KEY")) - if err != nil { - return registrytypes.RegistrySettings{}, errors.Wrap(err, "failed to load apiCipher") - } - decodedPassword, err := base64.StdEncoding.DecodeString(registrySettings.PasswordEnc) if err != nil { return registrytypes.RegistrySettings{}, errors.Wrap(err, "failed to decode") } - decryptedPassword, err := apiCipher.Decrypt([]byte(decodedPassword)) + decryptedPassword, err := crypto.Decrypt([]byte(decodedPassword)) if err != nil { return registrytypes.RegistrySettings{}, errors.Wrap(err, "failed to decrypt") } @@ -74,15 +67,10 @@ func (s *KOTSStore) UpdateRegistry(appID string, hostname string, username strin return errors.Wrap(err, "failed to update registry settings") } } else { - cipher, err := crypto.AESCipherFromString(os.Getenv("API_ENCRYPTION_KEY")) - if err != nil { - return errors.Wrap(err, "failed to create aes cipher") - } - - passwordEnc := base64.StdEncoding.EncodeToString(cipher.Encrypt([]byte(password))) + passwordEnc := base64.StdEncoding.EncodeToString(crypto.Encrypt([]byte(password))) query := `update app set registry_hostname = $1, registry_username = $2, registry_password_enc = $3, namespace = $4, registry_is_readonly = $5 where id = $6` - _, err = db.Exec(query, hostname, username, passwordEnc, namespace, isReadOnly, appID) + _, err := db.Exec(query, hostname, username, passwordEnc, namespace, isReadOnly, appID) if err != nil { return errors.Wrap(err, "failed to update registry settings") } diff --git a/pkg/template/builder.go b/pkg/template/builder.go index a3470e6dda..61fc5fc0f6 100644 --- a/pkg/template/builder.go +++ b/pkg/template/builder.go @@ -8,7 +8,6 @@ import ( "github.com/pkg/errors" kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/docker/registry" "github.com/replicatedhq/kots/pkg/k8sutil" ) @@ -26,7 +25,6 @@ type BuilderOptions struct { ConfigGroups []kotsv1beta1.ConfigGroup ExistingValues map[string]ItemValue LocalRegistry LocalRegistry - Cipher *crypto.AESCipher License *kotsv1beta1.License Application *kotsv1beta1.Application ApplicationInfo *ApplicationInfo @@ -57,7 +55,7 @@ func NewBuilder(opts BuilderOptions) (Builder, map[string]ItemValue, error) { slug = opts.ApplicationInfo.Slug } - configCtx, err := b.newConfigContext(opts.ConfigGroups, opts.ExistingValues, opts.LocalRegistry, opts.Cipher, + configCtx, err := b.newConfigContext(opts.ConfigGroups, opts.ExistingValues, opts.LocalRegistry, opts.License, opts.Application, opts.VersionInfo, dockerHubRegistry, slug) if err != nil { return Builder{}, nil, errors.Wrap(err, "create config context") @@ -68,7 +66,7 @@ func NewBuilder(opts BuilderOptions) (Builder, map[string]ItemValue, error) { licenseCtx{License: opts.License}, newKurlContext("base", "default"), // can be hardcoded because kurl always deploys to the default namespace newVersionCtx(opts.VersionInfo), - newIdentityCtx(opts.IdentityConfig, opts.ApplicationInfo, opts.Cipher), + newIdentityCtx(opts.IdentityConfig, opts.ApplicationInfo), configCtx, } return b, configCtx.ItemValues, nil diff --git a/pkg/template/config_context.go b/pkg/template/config_context.go index 8b7043ce2e..546d455e00 100644 --- a/pkg/template/config_context.go +++ b/pkg/template/config_context.go @@ -74,7 +74,7 @@ type ConfigCtx struct { } // newConfigContext creates and returns a context for template rendering -func (b *Builder) newConfigContext(configGroups []kotsv1beta1.ConfigGroup, existingValues map[string]ItemValue, localRegistry LocalRegistry, cipher *crypto.AESCipher, license *kotsv1beta1.License, app *kotsv1beta1.Application, info *VersionInfo, dockerHubRegistry registry.RegistryOptions, appSlug string) (*ConfigCtx, error) { +func (b *Builder) newConfigContext(configGroups []kotsv1beta1.ConfigGroup, existingValues map[string]ItemValue, localRegistry LocalRegistry, license *kotsv1beta1.License, app *kotsv1beta1.Application, info *VersionInfo, dockerHubRegistry registry.RegistryOptions, appSlug string) (*ConfigCtx, error) { configCtx := &ConfigCtx{ ItemValues: existingValues, LocalRegistry: localRegistry, @@ -103,7 +103,7 @@ func (b *Builder) newConfigContext(configGroups []kotsv1beta1.ConfigGroup, exist if configItem.Type == "password" { existingVal, ok := existingValues[configItem.Name] if ok && existingVal.HasValue() { - val, err := decrypt(existingVal.ValueStr(), cipher) + val, err := decrypt(existingVal.ValueStr()) if err == nil { existingVal.Value = val existingValues[configItem.Name] = existingVal @@ -397,17 +397,13 @@ func (ctx ConfigCtx) getConfigOptionValue(itemName string) (string, error) { return val.DefaultStr(), nil } -func decrypt(input string, cipher *crypto.AESCipher) (string, error) { - if cipher == nil { - return "", errors.New("cipher not defined") - } - +func decrypt(input string) (string, error) { decoded, err := base64.StdEncoding.DecodeString(input) if err != nil { return "", errors.Wrap(err, "failed to base64 decode") } - decrypted, err := cipher.Decrypt(decoded) + decrypted, err := crypto.Decrypt(decoded) if err != nil { return "", errors.Wrap(err, "failed to decrypt") } diff --git a/pkg/template/config_context_test.go b/pkg/template/config_context_test.go index 47531fbc00..bdeeb5d1aa 100644 --- a/pkg/template/config_context_test.go +++ b/pkg/template/config_context_test.go @@ -6,7 +6,6 @@ import ( kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" "github.com/replicatedhq/kots/kotskinds/multitype" - "github.com/replicatedhq/kots/pkg/crypto" "github.com/replicatedhq/kots/pkg/docker/registry" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -16,7 +15,6 @@ func TestBuilder_NewConfigContext(t *testing.T) { type args struct { configGroups []kotsv1beta1.ConfigGroup templateContext map[string]ItemValue - cipher *crypto.AESCipher license *kotsv1beta1.License } tests := []struct { @@ -29,7 +27,6 @@ func TestBuilder_NewConfigContext(t *testing.T) { args: args{ configGroups: []kotsv1beta1.ConfigGroup{}, templateContext: map[string]ItemValue{}, - cipher: nil, }, want: &ConfigCtx{ AppSlug: "app-slug", @@ -59,7 +56,6 @@ func TestBuilder_NewConfigContext(t *testing.T) { }, }, templateContext: map[string]ItemValue{}, - cipher: nil, }, want: &ConfigCtx{ AppSlug: "app-slug", @@ -98,7 +94,6 @@ func TestBuilder_NewConfigContext(t *testing.T) { Value: "replacedAbcItemValue", }, }, - cipher: nil, }, want: &ConfigCtx{ AppSlug: "app-slug", @@ -167,7 +162,6 @@ func TestBuilder_NewConfigContext(t *testing.T) { Value: "replacedAbcItemValue", }, }, - cipher: nil, }, want: &ConfigCtx{ AppSlug: "app-slug", @@ -257,7 +251,6 @@ func TestBuilder_NewConfigContext(t *testing.T) { Value: "overwritten default", }, }, - cipher: nil, }, want: &ConfigCtx{ AppSlug: "app-slug", @@ -290,7 +283,6 @@ func TestBuilder_NewConfigContext(t *testing.T) { Value: "item does not exist", }, }, - cipher: nil, }, want: &ConfigCtx{ AppSlug: "app-slug", @@ -339,7 +331,6 @@ func TestBuilder_NewConfigContext(t *testing.T) { }, }, templateContext: map[string]ItemValue{}, - cipher: nil, license: &kotsv1beta1.License{ Spec: kotsv1beta1.LicenseSpec{ Entitlements: map[string]kotsv1beta1.EntitlementField{ @@ -381,7 +372,7 @@ func TestBuilder_NewConfigContext(t *testing.T) { builder.AddCtx(StaticCtx{}) localRegistry := LocalRegistry{} - got, err := builder.newConfigContext(tt.args.configGroups, tt.args.templateContext, localRegistry, tt.args.cipher, tt.args.license, nil, nil, registry.RegistryOptions{}, "app-slug") + got, err := builder.newConfigContext(tt.args.configGroups, tt.args.templateContext, localRegistry, tt.args.license, nil, nil, registry.RegistryOptions{}, "app-slug") req.NoError(err) req.Equal(tt.want, got) }) diff --git a/pkg/template/identity_context.go b/pkg/template/identity_context.go index c4bfaab628..d216a76564 100644 --- a/pkg/template/identity_context.go +++ b/pkg/template/identity_context.go @@ -5,21 +5,18 @@ import ( "text/template" "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" - "github.com/replicatedhq/kots/pkg/crypto" identitytypes "github.com/replicatedhq/kots/pkg/identity/types" ) type identityCtx struct { identityConfig *v1beta1.IdentityConfig appInfo *ApplicationInfo - cipher *crypto.AESCipher } -func newIdentityCtx(identityConfig *v1beta1.IdentityConfig, appInfo *ApplicationInfo, cipher *crypto.AESCipher) identityCtx { +func newIdentityCtx(identityConfig *v1beta1.IdentityConfig, appInfo *ApplicationInfo) identityCtx { return identityCtx{ identityConfig: identityConfig, appInfo: appInfo, - cipher: cipher, } } @@ -50,10 +47,10 @@ func (ctx identityCtx) identityServiceClientID() string { } func (ctx identityCtx) identityServiceClientSecret() (string, error) { - if ctx.identityConfig == nil || ctx.cipher == nil { + if ctx.identityConfig == nil { return "", nil } - return ctx.identityConfig.Spec.ClientSecret.GetValue(*ctx.cipher) + return ctx.identityConfig.Spec.ClientSecret.GetValue() } func (ctx identityCtx) identityServiceRoles() map[string]interface{} { diff --git a/pkg/template/identity_context_test.go b/pkg/template/identity_context_test.go index a597f73b34..073e161ce5 100644 --- a/pkg/template/identity_context_test.go +++ b/pkg/template/identity_context_test.go @@ -11,7 +11,7 @@ import ( func TestIdentityContext(t *testing.T) { req := require.New(t) - cipher, err := crypto.NewAESCipher() + err := crypto.NewAESCipher() req.NoError(err) // a properly populated identityCtx - should return the appropriate values @@ -36,13 +36,12 @@ func TestIdentityContext(t *testing.T) { }, IdentityServiceAddress: "https://dex.kotsadmdevenv.com", ClientID: "client-id", - ClientSecret: kotsv1beta1.NewStringValueOrEncrypted("client-secret", *cipher), + ClientSecret: kotsv1beta1.NewStringValueOrEncrypted("client-secret"), }, }, appInfo: &ApplicationInfo{ Slug: "my-app", }, - cipher: cipher, } // an unpopulated identityCtx - should not error/panic diff --git a/pkg/upstream/fetch.go b/pkg/upstream/fetch.go index 510c56ddfb..cf8571c1d0 100644 --- a/pkg/upstream/fetch.go +++ b/pkg/upstream/fetch.go @@ -23,13 +23,11 @@ func downloadUpstream(upstreamURI string, fetchOptions *types.FetchOptions) (*ty return readFilesFromPath(upstreamURI) } - var cipher *crypto.AESCipher if fetchOptions.EncryptionKey != "" { - c, err := crypto.AESCipherFromString(fetchOptions.EncryptionKey) + err := crypto.InitFromString(fetchOptions.EncryptionKey) if err != nil { return nil, errors.Wrap(err, "failed to create cipher") } - cipher = c } u, err := url.ParseRequestURI(upstreamURI) @@ -50,7 +48,6 @@ func downloadUpstream(upstreamURI string, fetchOptions *types.FetchOptions) (*ty fetchOptions.IdentityConfig, pickCursor(fetchOptions), pickVersionLabel(fetchOptions), - cipher, fetchOptions.AppSlug, fetchOptions.AppSequence, fetchOptions.Airgap != nil, diff --git a/pkg/upstream/replicated.go b/pkg/upstream/replicated.go index a4fd0ff095..33e4bf1b67 100644 --- a/pkg/upstream/replicated.go +++ b/pkg/upstream/replicated.go @@ -22,7 +22,6 @@ import ( kotsv1beta1 "github.com/replicatedhq/kots/kotskinds/apis/kots/v1beta1" reportingtypes "github.com/replicatedhq/kots/pkg/api/reporting/types" "github.com/replicatedhq/kots/pkg/buildversion" - "github.com/replicatedhq/kots/pkg/crypto" kotslicense "github.com/replicatedhq/kots/pkg/license" reporting "github.com/replicatedhq/kots/pkg/reporting" "github.com/replicatedhq/kots/pkg/template" @@ -136,7 +135,6 @@ func downloadReplicated( existingIdentityConfig *kotsv1beta1.IdentityConfig, updateCursor ReplicatedCursor, versionLabel string, - cipher *crypto.AESCipher, appSlug string, appSequence int64, isAirgap bool, @@ -262,7 +260,7 @@ func downloadReplicated( // If config existed and was removed from the app, // values will be carried over to the new version anyway. - configValues, err := createConfigValues(application.Name, config, existingConfigValues, cipher, license, application, &appInfo, &versionInfo, localRegistry, existingIdentityConfig) + configValues, err := createConfigValues(application.Name, config, existingConfigValues, license, application, &appInfo, &versionInfo, localRegistry, existingIdentityConfig) if err != nil { return nil, errors.Wrap(err, "failed to create empty config values") } @@ -281,17 +279,16 @@ func downloadReplicated( } upstream := &types.Upstream{ - URI: u.RequestURI(), - Name: application.Name, - Files: files, - Type: "replicated", - UpdateCursor: release.UpdateCursor.Cursor, - ChannelID: channelID, - ChannelName: channelName, - VersionLabel: release.VersionLabel, - ReleaseNotes: release.ReleaseNotes, - ReleasedAt: release.ReleasedAt, - EncryptionKey: cipher.ToString(), + URI: u.RequestURI(), + Name: application.Name, + Files: files, + Type: "replicated", + UpdateCursor: release.UpdateCursor.Cursor, + ChannelID: channelID, + ChannelName: channelName, + VersionLabel: release.VersionLabel, + ReleaseNotes: release.ReleaseNotes, + ReleasedAt: release.ReleasedAt, } return upstream, nil @@ -585,7 +582,7 @@ func mustMarshalConfigValues(configValues *kotsv1beta1.ConfigValues) []byte { return b.Bytes() } -func createConfigValues(applicationName string, config *kotsv1beta1.Config, existingConfigValues *kotsv1beta1.ConfigValues, cipher *crypto.AESCipher, license *kotsv1beta1.License, app *kotsv1beta1.Application, appInfo *template.ApplicationInfo, versionInfo *template.VersionInfo, localRegistry template.LocalRegistry, identityConfig *kotsv1beta1.IdentityConfig) (*kotsv1beta1.ConfigValues, error) { +func createConfigValues(applicationName string, config *kotsv1beta1.Config, existingConfigValues *kotsv1beta1.ConfigValues, license *kotsv1beta1.License, app *kotsv1beta1.Application, appInfo *template.ApplicationInfo, versionInfo *template.VersionInfo, localRegistry template.LocalRegistry, identityConfig *kotsv1beta1.IdentityConfig) (*kotsv1beta1.ConfigValues, error) { templateContextValues := make(map[string]template.ItemValue) var newValues kotsv1beta1.ConfigValuesSpec @@ -627,7 +624,6 @@ func createConfigValues(applicationName string, config *kotsv1beta1.Config, exis ConfigGroups: config.Spec.Groups, ExistingValues: templateContextValues, LocalRegistry: localRegistry, - Cipher: cipher, License: license, Application: app, ApplicationInfo: appInfo, diff --git a/pkg/upstream/replicated_test.go b/pkg/upstream/replicated_test.go index 9791e0e897..9a70e8fb2f 100644 --- a/pkg/upstream/replicated_test.go +++ b/pkg/upstream/replicated_test.go @@ -251,13 +251,13 @@ func Test_createConfigValues(t *testing.T) { Default: "default_4", }, } - values1, err := createConfigValues(applicationName, config, nil, nil, nil, nil, appInfo, nil, template.LocalRegistry{}, nil) + values1, err := createConfigValues(applicationName, config, nil, nil, nil, appInfo, nil, template.LocalRegistry{}, nil) req.NoError(err) assert.Equal(t, expected1, values1.Spec.Values) // Like an app without a config, should have exact same values expected2 := configValues.Spec.Values - values2, err := createConfigValues(applicationName, nil, configValues, nil, nil, nil, appInfo, nil, template.LocalRegistry{}, nil) + values2, err := createConfigValues(applicationName, nil, configValues, nil, nil, appInfo, nil, template.LocalRegistry{}, nil) req.NoError(err) assert.Equal(t, expected2, values2.Spec.Values) @@ -278,7 +278,7 @@ func Test_createConfigValues(t *testing.T) { Default: "default_4", }, } - values3, err := createConfigValues(applicationName, config, configValues, nil, nil, nil, appInfo, nil, template.LocalRegistry{}, nil) + values3, err := createConfigValues(applicationName, config, configValues, nil, nil, appInfo, nil, template.LocalRegistry{}, nil) req.NoError(err) assert.Equal(t, expected3, values3.Spec.Values) } diff --git a/pkg/upstream/write.go b/pkg/upstream/write.go index 4b710fefa6..42c3720d6a 100644 --- a/pkg/upstream/write.go +++ b/pkg/upstream/write.go @@ -67,7 +67,7 @@ func WriteUpstream(u *types.Upstream, options types.WriteOptions) error { if err != nil { return errors.Wrap(err, "failed to get encryption key") } - u.EncryptionKey = encryptionKey + _ = crypto.InitFromString(encryptionKey) for i, file := range u.Files { fileRenderPath := path.Join(renderDir, file.Path) @@ -81,7 +81,7 @@ func WriteUpstream(u *types.Upstream, options types.WriteOptions) error { if options.EncryptConfig { configValues := contentToConfigValues(file.Content) if configValues != nil { - content, err := encryptConfigValues(configValues, encryptionKey) + content, err := encryptConfigValues(configValues) if err != nil { return errors.Wrap(err, "failed to encrypt config values") } @@ -92,7 +92,7 @@ func WriteUpstream(u *types.Upstream, options types.WriteOptions) error { identityConfig := contentToIdentityConfig(file.Content) if identityConfig != nil { - content, err := maybeEncryptIdentityConfig(identityConfig, encryptionKey) + content, err := maybeEncryptIdentityConfig(identityConfig) if err != nil { return errors.Wrap(err, "failed to encrypt identity config") } @@ -152,12 +152,7 @@ func WriteUpstream(u *types.Upstream, options types.WriteOptions) error { func getEncryptionKey(prevInstallation *kotsv1beta1.Installation) (string, error) { if prevInstallation == nil { - cipher, err := crypto.NewAESCipher() - if err != nil { - return "", errors.Wrap(err, "failed to create new AES cipher") - } - - return cipher.ToString(), nil + return "", nil } return prevInstallation.Spec.EncryptionKey, nil @@ -174,17 +169,13 @@ func mustMarshalInstallation(installation *kotsv1beta1.Installation) []byte { return b.Bytes() } -func encryptConfigValues(configValues *kotsv1beta1.ConfigValues, encryptionKey string) ([]byte, error) { - cipher, err := crypto.AESCipherFromString(encryptionKey) - if err != nil { - return nil, errors.Wrap(err, "failed to load encryption cipher") - } +func encryptConfigValues(configValues *kotsv1beta1.ConfigValues) ([]byte, error) { for k, v := range configValues.Spec.Values { if v.ValuePlaintext == "" { continue } - v.Value = base64.StdEncoding.EncodeToString(cipher.Encrypt([]byte(v.ValuePlaintext))) + v.Value = base64.StdEncoding.EncodeToString(crypto.Encrypt([]byte(v.ValuePlaintext))) v.ValuePlaintext = "" configValues.Spec.Values[k] = v @@ -200,19 +191,14 @@ func encryptConfigValues(configValues *kotsv1beta1.ConfigValues, encryptionKey s return b.Bytes(), nil } -func maybeEncryptIdentityConfig(identityConfig *kotsv1beta1.IdentityConfig, encryptionKey string) ([]byte, error) { - cipher, err := crypto.AESCipherFromString(encryptionKey) - if err != nil { - return nil, errors.Wrap(err, "failed to load encryption cipher") - } - - identityConfig.Spec.ClientSecret.EncryptValue(*cipher) +func maybeEncryptIdentityConfig(identityConfig *kotsv1beta1.IdentityConfig) ([]byte, error) { + identityConfig.Spec.ClientSecret.EncryptValue() if identityConfig.Spec.Storage.PostgresConfig != nil { - identityConfig.Spec.Storage.PostgresConfig.Password.EncryptValue(*cipher) + identityConfig.Spec.Storage.PostgresConfig.Password.EncryptValue() } - identityConfig.Spec.DexConnectors.EncryptValue(*cipher) + identityConfig.Spec.DexConnectors.EncryptValue() s := serializer.NewYAMLSerializer(serializer.DefaultMetaFactory, scheme.Scheme, scheme.Scheme) From 67ba2d1605497bbaf7ad7fb4643cfdd0f14788a4 Mon Sep 17 00:00:00 2001 From: Andrew Lavery Date: Wed, 8 Dec 2021 19:46:48 -0500 Subject: [PATCH 2/2] improve 'do nothing' comment --- pkg/crypto/aes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/crypto/aes.go b/pkg/crypto/aes.go index 09f6cb81a1..65bef6e079 100644 --- a/pkg/crypto/aes.go +++ b/pkg/crypto/aes.go @@ -32,7 +32,7 @@ func init() { if os.Getenv("API_ENCRYPTION_KEY") != "" { envCipher, err := aesCipherFromString(os.Getenv("API_ENCRYPTION_KEY")) if err != nil { - // do nothing + // do nothing - the secret can still be initialized from a different source } else { decryptionCiphers = append(decryptionCiphers, envCipher) encryptionCipher = envCipher