From e6fb7429bf425f175cfea3d57dd80dbee7d2ea28 Mon Sep 17 00:00:00 2001 From: Ralf Pannemans Date: Wed, 10 May 2023 17:44:07 +0200 Subject: [PATCH] Copy trust store to /tmp to work with readonly fs Co-authored-by: Sumit Kulhadia --- helper/openssl_certificate_loader.go | 46 +++++++++++++++++++++-- helper/openssl_certificate_loader_test.go | 32 +++++++++++++++- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/helper/openssl_certificate_loader.go b/helper/openssl_certificate_loader.go index 8f3fd81..6f2a824 100644 --- a/helper/openssl_certificate_loader.go +++ b/helper/openssl_certificate_loader.go @@ -19,28 +19,68 @@ package helper import ( "fmt" "os" + "path/filepath" "github.com/paketo-buildpacks/libpak/bard" + "github.com/paketo-buildpacks/libpak/sherpa" + "golang.org/x/sys/unix" "github.com/paketo-buildpacks/libjvm" ) +var TmpTrustStore = filepath.Join(os.TempDir(), "truststore") + type OpenSSLCertificateLoader struct { CertificateLoader libjvm.CertificateLoader Logger bard.Logger } +func (o OpenSSLCertificateLoader) prepareTempTrustStore(trustStore, tempTrustStore string) (map[string]string, error) { + o.Logger.Infof("Using readonly truststore: %s", tempTrustStore) + + trustStoreFile, err := os.Open(trustStore) + if err != nil { + return nil, fmt.Errorf("unable to open trust store %s\n%w", trustStore, err) + } + defer trustStoreFile.Close() + + err = sherpa.CopyFile(trustStoreFile, tempTrustStore) + if err != nil { + return nil, fmt.Errorf("unable to copy dir (%s, %s)\n%w", trustStore, tempTrustStore, err) + } + + opts := sherpa.AppendToEnvVar("JAVA_TOOL_OPTIONS", " ", fmt.Sprintf("-Djavax.net.ssl.trustStore=%s", tempTrustStore)) + o.Logger.Debugf("changed JAVA_TOOL_OPTIONS: '%s'", opts) + + return map[string]string{"JAVA_TOOL_OPTIONS": opts}, nil +} + func (o OpenSSLCertificateLoader) Execute() (map[string]string, error) { - k, ok := os.LookupEnv("BPI_JVM_CACERTS") + trustStore, ok := os.LookupEnv("BPI_JVM_CACERTS") if !ok { return nil, fmt.Errorf("$BPI_JVM_CACERTS must be set") } + trustStoreWriteable := true + if unix.Access(trustStore, unix.W_OK) != nil { + trustStoreWriteable = false + } + + var opts map[string]string + if !trustStoreWriteable { + tmpOpts, err := o.prepareTempTrustStore(trustStore, TmpTrustStore) + if err == nil { + trustStore = TmpTrustStore + opts = tmpOpts + } + } + o.CertificateLoader.Logger = o.Logger.InfoWriter() - if err := o.CertificateLoader.Load(k, "changeit"); err != nil { + if err := o.CertificateLoader.Load(trustStore, "changeit"); err != nil { return nil, fmt.Errorf("unable to load certificates\n%w", err) } - return nil, nil + return opts, nil + } diff --git a/helper/openssl_certificate_loader_test.go b/helper/openssl_certificate_loader_test.go index 03bb44f..dd355ed 100644 --- a/helper/openssl_certificate_loader_test.go +++ b/helper/openssl_certificate_loader_test.go @@ -17,6 +17,7 @@ package helper_test import ( + "fmt" "io" "io/ioutil" "os" @@ -79,6 +80,7 @@ func testOpenSSLCertificateLoader(t *testing.T, context spec.G, it spec.S) { it.After(func() { Expect(os.Unsetenv("BPI_JVM_CACERTS")).To(Succeed()) + _ = os.Remove(helper.TmpTrustStore) }) it("loads additional certificates", func() { @@ -100,12 +102,37 @@ func testOpenSSLCertificateLoader(t *testing.T, context spec.G, it spec.S) { return } - it("does not return error when keystore is read-only", func() { + it("does use temp keystore if keystore is read-only", func() { Expect(os.Chmod(path, 0555)).To(Succeed()) o := helper.OpenSSLCertificateLoader{CertificateLoader: cl, Logger: bard.NewLogger(ioutil.Discard)} - Expect(o.Execute()).To(BeNil()) + env, err := o.Execute() + Expect(err).NotTo(HaveOccurred()) + + in, err := os.Open(helper.TmpTrustStore) + Expect(err).NotTo(HaveOccurred()) + defer in.Close() + + ks := keystore.New() + err = ks.Load(in, []byte("changeit")) + Expect(err).NotTo(HaveOccurred()) + Expect(ks.Aliases()).To(HaveLen(1)) + + Expect(env).To(HaveKeyWithValue("JAVA_TOOL_OPTIONS", fmt.Sprintf("-Djavax.net.ssl.trustStore=%s", helper.TmpTrustStore))) + }) + + it("does not return error when keystore and /tmp/truststore are read-only", func() { + Expect(os.Chmod(path, 0555)).To(Succeed()) + _, err := os.OpenFile(helper.TmpTrustStore, os.O_CREATE, 0) + Expect(err).NotTo(HaveOccurred()) + Expect(os.Chmod(helper.TmpTrustStore, 0555)).To(Succeed()) + + o := helper.OpenSSLCertificateLoader{CertificateLoader: cl, Logger: bard.NewLogger(os.Stdout)} + + env, err := o.Execute() + Expect(env).To(BeNil()) + Expect(err).NotTo(HaveOccurred()) in, err := os.Open(path) Expect(err).NotTo(HaveOccurred()) @@ -116,6 +143,7 @@ func testOpenSSLCertificateLoader(t *testing.T, context spec.G, it spec.S) { Expect(err).NotTo(HaveOccurred()) Expect(ks.Aliases()).To(HaveLen(1)) }) + }) }