Skip to content

Commit

Permalink
encrypt plain text passwords on initial install
Browse files Browse the repository at this point in the history
  • Loading branch information
divolgin committed Jul 28, 2020
1 parent d64c457 commit 69dcd33
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 18 deletions.
3 changes: 3 additions & 0 deletions pkg/pull/pull.go
Expand Up @@ -131,12 +131,14 @@ func Pull(upstreamURI string, pullOptions PullOptions) (string, error) {
fetchOptions.License = localLicense
}

encryptConfig := false
if pullOptions.ConfigFile != "" {
config, err := ParseConfigValuesFromFile(pullOptions.ConfigFile)
if err != nil {
return "", errors.Wrap(err, "failed to parse config values from file")
}
fetchOptions.ConfigValues = config
encryptConfig = true
} else {
fetchOptions.ConfigValues = localConfigValues
}
Expand Down Expand Up @@ -206,6 +208,7 @@ func Pull(upstreamURI string, pullOptions PullOptions) (string, error) {
CreateAppDir: pullOptions.CreateAppDir,
IncludeAdminConsole: includeAdminConsole,
SharedPassword: pullOptions.SharedPassword,
EncryptConfig: encryptConfig,
}
if err := upstream.WriteUpstream(u, writeUpstreamOptions); err != nil {
log.FinishSpinnerWithError()
Expand Down
28 changes: 19 additions & 9 deletions pkg/upstream/replicated.go
Expand Up @@ -493,8 +493,12 @@ func createConfigValues(applicationName string, config *kotsv1beta1.Config, exis
var newValues kotsv1beta1.ConfigValuesSpec
if existingConfigValues != nil {
for k, v := range existingConfigValues.Spec.Values {
value := v.Value
if value == "" {
value = v.ValuePlaintext
}
templateContextValues[k] = template.ItemValue{
Value: v.Value,
Value: value,
Default: v.Default,
}
}
Expand Down Expand Up @@ -532,10 +536,11 @@ func createConfigValues(applicationName string, config *kotsv1beta1.Config, exis

for _, group := range config.Spec.Groups {
for _, item := range group.Items {
var foundValue string
var foundValue, foundValuePlaintext string
prevValue, ok := newValues.Values[item.Name]
if ok && prevValue.Value != "" {
if ok {
foundValue = prevValue.Value
foundValuePlaintext = prevValue.ValuePlaintext
}

renderedValue, err := builder.RenderTemplate(item.Name, item.Value.String())
Expand All @@ -548,10 +553,11 @@ func createConfigValues(applicationName string, config *kotsv1beta1.Config, exis
return nil, errors.Wrap(err, "failed to render config item default")
}

if foundValue != "" {
if foundValue != "" || foundValuePlaintext != "" {
newValues.Values[item.Name] = kotsv1beta1.ConfigValue{
Value: foundValue,
Default: renderedDefault,
Value: foundValue,
ValuePlaintext: foundValuePlaintext,
Default: renderedDefault,
}
} else {
newValues.Values[item.Name] = kotsv1beta1.ConfigValue{
Expand Down Expand Up @@ -585,17 +591,21 @@ func findConfigValuesInFile(filename string) (*kotsv1beta1.ConfigValues, error)
return nil, errors.Wrap(err, "failed to open file")
}

return contentToConfigValues(content), nil
}

func contentToConfigValues(content []byte) *kotsv1beta1.ConfigValues {
decode := scheme.Codecs.UniversalDeserializer().Decode
obj, gvk, err := decode(content, nil, nil)
if err != nil {
return nil, nil
return nil
}

if gvk.Group == "kots.io" && gvk.Version == "v1beta1" && gvk.Kind == "ConfigValues" {
return obj.(*kotsv1beta1.ConfigValues), nil
return obj.(*kotsv1beta1.ConfigValues)
}

return nil, nil
return nil
}

func findTemplateContextDataInRelease(release *Release) (*kotsv1beta1.Config, *kotsv1beta1.ConfigValues, *kotsv1beta1.License, *kotsv1beta1.Installation, error) {
Expand Down
4 changes: 3 additions & 1 deletion pkg/upstream/types/types.go
Expand Up @@ -36,7 +36,9 @@ type WriteOptions struct {
// and should be false when it's an upstream update.
// When true, the channel name in Installation yaml will not be changed.
PreserveInstallation bool
SharedPassword string
// Set to true on initial installation when an unencrypted config file is provided
EncryptConfig bool
SharedPassword string
}

func (u *Upstream) GetUpstreamDir(options WriteOptions) string {
Expand Down
56 changes: 48 additions & 8 deletions pkg/upstream/write.go
Expand Up @@ -2,6 +2,7 @@ package upstream

import (
"bytes"
"encoding/base64"
"io/ioutil"
"os"
"path"
Expand All @@ -12,6 +13,7 @@ import (
"github.com/replicatedhq/kots/pkg/upstream/types"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
serializer "k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/client-go/kubernetes/scheme"
)

Expand Down Expand Up @@ -61,7 +63,13 @@ func WriteUpstream(u *types.Upstream, options types.WriteOptions) error {
prevInstallation = prevObj.(*kotsv1beta1.Installation)
}

for _, file := range u.Files {
encryptionKey, err := getEncryptionKey(prevInstallation)
if err != nil {
return errors.Wrap(err, "failed to get encryption key")
}
u.EncryptionKey = encryptionKey

for i, file := range u.Files {
fileRenderPath := path.Join(renderDir, file.Path)
d, _ := path.Split(fileRenderPath)
if _, err := os.Stat(d); os.IsNotExist(err) {
Expand All @@ -70,18 +78,23 @@ func WriteUpstream(u *types.Upstream, options types.WriteOptions) error {
}
}

if options.EncryptConfig {
configValues := contentToConfigValues(file.Content)
if configValues != nil {
content, err := encryptConfigValues(configValues, encryptionKey)
if err != nil {
return errors.Wrap(err, "encrypt config values")
}
file.Content = content
u.Files[i] = file
}
}

if err := ioutil.WriteFile(fileRenderPath, file.Content, 0644); err != nil {
return errors.Wrap(err, "failed to write upstream file")
}
}

// Write the installation status (update cursor, etc)
// but preserving the encryption key, if there already is one
encryptionKey, err := getEncryptionKey(prevInstallation)
if err != nil {
return errors.Wrap(err, "failed to get encryption key")
}

var channelName string
if prevInstallation != nil && options.PreserveInstallation {
channelName = prevInstallation.Spec.ChannelName
Expand All @@ -105,6 +118,7 @@ func WriteUpstream(u *types.Upstream, options types.WriteOptions) error {
EncryptionKey: encryptionKey,
},
}

if _, err := os.Stat(path.Join(renderDir, "userdata")); os.IsNotExist(err) {
if err := os.MkdirAll(path.Join(renderDir, "userdata"), 0755); err != nil {
return errors.Wrap(err, "failed to create userdata dir")
Expand Down Expand Up @@ -141,3 +155,29 @@ 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 craete cipher")
}
for k, v := range configValues.Spec.Values {
if v.ValuePlaintext == "" {
continue
}

v.Value = base64.StdEncoding.EncodeToString(cipher.Encrypt([]byte(v.ValuePlaintext)))
v.ValuePlaintext = ""

configValues.Spec.Values[k] = v
}

s := serializer.NewYAMLSerializer(serializer.DefaultMetaFactory, scheme.Scheme, scheme.Scheme)

var b bytes.Buffer
if err := s.Encode(configValues, &b); err != nil {
return nil, errors.Wrap(err, "failed to encode config values")
}

return b.Bytes(), nil
}

0 comments on commit 69dcd33

Please sign in to comment.