github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/k8s/spiffe.go (about) 1 package k8s 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 "time" 8 9 "github.com/golang/glog" 10 "github.com/spiffe/go-spiffe/workload" 11 ) 12 13 type spiffeController struct { 14 watcher *spiffeWatcher 15 client *workload.X509SVIDClient 16 } 17 18 // NewSpiffeController creates the spiffeWatcher and the Spiffe Workload API Client, 19 // returns an error if the client cannot connect to the Spire Agent. 20 func NewSpiffeController(sync func(*workload.X509SVIDs), spireAgentAddr string) (*spiffeController, error) { 21 watcher := &spiffeWatcher{sync: sync} 22 client, err := workload.NewX509SVIDClient(watcher, workload.WithAddr("unix://"+spireAgentAddr)) 23 if err != nil { 24 return nil, fmt.Errorf("failed to create Spiffe Workload API Client: %w", err) 25 } 26 sc := &spiffeController{ 27 watcher: watcher, 28 client: client, 29 } 30 return sc, nil 31 } 32 33 // Start starts the Spiffe Workload API Client and waits for the Spiffe certs to be written to disk. 34 // If the certs are not available after 30 seconds an error is returned. 35 // On success, calls onStart function and kicks off the Spiffe Controller's run loop. 36 func (sc *spiffeController) Start(stopCh <-chan struct{}, onStart func()) error { 37 glog.V(3).Info("Starting SPIFFE Workload API Client") 38 err := sc.client.Start() 39 if err != nil { 40 return fmt.Errorf("failed to start Spiffe Workload API Client: %w", err) 41 } 42 timeout := time.After(30 * time.Second) 43 duration := 100 * time.Millisecond 44 for { 45 if sc.watcher.synced { 46 glog.V(3).Info("initial SPIFFE trust bundle written to disk") 47 break 48 } 49 select { 50 case <-timeout: 51 return errors.New("timed out waiting for SPIFFE trust bundle") 52 case <-stopCh: 53 return sc.client.Stop() 54 default: 55 break 56 } 57 time.Sleep(duration) 58 } 59 onStart() 60 go sc.Run(stopCh) 61 return nil 62 } 63 64 // Run waits until a message is sent on the stop channel and stops the Spiffe Workload API Client. 65 func (sc *spiffeController) Run(stopCh <-chan struct{}) { 66 <-stopCh 67 err := sc.client.Stop() 68 if err != nil { 69 glog.Errorf("failed to stop Spiffe Workload API Client: %v", err) 70 } 71 } 72 73 // spiffeWatcher is a sample implementation of the workload.X509SVIDWatcher interface 74 type spiffeWatcher struct { 75 sync func(*workload.X509SVIDs) 76 synced bool 77 } 78 79 // UpdateX509SVIDs is run every time an SVID is updated 80 func (w *spiffeWatcher) UpdateX509SVIDs(svids *workload.X509SVIDs) { 81 for _, svid := range svids.SVIDs { 82 glog.V(3).Infof("SVID updated for spiffeID: %q", svid.SPIFFEID) 83 } 84 w.sync(svids) 85 w.synced = true 86 } 87 88 // OnError is run when the client runs into an error 89 func (w *spiffeWatcher) OnError(err error) { 90 if strings.Contains(err.Error(), "PermissionDenied") { 91 glog.V(3).Infof("X509SVIDClient still waiting for certificates: %v", err) 92 return 93 } 94 glog.Fatal(err) 95 }