From 3ba5715bcff79dcf761f4bb2ef4fb0dac2256363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Caba=C3=B1a?= <46539158+JU4N98@users.noreply.github.com> Date: Tue, 12 Dec 2023 20:05:54 -0300 Subject: [PATCH] Add JWT support (#85) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adds jwt update to posix. Signed-off-by: JU4N98 * Adds jwt support for windows, fixes lint errors. Signed-off-by: JU4N98 * Improves some messages. Signed-off-by: JU4N98 * Improves context handling. Signed-off-by: JU4N98 * Fixes typo. Signed-off-by: JU4N98 * Adds jsonFilename config and its warning and error. Signed-off-by: JU4N98 * adds suggested changes Signed-off-by: JU4N98 * Replaces errorf for fatalf. Signed-off-by: JU4N98 * Uses expiry time to renew JWT svid. Signed-off-by: JU4N98 * Creates separates files for JWT SVID and Bundles, updates README. Signed-off-by: JU4N98 * Fixes lint error. Signed-off-by: JU4N98 * Fixes bug in config.go validations, changes JWT files structure, updates README.md. Signed-off-by: JU4N98 * Adds suggested changes. Signed-off-by: JU4N98 * Refactors util files. Signed-off-by: JU4N98 * Updates README.md. Co-authored-by: Faisal Memon Signed-off-by: Juan Pablo Cabaña <46539158+JU4N98@users.noreply.github.com> * Updates README.md. Co-authored-by: Faisal Memon Signed-off-by: Juan Pablo Cabaña <46539158+JU4N98@users.noreply.github.com> * Updates README.md. Co-authored-by: Faisal Memon Signed-off-by: Juan Pablo Cabaña <46539158+JU4N98@users.noreply.github.com> * Updates README.md. Co-authored-by: Faisal Memon Signed-off-by: Juan Pablo Cabaña <46539158+JU4N98@users.noreply.github.com> * Moves RunDeamon into sidecar.go, refactors updateJWTSVID method. Signed-off-by: JU4N98 * Moves RunDaemon method just after New method. Signed-off-by: JU4N98 * Refactors createRetryIntervalFunc and updateJWTSVID. Signed-off-by: JU4N98 * Updates logs and README.md. Signed-off-by: JU4N98 * Updates README.md. Signed-off-by: JU4N98 * Corrects misplaced log. Signed-off-by: JU4N98 * Updates pkg/sidecar/sidecar.go Co-authored-by: Faisal Memon Signed-off-by: Juan Pablo Cabaña <46539158+JU4N98@users.noreply.github.com> * Updates pkg/sidecar/sidecar.go Co-authored-by: Faisal Memon Signed-off-by: Juan Pablo Cabaña <46539158+JU4N98@users.noreply.github.com> * Updates README.md Co-authored-by: Max Lambrecht Signed-off-by: Juan Pablo Cabaña <46539158+JU4N98@users.noreply.github.com> * Updates README.md Signed-off-by: JU4N98 * Adds tests for new conf fields. Signed-off-by: JU4N98 * Adds suggested validations. Signed-off-by: JU4N98 * Adds suggested changes. Signed-off-by: JU4N98 * Adds suggested changes. Signed-off-by: JU4N98 * Adds flexibility to JWT. Signed-off-by: JU4N98 * Updates writeJSON and error message. Signed-off-by: JU4N98 * Re use jwtSource, solve identation, add blank line. Signed-off-by: JU4N98 * Improves identation. Signed-off-by: JU4N98 --------- Signed-off-by: JU4N98 Signed-off-by: Juan Pablo Cabaña <46539158+JU4N98@users.noreply.github.com> Co-authored-by: Faisal Memon Co-authored-by: Max Lambrecht --- README.md | 31 +++-- pkg/sidecar/config.go | 40 +++++-- pkg/sidecar/config_test.go | 45 +++++--- pkg/sidecar/sidecar.go | 199 +++++++++++++++++++++++++++++++- pkg/sidecar/util_posix.go | 15 +-- pkg/sidecar/util_windows.go | 14 +-- test/fixture/config/helper.conf | 5 +- 7 files changed, 283 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 28a1d1e9..08f3dc07 100644 --- a/README.md +++ b/README.md @@ -16,17 +16,20 @@ If `-config` is not specified, the default value `helper.conf` is assumed. ## Configuration The configuration file is an [HCL](https://github.com/hashicorp/hcl) formatted file that defines the following configurations: - |Configuration | Description | Example Value | - |--------------------------|------------------------------------------------------------------------------------------------| ------------- | - |`agent_address` | Socket address of SPIRE Agent. | `"/tmp/agent.sock"` | - |`cmd` | The path to the process to launch. | `"ghostunnel"` | - |`cmd_args` | The arguments of the process to launch. | `"server --listen localhost:8002 --target localhost:8001--keystore certs/svid_key.pem --cacert certs/svid_bundle.pem --allow-uri-san spiffe://example.org/Database"` | - |`cert_dir` | Directory name to store the fetched certificates. This directory must be created previously. | `"certs"` | - |`add_intermediates_to_bundle`| Add intermediate certificates into Bundle file instead of SVID file. | `true` | - |`renew_signal` | The signal that the process to be launched expects to reload the certificates. It is not supported on Windows. | `"SIGUSR1"` | - |`svid_file_name` | File name to be used to store the X.509 SVID public certificate in PEM format. | `"svid.pem"` | - |`svid_key_file_name` | File name to be used to store the X.509 SVID private key and public certificate in PEM format. | `"svid_key.pem"` | - |`svid_bundle_file_name` | File name to be used to store the X.509 SVID Bundle in PEM format. | `"svid_bundle.pem"` | + | Configuration | Description | Example Value | + |-----------------------------|----------------------------------------------------------------------------------------------------------------| -------------------- | + |`agent_address` | Socket address of SPIRE Agent. | `"/tmp/agent.sock"` | + |`cmd` | The path to the process to launch. | `"ghostunnel"` | + |`cmd_args` | The arguments of the process to launch. | `"server --listen localhost:8002 --target localhost:8001--keystore certs/svid_key.pem --cacert certs/svid_bundle.pem --allow-uri-san spiffe://example.org/Database"` | + |`cert_dir` | Directory name to store the fetched certificates. This directory must be created previously. | `"certs"` | + |`add_intermediates_to_bundle`| Add intermediate certificates into Bundle file instead of SVID file. | `true` | + |`renew_signal` | The signal that the process to be launched expects to reload the certificates. It is not supported on Windows. | `"SIGUSR1"` | + |`svid_file_name` | File name to be used to store the X.509 SVID public certificate in PEM format. | `"svid.pem"` | + |`svid_key_file_name` | File name to be used to store the X.509 SVID private key and public certificate in PEM format. | `"svid_key.pem"` | + |`svid_bundle_file_name` | File name to be used to store the X.509 SVID Bundle in PEM format. | `"svid_bundle.pem"` | + |`jwt_audience` | JWT SVID audience. | `"your-audience"` | + |`jwt_svid_file_name` | File name to be used to store JWT SVID in Base64-encoded string. | `"jwt_svid.token"` | + |`jwt_bundle_file_name` | File name to be used to store JWT Bundle in JSON format. | `"jwt_bundle.json"` | ### Configuration example ``` @@ -38,6 +41,9 @@ renew_signal = "SIGUSR1" svid_file_name = "svid.pem" svid_key_file_name = "svid_key.pem" svid_bundle_file_name = "svid_bundle.pem" +jwt_audience = "your-audience" +jwt_svid_file_name = "jwt.token" +jwt_bundle_file_name = "bundle.json" ``` ### Windows example @@ -47,4 +53,7 @@ cert_dir = "certs" svid_file_name = "svid.pem" svid_key_file_name = "svid_key.pem" svid_bundle_file_name = "svid_bundle.pem" +jwt_audience = "your-audience" +jwt_svid_file_name = "jwt.token" +jwt_bundle_file_name = "bundle.json" ``` \ No newline at end of file diff --git a/pkg/sidecar/config.go b/pkg/sidecar/config.go index ed088c10..e83c30bd 100644 --- a/pkg/sidecar/config.go +++ b/pkg/sidecar/config.go @@ -30,6 +30,12 @@ type Config struct { SvidBundleFileNameDeprecated string `hcl:"svidBundleFileName"` RenewSignal string `hcl:"renew_signal"` RenewSignalDeprecated string `hcl:"renewSignal"` + + // JWT configuration + JWTAudience string `hcl:"jwt_audience"` + JWTSvidFilename string `hcl:"jwt_svid_file_name"` + JWTBundleFilename string `hcl:"jwt_bundle_file_name"` + // TODO: is there a reason for this to be exposed? and inside of config? ReloadExternalProcess func() error // TODO: is there a reason for this to be exposed? and inside of config? @@ -114,18 +120,34 @@ func ValidateConfig(c *Config) error { c.RenewSignal = c.RenewSignalDeprecated } - switch { - case c.SvidFileName == "": - return errors.New("svid_file_name is required") - case c.SvidKeyFileName == "": - return errors.New("svid_key_file_name is required") - case c.SvidBundleFileName == "": - return errors.New("svid_bundle_file_name is required") - default: - return nil + x509EmptyCount := countEmpty(c.SvidFileName, c.SvidBundleFileName, c.SvidKeyFileName) + jwtSVIDEmptyCount := countEmpty(c.JWTSvidFilename, c.JWTAudience) + jwtBundleEmptyCount := countEmpty(c.SvidBundleFileName) + if x509EmptyCount == 3 && jwtSVIDEmptyCount == 2 && jwtBundleEmptyCount == 1 { + return errors.New("at least one of the sets ('svid_file_name', 'svid_key_file_name', 'svid_bundle_file_name'), ('jwt_file_name', 'jwt_audience'), or ('jwt_bundle_file_name') must be fully specified") + } + + if x509EmptyCount != 0 && x509EmptyCount != 3 { + return errors.New("all or none of 'svid_file_name', 'svid_key_file_name', 'svid_bundle_file_name' must be specified") + } + + if jwtSVIDEmptyCount != 0 && jwtSVIDEmptyCount != 2 { + return errors.New("all or none of 'jwt_file_name', 'jwt_audience' must be specified") } + + return nil } func getWarning(s1 string, s2 string) string { return s1 + " will be deprecated, should be used as " + s2 } + +func countEmpty(configs ...string) int { + cnt := 0 + for _, config := range configs { + if config == "" { + cnt++ + } + } + return cnt +} diff --git a/pkg/sidecar/config_test.go b/pkg/sidecar/config_test.go index 4ded5581..36fad5b4 100644 --- a/pkg/sidecar/config_test.go +++ b/pkg/sidecar/config_test.go @@ -22,6 +22,9 @@ func TestParseConfig(t *testing.T) { expectedSvidFileName := "svid.pem" expectedKeyFileName := "svid_key.pem" expectedSvidBundleFileName := "svid_bundle.pem" + expectedJWTSVIDFileName := "jwt_svid.token" + expectedJWTBundleFileName := "jwt_bundle.json" + expectedJWTAudience := "your-audience" assert.Equal(t, expectedAgentAddress, c.AgentAddress) assert.Equal(t, expectedCmd, c.Cmd) @@ -31,6 +34,9 @@ func TestParseConfig(t *testing.T) { assert.Equal(t, expectedSvidFileName, c.SvidFileName) assert.Equal(t, expectedKeyFileName, c.SvidKeyFileName) assert.Equal(t, expectedSvidBundleFileName, c.SvidBundleFileName) + assert.Equal(t, expectedJWTSVIDFileName, c.JWTSvidFilename) + assert.Equal(t, expectedJWTBundleFileName, c.JWTBundleFilename) + assert.Equal(t, expectedJWTAudience, c.JWTAudience) assert.True(t, c.AddIntermediatesToBundle) } @@ -51,33 +57,37 @@ func TestValidateConfig(t *testing.T) { }, }, { - name: "no SVID file", + name: "no error", config: &Config{ - AgentAddress: "path", - SvidKeyFileName: "key.pem", - SvidBundleFileName: "bundle.pem", + AgentAddress: "path", + JWTAudience: "your-audience", + JWTSvidFilename: "jwt.token", + JWTBundleFilename: "bundle.json", }, - expectError: "svid_file_name is required", }, { - name: "no key file", + name: "no set specified", config: &Config{ - AgentAddress: "path", - SvidFileName: "cert.pem", - SvidBundleFileName: "bundle.pem", + AgentAddress: "path", }, - expectError: "svid_key_file_name is required", + expectError: "at least one of the sets ('svid_file_name', 'svid_key_file_name', 'svid_bundle_file_name'), ('jwt_file_name', 'jwt_audience'), or ('jwt_bundle_file_name') must be fully specified", }, { - name: "no bundle file", + name: "missing svid config", + config: &Config{ + AgentAddress: "path", + SvidFileName: "cert.pem", + }, + expectError: "all or none of 'svid_file_name', 'svid_key_file_name', 'svid_bundle_file_name' must be specified", + }, + { + name: "missing jwt config", config: &Config{ AgentAddress: "path", - SvidFileName: "cert.pem", - SvidKeyFileName: "key.pem", + JWTSvidFilename: "cert.pem", }, - expectError: "svid_bundle_file_name is required", + expectError: "all or none of 'jwt_file_name', 'jwt_audience' must be specified", }, - // Duplicated field error: { name: "Both agent_address & agentAddress in use", @@ -88,7 +98,7 @@ func TestValidateConfig(t *testing.T) { SvidKeyFileName: "key.pem", SvidBundleFileName: "bundle.pem", }, - expectError: "use of agent_address and AgentAddress found, use only agent_address", + expectError: "use of agent_address and agentAddress found, use only agent_address", }, { name: "Both cmd_args & cmdArgs in use", @@ -159,7 +169,6 @@ func TestValidateConfig(t *testing.T) { }, expectError: "use of renew_signal and renewSignal found, use only renew_signal", }, - // Deprecated field warning: { name: "Using AgentAddressDeprecated", @@ -276,7 +285,7 @@ func TestValidateConfig(t *testing.T) { require.ElementsMatch(t, tt.expectLogs, getShortEntries(hook.AllEntries())) if tt.expectError != "" { - require.Error(t, err, tt.expectError) + require.EqualError(t, err, tt.expectError) return } diff --git a/pkg/sidecar/sidecar.go b/pkg/sidecar/sidecar.go index 71b4abc1..a9a31a49 100644 --- a/pkg/sidecar/sidecar.go +++ b/pkg/sidecar/sidecar.go @@ -1,17 +1,24 @@ package sidecar import ( + "context" "crypto/x509" + "encoding/base64" "encoding/csv" + "encoding/json" "encoding/pem" "fmt" "os" "os/exec" "path" "strings" + "sync" "sync/atomic" + "time" "github.com/sirupsen/logrus" + "github.com/spiffe/go-spiffe/v2/bundle/jwtbundle" + "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" "github.com/spiffe/go-spiffe/v2/workloadapi" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -27,6 +34,7 @@ const ( // implements the interface Sidecar type Sidecar struct { config *Config + jwtSource *workloadapi.JWTSource processRunning int32 process *os.Process certReadyChan chan struct{} @@ -66,6 +74,55 @@ func New(configPath string, log logrus.FieldLogger) (*Sidecar, error) { }, nil } +// RunDaemon starts the main loop +// Starts the workload API client to listen for new SVID updates +// When a new SVID is received on the updateChan, the SVID certificates +// are stored in disk and a restart signal is sent to the proxy's process +func (s *Sidecar) RunDaemon(ctx context.Context) error { + var wg sync.WaitGroup + + if s.config.SvidFileName != "" && s.config.SvidKeyFileName != "" && s.config.SvidBundleFileName != "" { + wg.Add(1) + go func() { + defer wg.Done() + err := workloadapi.WatchX509Context(ctx, &x509Watcher{sidecar: s}, s.getWorkloadAPIAdress()) + if err != nil && status.Code(err) != codes.Canceled { + s.config.Log.Fatalf("Error watching X.509 context: %v", err) + } + }() + } + + if s.config.JWTBundleFilename != "" { + wg.Add(1) + go func() { + defer wg.Done() + err := workloadapi.WatchJWTBundles(ctx, &JWTBundlesWatcher{sidecar: s}, s.getWorkloadAPIAdress()) + if err != nil && status.Code(err) != codes.Canceled { + s.config.Log.Fatalf("Error watching JWT bundle updates: %v", err) + } + }() + } + + if s.config.JWTSvidFilename != "" && s.config.JWTAudience != "" { + jwtSource, err := workloadapi.NewJWTSource(ctx, workloadapi.WithClientOptions(s.getWorkloadAPIAdress())) + if err != nil { + s.config.Log.Fatalf("Error watching JWT svid updates: %v", err) + } + s.jwtSource = jwtSource + defer s.jwtSource.Close() + + wg.Add(1) + go func() { + defer wg.Done() + s.updateJWTSVID(ctx) + }() + } + + wg.Wait() + + return nil +} + // CertReadyChan returns a channel to know when the certificates are ready func (s *Sidecar) CertReadyChan() <-chan struct{} { return s.certReadyChan @@ -73,13 +130,13 @@ func (s *Sidecar) CertReadyChan() <-chan struct{} { // updateCertificates Updates the certificates stored in disk and signal the Process to restart func (s *Sidecar) updateCertificates(svidResponse *workloadapi.X509Context) { - s.config.Log.Info("Updating certificates") - + s.config.Log.Debug("Updating X.509 certificates") err := s.dumpBundles(svidResponse) if err != nil { s.config.Log.WithError(err).Error("Unable to dump bundle") return } + s.config.Log.Info("X.509 certificates updated") if s.config.Cmd != "" { if err := s.signalProcess(); err != nil { @@ -183,6 +240,127 @@ func (s *Sidecar) dumpBundles(svidResponse *workloadapi.X509Context) error { return nil } +func (s *Sidecar) writeJSON(fileName string, certs map[string]interface{}) error { + file, err := json.Marshal(certs) + if err != nil { + return err + } + + jsonPath := path.Join(s.config.CertDir, fileName) + if err = os.WriteFile(jsonPath, file, os.ModePerm); err != nil { + return err + } + + return nil +} + +func (s *Sidecar) updateJWTBundle(jwkSet *jwtbundle.Set) { + s.config.Log.Debug("Updating JWT bundle") + + bundles := make(map[string]interface{}) + for _, bundle := range jwkSet.Bundles() { + bytes, err := bundle.Marshal() + if err != nil { + s.config.Log.Errorf("Unable to marshal JWT bundle: %v", err) + continue + } + bundles[bundle.TrustDomain().Name()] = base64.StdEncoding.EncodeToString(bytes) + } + + if err := s.writeJSON(s.config.JWTBundleFilename, bundles); err != nil { + s.config.Log.Errorf("Unable to write JSON file: %v", err) + } else { + s.config.Log.Info("JWT bundle updated") + } +} + +func (s *Sidecar) fetchJWTSVID(ctx context.Context) (*jwtsvid.SVID, error) { + jwtSVID, err := s.jwtSource.FetchJWTSVID(ctx, jwtsvid.Params{Audience: s.config.JWTAudience}) + if err != nil { + s.config.Log.Errorf("Unable to fetch JWT SVID: %v", err) + return nil, err + } + + _, err = jwtsvid.ParseAndValidate(jwtSVID.Marshal(), s.jwtSource, []string{s.config.JWTAudience}) + if err != nil { + s.config.Log.Errorf("Unable to parse or validate token: %v", err) + return nil, err + } + + return jwtSVID, nil +} + +func createRetryIntervalFunc() func() time.Duration { + const ( + initialBackoff = 1 * time.Second + maxBackoff = 60 * time.Second + multiplier = 2 + ) + backoffInterval := initialBackoff + return func() time.Duration { + currentBackoff := backoffInterval + // Update backoffInterval for next call, capped at maxBackoff + backoffInterval *= multiplier + if backoffInterval > maxBackoff { + backoffInterval = maxBackoff + } + return currentBackoff + } +} + +func getRefreshInterval(svid *jwtsvid.SVID) time.Duration { + return time.Until(svid.Expiry)/2 + time.Second +} + +func (s *Sidecar) performJWTSVIDUpdate(ctx context.Context) (*jwtsvid.SVID, error) { + s.config.Log.Debug("Updating JWT SVID") + + jwtSVID, err := s.fetchJWTSVID(ctx) + if err != nil { + s.config.Log.Errorf("Unable to update JWT SVID: %v", err) + return nil, err + } + + filePath := path.Join(s.config.CertDir, s.config.JWTSvidFilename) + if err = os.WriteFile(filePath, []byte(jwtSVID.Marshal()), os.ModePerm); err != nil { + s.config.Log.Errorf("Unable to update JWT SVID: %v", err) + return nil, err + } + + s.config.Log.Info("JWT SVID updated") + return jwtSVID, nil +} + +func (s *Sidecar) updateJWTSVID(ctx context.Context) { + retryInterval := createRetryIntervalFunc() + var initialInterval time.Duration + jwtSVID, err := s.performJWTSVIDUpdate(ctx) + if err != nil { + // If the first update fails, use the retry interval + initialInterval = retryInterval() + } else { + // If the update succeeds, use the refresh interval + initialInterval = getRefreshInterval(jwtSVID) + } + ticker := time.NewTicker(initialInterval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + jwtSVID, err = s.performJWTSVIDUpdate(ctx) + if err == nil { + retryInterval = createRetryIntervalFunc() + ticker.Reset(getRefreshInterval(jwtSVID)) + } else { + ticker.Reset(retryInterval()) + } + } + } +} + // x509Watcher is a sample implementation of the workload.X509SVIDWatcher interface type x509Watcher struct { sidecar *Sidecar @@ -246,3 +424,20 @@ func getCmdArgs(args string) ([]string, error) { return cmdArgs, nil } + +// JWTBundleWatcher is an implementation of workload.JWTBundleWatcher interface +type JWTBundlesWatcher struct { + sidecar *Sidecar +} + +// OnJWTBundlesUpdate is ran every time a bundle is updated +func (w JWTBundlesWatcher) OnJWTBundlesUpdate(jwkSet *jwtbundle.Set) { + w.sidecar.updateJWTBundle(jwkSet) +} + +// OnJWTBundlesWatchError is ran when the client runs into an error +func (w JWTBundlesWatcher) OnJWTBundlesWatchError(err error) { + if status.Code(err) != codes.Canceled { + w.sidecar.config.Log.Errorf("Error while watching JWT bundles: %v", err) + } +} diff --git a/pkg/sidecar/util_posix.go b/pkg/sidecar/util_posix.go index 9759bc43..15cfd5aa 100644 --- a/pkg/sidecar/util_posix.go +++ b/pkg/sidecar/util_posix.go @@ -4,25 +4,14 @@ package sidecar import ( - "context" - "errors" "fmt" "github.com/spiffe/go-spiffe/v2/workloadapi" "golang.org/x/sys/unix" ) -// RunDaemon starts the main loop -// Starts the workload API client to listen for new SVID updates -// When a new SVID is received on the updateChan, the SVID certificates -// are stored in disk and a restart signal is sent to the proxy's process -func (s *Sidecar) RunDaemon(ctx context.Context) error { - err := workloadapi.WatchX509Context(ctx, &x509Watcher{sidecar: s}, workloadapi.WithAddr("unix://"+s.config.AgentAddress)) - if err != nil && !errors.Is(err, context.Canceled) { - return err - } - - return nil +func (s *Sidecar) getWorkloadAPIAdress() workloadapi.ClientOption { + return workloadapi.WithAddr("unix://" + s.config.AgentAddress) } func (s *Sidecar) SignalProcess() error { diff --git a/pkg/sidecar/util_windows.go b/pkg/sidecar/util_windows.go index 62cbe65b..7ae05ab6 100644 --- a/pkg/sidecar/util_windows.go +++ b/pkg/sidecar/util_windows.go @@ -4,23 +4,13 @@ package sidecar import ( - "context" "errors" "github.com/spiffe/go-spiffe/v2/workloadapi" ) -// RunDaemon starts the main loop -// Starts the workload API client to listen for new SVID updates -// When a new SVID is received on the updateChan, the SVID certificates -// are stored in disk and a restart signal is sent to the proxy's process -func (s *Sidecar) RunDaemon(ctx context.Context) error { - err := workloadapi.WatchX509Context(ctx, &x509Watcher{sidecar: s}, workloadapi.WithNamedPipeName(s.config.AgentAddress)) - if err != nil && !errors.Is(err, context.Canceled) { - return err - } - - return nil +func (s *Sidecar) getWorkloadAPIAdress() workloadapi.ClientOption { + return workloadapi.WithNamedPipeName(s.config.AgentAddress) } func (s *Sidecar) SignalProcess() error { diff --git a/test/fixture/config/helper.conf b/test/fixture/config/helper.conf index 44e0ee87..0ab57b78 100644 --- a/test/fixture/config/helper.conf +++ b/test/fixture/config/helper.conf @@ -6,5 +6,8 @@ renew_signal = "SIGHUP" svid_file_name = "svid.pem" svid_key_file_name = "svid_key.pem" svid_bundle_file_name = "svid_bundle.pem" +jwt_svid_file_name = "jwt_svid.token" +jwt_bundle_file_name = "jwt_bundle.json" +jwt_audience = "your-audience" timeout = "10s" -add_intermediates_to_bundle = true \ No newline at end of file +add_intermediates_to_bundle = true