github.com/smugmug/godynamo@v0.0.0-20151122084750-7913028f6623/conf_iam/conf_iam.go (about) 1 // Manages writing roles credentials into the global conf.Vals state. 2 // 3 // example use: 4 // 5 // iam_ready_chan := make(chan bool) 6 // go conf_iam.GoIAM(iam_ready_chan) 7 // iam_ready := <- iam_ready_chan 8 // if iam_ready { 9 // fmt.Printf("using iam\n") 10 // } else { 11 // fmt.Printf("not using iam\n") 12 // } 13 package conf_iam 14 15 import ( 16 "errors" 17 "fmt" 18 conf "github.com/smugmug/godynamo/conf" 19 roles_files "github.com/smugmug/goawsroles/roles_files" 20 "log" 21 "time" 22 ) 23 24 // AssignCredentialsToConf will safely copy the credentials data from rf to the conf c. 25 func AssignCredentialsToConf(rf *roles_files.RolesFiles, c *conf.AWS_Conf) error { 26 if rf == nil || c == nil { 27 return errors.New("conf_iam.AssignCredentialsToConf: rf or c is nil") 28 } 29 accessKey, secret, token, get_err := rf.Get() 30 if get_err != nil { 31 e := fmt.Sprintf("conf_iam.AssignCredentialsToConf:cannot get a role file:%s", 32 get_err.Error()) 33 return errors.New(e) 34 } 35 c.ConfLock.Lock() 36 c.IAM.Credentials.AccessKey = accessKey 37 c.IAM.Credentials.Secret = secret 38 c.IAM.Credentials.Token = token 39 c.ConfLock.Unlock() 40 e := fmt.Sprintf("IAM credentials assigned at %v", time.Now()) 41 log.Printf(e) 42 return nil 43 } 44 45 // AssignCredentials will safely copy the credentials data from rf to the global conf.Vals. 46 func AssignCredentials(rf *roles_files.RolesFiles) error { 47 return AssignCredentialsToConf(rf, &conf.Vals) 48 } 49 50 // ReadIAMToConf will read the credentials data from rf and safely assign it to conf c. 51 func ReadIAMToConf(rf *roles_files.RolesFiles, c *conf.AWS_Conf) error { 52 if rf == nil || c == nil { 53 return errors.New("conf_iam.ReadIAMToConf: rf or c is nil") 54 } 55 roles_read_err := rf.RolesRead() 56 if roles_read_err != nil { 57 e := fmt.Sprintf("conf_iam.ReadIAM:cannot perform initial roles read: %s", 58 roles_read_err.Error()) 59 return errors.New(e) 60 } 61 return AssignCredentialsToConf(rf, c) 62 } 63 64 // ReadIAM will read the credentials data from rf and safely assign it to the global conf.Vals. 65 func ReadIAM(rf *roles_files.RolesFiles) error { 66 return ReadIAMToConf(rf, &conf.Vals) 67 } 68 69 // WatchIAMToConf will begin rf's RolesWatch method and wait to receive signals that new credentials 70 // are available to be assigned, which will then be safely copied to conf c. 71 func WatchIAMToConf(rf *roles_files.RolesFiles, c *conf.AWS_Conf, watch_err_chan chan error) { 72 if rf == nil || c == nil { 73 watch_err_chan <- errors.New("conf_iam.WatchIAMToConf: rf or c is nil") 74 return 75 } 76 err_chan := make(chan error) 77 read_signal := make(chan bool) 78 go rf.RolesWatch(err_chan, read_signal) 79 e := "IAM watching set to true, waiting..." 80 log.Printf(e) 81 for { 82 select { 83 case roles_watch_err := <-err_chan: 84 watch_err_chan <- roles_watch_err 85 case <-read_signal: 86 e := "WatchIAM received a read signal" 87 log.Printf(e) 88 assign_err := AssignCredentialsToConf(rf, c) 89 if assign_err != nil { 90 watch_err_chan <- assign_err 91 } 92 } 93 } 94 } 95 96 // WatchIAMToConf will begin rf's RolesWatch method and wait to receive signals that new credentials 97 // are available to be assigned, which will then be safely copied to the global conf.Vals. 98 func WatchIAM(rf *roles_files.RolesFiles, watch_err_chan chan error) { 99 WatchIAMToConf(rf, &conf.Vals, watch_err_chan) 100 } 101 102 // GoIAMToConf is a convenience wrapper for callers using roles_files instantiation of the roles interface. 103 // First there is a blocking read on the roles files to get the initial roles information. Then the 104 // file notification watcher will run as a goroutine, and resetting conf c's roles 105 // values. If IAM Credentials are ready for use, the parameter chan `ready_chan` will receive a true 106 // value, otherwise false. A false value on this chan should indicate to a caller that another auth 107 // mechanism (for example, hardocded credentials) should be used. 108 func GoIAMToConf(c *conf.AWS_Conf, ready_chan chan bool) { 109 if c == nil { 110 log.Printf("conf_iam.GoIAMToConf: c is nil") 111 ready_chan <- false 112 return 113 } 114 use_iam := false 115 c.ConfLock.RLock() 116 use_iam = c.UseIAM 117 c.ConfLock.RUnlock() 118 if use_iam == true { 119 rf := roles_files.NewRolesFiles() 120 watching := false 121 c.ConfLock.RLock() 122 rf.BaseDir = c.IAM.File.BaseDir 123 rf.AccessKeyFile = c.IAM.File.AccessKey 124 rf.SecretFile = c.IAM.File.Secret 125 rf.TokenFile = c.IAM.File.Token 126 watching = c.IAM.Watch 127 c.ConfLock.RUnlock() 128 roles_read_err := ReadIAMToConf(rf, c) 129 if roles_read_err != nil { 130 e := fmt.Sprintf("conf_iam.GoIAMToConf:cannot perform initial roles read: %s", 131 roles_read_err.Error()) 132 log.Printf(e) 133 c.ConfLock.Lock() 134 c.UseIAM = false 135 c.ConfLock.Unlock() 136 ready_chan <- false 137 return 138 } 139 // signal to caller that iam roles are ready to use 140 ready_chan <- true 141 if watching == true { 142 watch_err := make(chan error) 143 go WatchIAMToConf(rf, c, watch_err) 144 go func() { 145 select { 146 case err := <-watch_err: 147 if err != nil { 148 log.Printf(err.Error()) 149 // caller can fall back to hard-coded perms 150 // or live with the panic 151 c.ConfLock.Lock() 152 c.UseIAM = false 153 c.ConfLock.Unlock() 154 } 155 } 156 }() 157 } 158 } else { 159 // signal to the caller than iam roles are not selected as a auth mechanism 160 e := fmt.Sprintf("conf_iam.GoIAMToConf: not using IAM") 161 log.Printf(e) 162 ready_chan <- false 163 } 164 } 165 166 // GoIAM calls the GoIAMToConf credential manager, assigning to the global conf.Vals. 167 func GoIAM(ready_chan chan bool) { 168 GoIAMToConf(&conf.Vals, ready_chan) 169 }