diff --git a/README.md b/README.md index c9c1522..9e10506 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ The configuration file is an [HCL](https://github.com/hashicorp/hcl) formatted f | `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_svids` | An array with the audience and file name to store the JWT SVIDs. File is Base64-encoded string). | `[{jwt_audience="your-audience", jwt_svid_file_name="jwt_svid.token"}]` | + | `jwt_svids` | An array with the audience, optional extra audiences array, and file name to store the JWT SVIDs. File is Base64-encoded string). | `[{jwt_audience="your-audience", jwt_extra_audiences=["your-extra-audience-1", "your-extra-audience-2"], jwt_svid_file_name="jwt_svid.token"}]` | | `jwt_bundle_file_name` | File name to be used to store JWT Bundle in JSON format. | `"jwt_bundle.json"` | | `include_federated_domains` | Include trust domains from federated servers in the CA bundle. | `true` | | `cert_file_mode` | The octal file mode to use when saving the X.509 public certificate file. | `0644` | @@ -48,7 +48,7 @@ renew_signal = "SIGUSR1" svid_file_name = "svid.pem" svid_key_file_name = "svid_key.pem" svid_bundle_file_name = "svid_bundle.pem" -jwt_svids = [{jwt_audience="your-audience", jwt_svid_file_name="jwt_svid.token"}] +jwt_svids = [{jwt_audience="your-audience",jwt_extra_audiences=["your-extra-audience-1", "your-extra-audience-2"], jwt_svid_file_name="jwt_svid.token"}] jwt_bundle_file_name = "bundle.json" cert_file_mode = 0444 key_file_mode = 0444 @@ -63,6 +63,6 @@ cert_dir = "certs" svid_file_name = "svid.pem" svid_key_file_name = "svid_key.pem" svid_bundle_file_name = "svid_bundle.pem" -jwt_svids = [{jwt_audience="your-audience", jwt_svid_file_name="jwt_svid.token"}] +jwt_svids = [{jwt_audience="your-audience",jwt_extra_audiences=["your-extra-audience-1", "your-extra-audience-2"], jwt_svid_file_name="jwt_svid.token"}] jwt_bundle_file_name = "bundle.json" ``` diff --git a/cmd/spiffe-helper/config/config.go b/cmd/spiffe-helper/config/config.go index ce3a345..16fd115 100644 --- a/cmd/spiffe-helper/config/config.go +++ b/cmd/spiffe-helper/config/config.go @@ -51,8 +51,9 @@ type Config struct { } type JWTConfig struct { - JWTAudience string `hcl:"jwt_audience"` - JWTSVIDFilename string `hcl:"jwt_svid_file_name"` + JWTAudience string `hcl:"jwt_audience"` + JWTExtraAudiences []string `hcl:"jwt_extra_audiences"` + JWTSVIDFilename string `hcl:"jwt_svid_file_name"` UnusedKeyPositions map[string][]token.Pos `hcl:",unusedKeyPositions"` } @@ -188,8 +189,9 @@ func NewSidecarConfig(config *Config, log logrus.FieldLogger) *sidecar.Config { for _, jwtSVID := range config.JWTSVIDs { sidecarConfig.JWTSVIDs = append(sidecarConfig.JWTSVIDs, sidecar.JWTConfig{ - JWTAudience: jwtSVID.JWTAudience, - JWTSVIDFilename: jwtSVID.JWTSVIDFilename, + JWTAudience: jwtSVID.JWTAudience, + JWTExtraAudiences: jwtSVID.JWTExtraAudiences, + JWTSVIDFilename: jwtSVID.JWTSVIDFilename, }) } diff --git a/cmd/spiffe-helper/config/config_test.go b/cmd/spiffe-helper/config/config_test.go index 43aadec..2564841 100644 --- a/cmd/spiffe-helper/config/config_test.go +++ b/cmd/spiffe-helper/config/config_test.go @@ -29,6 +29,7 @@ func TestParseConfig(t *testing.T) { expectedJWTSVIDFileName := "jwt_svid.token" expectedJWTBundleFileName := "jwt_bundle.json" expectedJWTAudience := "your-audience" + expectedJWTExtraAudiences := []string{"your-extra-audience-1", "your-extra-audience-2"} assert.Equal(t, expectedAgentAddress, c.AgentAddress) assert.Equal(t, expectedCmd, c.Cmd) @@ -41,6 +42,7 @@ func TestParseConfig(t *testing.T) { assert.Equal(t, expectedJWTSVIDFileName, c.JWTSVIDs[0].JWTSVIDFilename) assert.Equal(t, expectedJWTBundleFileName, c.JWTBundleFilename) assert.Equal(t, expectedJWTAudience, c.JWTSVIDs[0].JWTAudience) + assert.Equal(t, expectedJWTExtraAudiences, c.JWTSVIDs[0].JWTExtraAudiences) assert.True(t, c.AddIntermediatesToBundle) assert.Equal(t, 444, c.CertFileMode) assert.Equal(t, 444, c.KeyFileMode) diff --git a/cmd/spiffe-helper/config/testdata/helper.conf b/cmd/spiffe-helper/config/testdata/helper.conf index 0219e30..a832fe9 100644 --- a/cmd/spiffe-helper/config/testdata/helper.conf +++ b/cmd/spiffe-helper/config/testdata/helper.conf @@ -15,6 +15,8 @@ jwt_svids = [ { jwt_svid_file_name = "jwt_svid.token" jwt_audience = "your-audience" + jwt_extra_audiences = ["your-extra-audience-1", "your-extra-audience-2"] + } ] timeout = "10s" diff --git a/pkg/sidecar/config.go b/pkg/sidecar/config.go index 9b95e32..7898893 100644 --- a/pkg/sidecar/config.go +++ b/pkg/sidecar/config.go @@ -73,6 +73,9 @@ type JWTConfig struct { // The audience for the JWT SVID to fetch JWTAudience string + // The extra audiences for the JWT SVID to fetch + JWTExtraAudiences []string + // The filename to save the JWT SVID to JWTSVIDFilename string } diff --git a/pkg/sidecar/sidecar.go b/pkg/sidecar/sidecar.go index 47995c2..891b79f 100644 --- a/pkg/sidecar/sidecar.go +++ b/pkg/sidecar/sidecar.go @@ -87,7 +87,7 @@ func (s *Sidecar) RunDaemon(ctx context.Context) error { wg.Add(1) go func() { defer wg.Done() - s.updateJWTSVID(ctx, jwtConfig.JWTAudience, jwtConfig.JWTSVIDFilename) + s.updateJWTSVID(ctx, jwtConfig.JWTAudience, jwtConfig.JWTExtraAudiences, jwtConfig.JWTSVIDFilename) }() } } @@ -253,8 +253,8 @@ func (s *Sidecar) checkProcessExit() { atomic.StoreInt32(&s.processRunning, 0) } -func (s *Sidecar) fetchJWTSVIDs(ctx context.Context, jwtAudience string) (*jwtsvid.SVID, error) { - jwtSVID, err := s.jwtSource.FetchJWTSVID(ctx, jwtsvid.Params{Audience: jwtAudience}) +func (s *Sidecar) fetchJWTSVIDs(ctx context.Context, jwtAudience string, jwtExtraAudiences []string) (*jwtsvid.SVID, error) { + jwtSVID, err := s.jwtSource.FetchJWTSVID(ctx, jwtsvid.Params{Audience: jwtAudience, ExtraAudiences: jwtExtraAudiences}) if err != nil { s.config.Log.Errorf("Unable to fetch JWT SVID: %v", err) return nil, err @@ -291,10 +291,10 @@ func getRefreshInterval(svid *jwtsvid.SVID) time.Duration { return time.Until(svid.Expiry)/2 + time.Second } -func (s *Sidecar) performJWTSVIDUpdate(ctx context.Context, jwtAudience string, jwtSVIDFilename string) (*jwtsvid.SVID, error) { +func (s *Sidecar) performJWTSVIDUpdate(ctx context.Context, jwtAudience string, jwtExtraAudiences []string, jwtSVIDFilename string) (*jwtsvid.SVID, error) { s.config.Log.Debug("Updating JWT SVID") - jwtSVID, err := s.fetchJWTSVIDs(ctx, jwtAudience) + jwtSVID, err := s.fetchJWTSVIDs(ctx, jwtAudience, jwtExtraAudiences) if err != nil { s.config.Log.Errorf("Unable to update JWT SVID: %v", err) return nil, err @@ -309,10 +309,10 @@ func (s *Sidecar) performJWTSVIDUpdate(ctx context.Context, jwtAudience string, return jwtSVID, nil } -func (s *Sidecar) updateJWTSVID(ctx context.Context, jwtAudience string, jwtSVIDFilename string) { +func (s *Sidecar) updateJWTSVID(ctx context.Context, jwtAudience string, jwtExtraAudiences []string, jwtSVIDFilename string) { retryInterval := createRetryIntervalFunc() var initialInterval time.Duration - jwtSVID, err := s.performJWTSVIDUpdate(ctx, jwtAudience, jwtSVIDFilename) + jwtSVID, err := s.performJWTSVIDUpdate(ctx, jwtAudience, jwtExtraAudiences, jwtSVIDFilename) if err != nil { // If the first update fails, use the retry interval initialInterval = retryInterval() @@ -328,7 +328,7 @@ func (s *Sidecar) updateJWTSVID(ctx context.Context, jwtAudience string, jwtSVID case <-ctx.Done(): return case <-ticker.C: - jwtSVID, err = s.performJWTSVIDUpdate(ctx, jwtAudience, jwtSVIDFilename) + jwtSVID, err = s.performJWTSVIDUpdate(ctx, jwtAudience, jwtExtraAudiences, jwtSVIDFilename) if err == nil { retryInterval = createRetryIntervalFunc() ticker.Reset(getRefreshInterval(jwtSVID))