diff --git a/cmd/kubeseal/main.go b/cmd/kubeseal/main.go index 167fb3593..517300597 100644 --- a/cmd/kubeseal/main.go +++ b/cmd/kubeseal/main.go @@ -167,7 +167,7 @@ func seal(in io.Reader, out io.Writer, codecs runtimeserializer.CodecFactory, pu return err } - if len(secret.Data) == 0 { + if len(secret.Data) == 0 && len(secret.StringData) == 0 { // No data. This is _theoretically_ just fine, but // almost certainly indicates a misuse of the tools. // If you _really_ want to encrypt an empty secret, diff --git a/cmd/kubeseal/main_test.go b/cmd/kubeseal/main_test.go index fcb30c5af..fee942659 100644 --- a/cmd/kubeseal/main_test.go +++ b/cmd/kubeseal/main_test.go @@ -133,6 +133,9 @@ func TestSeal(t *testing.T) { Data: map[string][]byte{ "foo": []byte("sekret"), }, + StringData: map[string]string{ + "foos": string("stringsekret"), + }, } info, ok := runtime.SerializerInfoForMediaType(scheme.Codecs.SupportedMediaTypes(), runtime.ContentTypeJSON) @@ -170,5 +173,8 @@ func TestSeal(t *testing.T) { if len(result.Spec.EncryptedData["foo"]) < 100 { t.Errorf("Encrypted data is implausibly short: %v", result.Spec.EncryptedData) } + if len(result.Spec.EncryptedData["foos"]) < 100 { + t.Errorf("Encrypted data is implausibly short: %v", result.Spec.EncryptedData) + } // NB: See sealedsecret_test.go for e2e crypto test } diff --git a/pkg/apis/sealed-secrets/v1alpha1/sealedsecret_expansion.go b/pkg/apis/sealed-secrets/v1alpha1/sealedsecret_expansion.go index 10f068439..5e4816020 100644 --- a/pkg/apis/sealed-secrets/v1alpha1/sealedsecret_expansion.go +++ b/pkg/apis/sealed-secrets/v1alpha1/sealedsecret_expansion.go @@ -115,6 +115,14 @@ func NewSealedSecret(codecs runtimeserializer.CodecFactory, pubKey *rsa.PublicKe s.Spec.EncryptedData[key] = base64.StdEncoding.EncodeToString(ciphertext) } + for key, value := range secret.StringData { + ciphertext, err := crypto.HybridEncrypt(rand.Reader, pubKey, []byte(value), label) + if err != nil { + return nil, err + } + s.Spec.EncryptedData[key] = base64.StdEncoding.EncodeToString(ciphertext) + } + if clusterWide { if s.Annotations == nil { s.Annotations = map[string]string{} diff --git a/pkg/apis/sealed-secrets/v1alpha1/sealedsecret_test.go b/pkg/apis/sealed-secrets/v1alpha1/sealedsecret_test.go index d6f4d4398..c8097b4ed 100644 --- a/pkg/apis/sealed-secrets/v1alpha1/sealedsecret_test.go +++ b/pkg/apis/sealed-secrets/v1alpha1/sealedsecret_test.go @@ -208,6 +208,59 @@ func TestSealRoundTrip(t *testing.T) { } } +func TestSealRoundTripStringDataConversion(t *testing.T) { + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + + SchemeBuilder.AddToScheme(scheme) + v1.SchemeBuilder.AddToScheme(scheme) + + rand := testRand() + key, err := rsa.GenerateKey(rand, 2048) + if err != nil { + t.Fatalf("Failed to generate test key: %v", err) + } + + secret := v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "myname", + Namespace: "myns", + }, + Data: map[string][]byte{ + "foo": []byte("bar"), + "fss": []byte("brr"), + }, + StringData: map[string]string{ + "fss": "baa", + }, + } + + unsealed := v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "myname", + Namespace: "myns", + }, + Data: map[string][]byte{ + "foo": []byte("bar"), + "fss": []byte("baa"), + }, + } + + ssecret, err := NewSealedSecret(codecs, &key.PublicKey, &secret) + if err != nil { + t.Fatalf("NewSealedSecret returned error: %v", err) + } + + secret2, err := ssecret.Unseal(codecs, key) + if err != nil { + t.Fatalf("Unseal returned error: %v", err) + } + + if !reflect.DeepEqual(unsealed.Data, secret2.Data) { + t.Errorf("Unsealed secret != original secret: %v != %v", unsealed, secret2) + } +} + func TestSealRoundTripWithClusterWide(t *testing.T) { scheme := runtime.NewScheme() codecs := serializer.NewCodecFactory(scheme)