Skip to content

Commit

Permalink
ability to encode secrets as Java KeyStore
Browse files Browse the repository at this point in the history
Java requires using a "keystore" instead of just pem encoded certs.
So this adds the ability to emit a keystore file containing secrets.

in Files, you can now use the "jks" filter like

"Marbles": {
    "javathing": {
        "Parameters": {
            "Files": {
                "/app/keystore.jks": "{{ jks \"password\" .MarbleRun.MarbleCert.Cert }}",

fixes edgelesssys#307
  • Loading branch information
aep committed Jul 21, 2022
1 parent d32aac4 commit d4cafaa
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 0 deletions.
8 changes: 8 additions & 0 deletions coordinator/core/marbleapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ func TestParseSecrets(t *testing.T) {
_, err = parseSecrets("{{ hex .Secrets.emptysecret }}", manifest.ManifestFileTemplateFuncMap, testWrappedSecrets)
assert.Error(err)

// Test if we can encode as jks
parsedSecret, err = parseSecrets("{{ jks \"password\" .Secrets.testcertificate }}", manifest.ManifestFileTemplateFuncMap, testWrappedSecrets)
require.NoError(err)

testWrappedSecrets.Secrets = map[string]manifest.Secret{
"plainSecret": {Type: "plain", Public: []byte{1, 2, 3}},
"nullSecret": {Type: "plain", Public: []byte{0, 1, 2}},
Expand All @@ -441,6 +445,10 @@ func TestParseSecrets(t *testing.T) {
// non plain secrets always result in an error
_, err = parseSecrets("{{ string .Secrets.otherSecret }}", manifest.ManifestEnvTemplateFuncMap, testWrappedSecrets)
assert.Error(err)

// jks must fail encoding a symmetric key
_, err = parseSecrets("{{ jks \"password\" .Secrets.otherSecret }}", manifest.ManifestEnvTemplateFuncMap, testWrappedSecrets)
assert.Error(err)
}

func TestSecurityLevelUpdate(t *testing.T) {
Expand Down
55 changes: 55 additions & 0 deletions coordinator/manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package manifest

import (
"bytes"
"context"
"crypto/x509"
"encoding/base64"
Expand All @@ -15,8 +16,10 @@ import (
"encoding/pem"
"errors"
"fmt"
"github.com/pavlo-v-chernykh/keystore-go/v4"
"strings"
"text/template"
"time"

"github.com/edgelesssys/marblerun/coordinator/quote"
"github.com/edgelesssys/marblerun/coordinator/user"
Expand Down Expand Up @@ -477,12 +480,64 @@ func EncodeSecretDataToString(data interface{}) (string, error) {
}
}

// EncodeSecretsToJavaKeyStore encodes secrets as java keystore
func EncodeSecretsToJavaKeyStore(password string, secrets...Secret) (string, error) {
ks := keystore.New()

for i, secret := range secrets {
if secret.Type != "cert-rsa" && secret.Type != "cert-ed25519" && secret.Type != "cert-ecdsa" {
return "", errors.New("only RSA, ED25519 and ECDSA certificates can be encoded as Java keystore")
}

if len(secret.Cert.Raw) == 0 {
return "", errors.New("certificate is empty")
}

var alias = fmt.Sprintf("a%d", i)

err := ks.SetTrustedCertificateEntry(alias, keystore.TrustedCertificateEntry{
Certificate: keystore.Certificate{
Type: "X509",
Content: secret.Cert.Raw,
},
})
if err != nil {
return "", err
}

if secret.Private != nil {
pkeIn := keystore.PrivateKeyEntry{
CreationTime: time.Now(),
PrivateKey: secret.Private,
CertificateChain: []keystore.Certificate{
{
Type: "X509",
Content: secret.Cert.Raw,
},
},
}

if err := ks.SetPrivateKeyEntry(alias, pkeIn, []byte(password)); err != nil {
return "", err
}
}
}

var f bytes.Buffer
err := ks.Store(&f, []byte(password))
if err != nil {
return "", err
}
return f.String(), nil
}

// ManifestTemplateFuncMap defines the functions which can be specified for secret injections into files in the in Go template format.
var ManifestFileTemplateFuncMap = template.FuncMap{
"pem": EncodeSecretDataToPem,
"hex": EncodeSecretDataToHex,
"raw": EncodeSecretDataToRaw,
"base64": EncodeSecretDataToBase64,
"jks": EncodeSecretsToJavaKeyStore,
}

// ManifestEnvTemplateFuncMap defines the functions which can be specified for secret injections into Env variables in the Go template format.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,8 @@ github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xA
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.0 h1:y9azNmMzvkNBPyczpNRwaV4bm0U6e7Oyrj7gi2/SNFI=
github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.0/go.mod h1:lAVhWwbNaveeJmxrxuSTxMgKpF6DjnuVpn6T8WiBwYQ=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
Expand Down

0 comments on commit d4cafaa

Please sign in to comment.