// GoIAM is a convenience wrapper for callers using roles_files instantiation of the roles interface. // First there is a blocking read on the roles files to get the initial roles information. Then the // file notification watcher will run as a goroutine, and resetting the global conf.Vals roles // values. If IAM Credentials are ready for use, the parameter chan `ready_chan` will receive a true // value, otherwise false. A false value on this chan should indicate to a caller that another auth // mechanism (for example, hardocded credentials) should be used. func GoIAM(ready_chan chan bool) { use_iam := false conf.Vals.ConfLock.RLock() use_iam = conf.Vals.UseIAM conf.Vals.ConfLock.RUnlock() if use_iam == true { rf := roles_files.NewRolesFiles() watching := false conf.Vals.ConfLock.RLock() rf.BaseDir = conf.Vals.IAM.File.BaseDir rf.AccessKeyFile = conf.Vals.IAM.File.AccessKey rf.SecretFile = conf.Vals.IAM.File.Secret rf.TokenFile = conf.Vals.IAM.File.Token watching = conf.Vals.IAM.Watch conf.Vals.ConfLock.RUnlock() roles_read_err := ReadIAM(rf) if roles_read_err != nil { e := fmt.Sprintf("conf_iam.GoIAM:cannot perform initial roles read: %s", roles_read_err.Error()) slog.SLog(syslog.LOG_ERR, e, true) conf.Vals.UseIAM = false ready_chan <- false } // signal to caller that iam roles are ready to use ready_chan <- true if watching == true { watch_err := make(chan error) go WatchIAM(rf, watch_err) go func() { select { case err := <-watch_err: if err != nil { slog.SLog(syslog.LOG_ERR, err.Error(), true) // caller can fall back to hard-coded perms // or live with the panic conf.Vals.UseIAM = false } } }() } } else { // signal to the caller than iam roles are selected as a auth mechanism ready_chan <- false } }
// WatchIAM will receive notifications for changes in IAM files and update credentials when a read signal is received. func WatchIAM(rf *roles_files.RolesFiles, watch_err_chan chan error) { err_chan := make(chan error) read_signal := make(chan bool) go rf.RolesWatch(err_chan, read_signal) e := "IAM watching set to true, waiting..." slog.SLog(syslog.LOG_NOTICE, e, true) for { select { case roles_watch_err := <-err_chan: watch_err_chan <- roles_watch_err case <-read_signal: e := "WatchIAM received a read signal" slog.SLog(syslog.LOG_NOTICE, e, true) assign_err := AssignCredentials(rf) if assign_err != nil { watch_err_chan <- assign_err } } } }
// AssignCredentials locks the global state and copy over roles data. func AssignCredentials(rf *roles_files.RolesFiles) error { accessKey, secret, token, get_err := rf.Get() if get_err != nil { e := fmt.Sprintf("conf_iam.ReadIAM:cannot get a role file:%s", get_err.Error()) return errors.New(e) } conf.Vals.ConfLock.Lock() conf.Vals.IAM.Credentials.AccessKey = accessKey conf.Vals.IAM.Credentials.Secret = secret conf.Vals.IAM.Credentials.Token = token conf.Vals.ConfLock.Unlock() e := fmt.Sprintf("IAM credentials assigned at %v", time.Now()) slog.SLog(syslog.LOG_NOTICE, e, true) return nil }