Skip to content

Commit

Permalink
Adds suggested changes.
Browse files Browse the repository at this point in the history
Signed-off-by: JU4N98 <juanpablocabana2@gmail.com>
  • Loading branch information
JU4N98 committed Nov 8, 2023
1 parent 2a7f271 commit 86c00af
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 35 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ 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"` |
|`audience` | JWT SVID audience. | `"example.org"`|
|`jwt_file_name` | File name to be used to store JWT SVID in JSON format. | `"jwt.json"` |
|`jwk_file_name` | File name to be used to store JWT SVID Bundle in JSON format. | `"jwk.json"` |
|`audience` | JWT SVID audience. | `"example.org"` |
|`jwt_svid_file_name` | File name to be used to store JWT SVID in JSON format. | `"jwt.json"` |
|`jwt_bundle_file_name` | File name to be used to store JWT Bundle in JSON format. | `"jwt_bundle.json"` |

### Configuration example
```
Expand All @@ -42,8 +42,8 @@ svid_file_name = "svid.pem"
svid_key_file_name = "svid_key.pem"
svid_bundle_file_name = "svid_bundle.pem"
audience = "example.org"
jwt_file_name = "jwt.json"
jwk_file_name = "jwk.json"
jwt_svid_file_name = "jwt.json"
jwt_bundle_file_name = "bundle.json"
```

### Windows example
Expand All @@ -54,6 +54,6 @@ svid_file_name = "svid.pem"
svid_key_file_name = "svid_key.pem"
svid_bundle_file_name = "svid_bundle.pem"
audience = "example.org"
jwt_file_name = "jwt.json"
jwk_file_name = "jwk.json"
jwt_svid_file_name = "jwt.json"
jwt_bundle_file_name = "bundle.json"
```
6 changes: 3 additions & 3 deletions pkg/sidecar/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ type Config struct {
RenewSignalDeprecated string `hcl:"renewSignal"`

// JWT configuration
JWTAudience string `hcl:"jwt_audience"`
JWTFilename string `hcl:"jwt_file_name"`
JWKFilename string `hcl:"jwk_file_name"`
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
Expand Down
48 changes: 34 additions & 14 deletions pkg/sidecar/sidecar.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ 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 x509 certificates")
s.config.Log.Info("Updating X.509 certificates")

err := s.dumpBundles(svidResponse)
if err != nil {
Expand Down Expand Up @@ -192,79 +192,99 @@ func (s *Sidecar) dumpBundles(svidResponse *workloadapi.X509Context) error {
func (s *Sidecar) writeJSON(fileName string, certs map[string]interface{}) {
file, err := json.Marshal(certs)
if err != nil {
s.config.Log.Warnf("Unable to parse certs: %v", err)
s.config.Log.Errorf("Unable to parse certs: %v", err)
}

jsonPath := path.Join(s.config.CertDir, fileName)
err = os.WriteFile(jsonPath, file, os.ModePerm)
if err != nil {
s.config.Log.Warnf("Unable to write JSON file: %v", err)
s.config.Log.Errorf("Unable to write JSON file: %v", err)
}
}

func (s *Sidecar) updateJWTBundle(jwkSet *jwtbundle.Set) {
s.config.Log.Info("Updating JWK bundles")
s.config.Log.Info("Updating JWT bundle")

bundles := make(map[string]interface{})
for _, bundle := range jwkSet.Bundles() {
bytes, err := bundle.Marshal()
if err != nil {
s.config.Log.Warnf("Unable to marshal JWK bundle: %v", err)
s.config.Log.Errorf("Unable to marshal JWT bundle: %v", err)
continue
}
bundles[bundle.TrustDomain().Name()] = base64.StdEncoding.EncodeToString(bytes)
}

s.writeJSON(s.config.JWKFilename, bundles)
s.writeJSON(s.config.JWTBundleFilename, bundles)
}

func (s *Sidecar) fetchJWTSVID(options ...workloadapi.ClientOption) (*jwtsvid.SVID, error) {
clientOptions := workloadapi.WithClientOptions(options...)

jwtSource, err := workloadapi.NewJWTSource(context.Background(), clientOptions)
if err != nil {
s.config.Log.Warnf("Unable to create JWTSource: %v", err)
s.config.Log.Errorf("Unable to create JWTSource: %v", err)
return nil, err
}
defer jwtSource.Close()

jwtSVID, err := jwtSource.FetchJWTSVID(context.Background(), jwtsvid.Params{Audience: s.config.JWTAudience})
if err != nil {
s.config.Log.Warnf("Unable to fetch JWT SVID: %v", err)
s.config.Log.Errorf("Unable to fetch JWT SVID: %v", err)
return nil, err
}

_, err = jwtsvid.ParseAndValidate(jwtSVID.Marshal(), jwtSource, []string{s.config.JWTAudience})
if err != nil {
s.config.Log.Warnf("Unable to parse or validate token: %v", err)
s.config.Log.Errorf("Unable to parse or validate token: %v", err)
return nil, err
}

return jwtSVID, nil
}

func getRetryInterval() func() time.Duration {
backoffInterval := 0
return func() time.Duration {
backoffInterval += 5
return time.Duration(backoffInterval) * time.Second
}
}

func getRefreshInterval(svid *jwtsvid.SVID) time.Duration {
return time.Until(svid.Expiry)/2 + time.Second
}

func (s *Sidecar) updateJWTSVID(ctx context.Context, options ...workloadapi.ClientOption) {
retryInterval := getRetryInterval()

ticker := time.NewTicker(time.Second)
defer ticker.Stop()

for {
select {
case <-ctx.Done():
return
default:
case <-ticker.C:
s.config.Log.Infof("Updating JWT SVID")

jwtSVID, err := s.fetchJWTSVID(options...)
if err != nil {
time.Sleep(time.Second)
ticker.Reset(retryInterval())
continue
}

filePath := path.Join(s.config.CertDir, s.config.JWTFilename)
filePath := path.Join(s.config.CertDir, s.config.JWTSvidFilename)
err = os.WriteFile(filePath, []byte(jwtSVID.Marshal()), os.ModePerm)
if err != nil {
s.config.Log.Warnf("Unable to write JWT SVID to a file: %v", err)
s.config.Log.Errorf("Unable to write JWT SVID to a file: %v", err)
ticker.Reset(retryInterval())
continue
}
retryInterval = getRetryInterval()

s.config.Log.Infof("JWT SVID updated")
time.Sleep(time.Until(jwtSVID.Expiry)/2 + 1*time.Second)
ticker.Reset(getRefreshInterval(jwtSVID))
}
}
}
Expand Down
15 changes: 8 additions & 7 deletions pkg/sidecar/util_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,35 @@ import (
// 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
socket := "unix://" + s.config.AgentAddress

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}, workloadapi.WithAddr("unix://"+s.config.AgentAddress))
err := workloadapi.WatchX509Context(ctx, &x509Watcher{sidecar: s}, workloadapi.WithAddr(socket))
if err != nil && status.Code(err) != codes.Canceled {
s.config.Log.Fatalf("Error watching X.509 context: %w", err)
s.config.Log.Errorf("Error watching X.509 context: %v", err)
}
}()
}

if s.config.JWKFilename != "" {
if s.config.JWTBundleFilename != "" {
wg.Add(1)
go func() {
defer wg.Done()
err := workloadapi.WatchJWTBundles(ctx, &JWTBundlesWatcher{sidecar: s}, workloadapi.WithAddr("unix://"+s.config.AgentAddress))
err := workloadapi.WatchJWTBundles(ctx, &JWTBundlesWatcher{sidecar: s}, workloadapi.WithAddr(socket))
if err != nil && status.Code(err) != codes.Canceled {
s.config.Log.Fatalf("Error watching JWT bundles updates: %w", err)
s.config.Log.Errorf("Error watching JWT bundle updates: %v", err)
}
}()
}

if s.config.JWTFilename != "" && s.config.JWTAudience != "" {
if s.config.JWTSvidFilename != "" && s.config.JWTAudience != "" {
wg.Add(1)
go func() {
defer wg.Done()
s.updateJWTSVID(ctx, workloadapi.WithAddr("unix://"+s.config.AgentAddress))
s.updateJWTSVID(ctx, workloadapi.WithAddr(socket))
}()
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/sidecar/util_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ func (s *Sidecar) RunDaemon(ctx context.Context) error {
defer wg.Done()
err := workloadapi.WatchX509Context(ctx, &x509Watcher{sidecar: s}, workloadapi.WithNamedPipeName(s.config.AgentAddress))
if err != nil && status.Code(err) != codes.Canceled {
s.config.Log.Fatalf("Error watching X.509 context: %w", err)
s.config.Log.Errorf("Error watching X.509 context: %v", err)
}
}()
}

if s.config.JWKFilename != "" {
if s.config.JWTBundleFilename != "" {
wg.Add(1)
go func() {
defer wg.Done()
err := workloadapi.WatchJWTBundles(ctx, &JWTBundlesWatcher{sidecar: s}, workloadapi.WithNamedPipeName(s.config.AgentAddress))
if err != nil && status.Code(err) != codes.Canceled {
s.config.Log.Fatalf("Error watching JWT bundles updates: %w", err)
s.config.Log.Errorf("Error watching JWT bundle updates: %v", err)
}
}()
}

if s.config.JWTFilename != "" && s.config.JwtAudience != "" {
if s.config.JWTSvidFilename != "" && s.config.JWTAudience != "" {
wg.Add(1)
go func() {
defer wg.Done()
Expand Down

0 comments on commit 86c00af

Please sign in to comment.