// GoIAMToConf 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 conf c's 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 GoIAMToConf(c *conf.AWS_Conf, ready_chan chan bool) { if c == nil { log.Printf("conf_iam.GoIAMToConf: c is nil") ready_chan <- false return } use_iam := false c.ConfLock.RLock() use_iam = c.UseIAM c.ConfLock.RUnlock() if use_iam == true { rf := roles_files.NewRolesFiles() watching := false c.ConfLock.RLock() rf.BaseDir = c.IAM.File.BaseDir rf.AccessKeyFile = c.IAM.File.AccessKey rf.SecretFile = c.IAM.File.Secret rf.TokenFile = c.IAM.File.Token watching = c.IAM.Watch c.ConfLock.RUnlock() roles_read_err := ReadIAMToConf(rf, c) if roles_read_err != nil { e := fmt.Sprintf("conf_iam.GoIAMToConf:cannot perform initial roles read: %s", roles_read_err.Error()) log.Printf(e) c.ConfLock.Lock() c.UseIAM = false c.ConfLock.Unlock() ready_chan <- false return } // signal to caller that iam roles are ready to use ready_chan <- true if watching == true { watch_err := make(chan error) go WatchIAMToConf(rf, c, watch_err) go func() { select { case err := <-watch_err: if err != nil { log.Printf(err.Error()) // caller can fall back to hard-coded perms // or live with the panic c.ConfLock.Lock() c.UseIAM = false c.ConfLock.Unlock() } } }() } } else { // signal to the caller than iam roles are not selected as a auth mechanism e := fmt.Sprintf("conf_iam.GoIAMToConf: not using IAM") log.Printf(e) ready_chan <- false } }
// RawReqWithConf will sign and transmit the request to the AWS DynamoDB endpoint. // reqJSON is the json request // amzTarget is the dynamoDB endpoint // c is the configuration struct // returns []byte respBody, string aws reqID, int http code, error func RawReqWithConf(reqJSON []byte, amzTarget string, c *conf.AWS_Conf) ([]byte, string, int, error) { if !conf.IsValid(c) { return nil, "", 0, errors.New("auth_v4.RawReqWithConf: conf not valid") } // shadow conf vars in a read lock to minimize contention var our_c conf.AWS_Conf cp_err := our_c.Copy(c) if cp_err != nil { return nil, "", 0, cp_err } return rawReqAll( reqJSON, amzTarget, our_c.UseIAM, our_c.Network.DynamoDB.URL, our_c.Network.DynamoDB.Host, our_c.Network.DynamoDB.Port, our_c.Network.DynamoDB.Zone, our_c.IAM.Credentials.Secret, our_c.IAM.Credentials.AccessKey, our_c.IAM.Credentials.Token, our_c.Auth.Secret, our_c.Auth.AccessKey) }
// ReadConfFile will attempt to read in the conf file path passed as a parameter // and convert it into a conf.AWS_Conf struct pointer. You can use this to read in // a conf for a file of your own choosing. func ReadConfFile(conf_file string) (*conf.AWS_Conf, error) { conf_bytes, conf_err := ioutil.ReadFile(conf_file) if conf_err != nil { e := fmt.Sprintf("conf_file.ReadConfFile: cannot read conf file %s", conf_file) return nil, errors.New(e) } var cf conf.SDK_conf_file um_err := json.Unmarshal(conf_bytes, &cf) if um_err != nil { e := fmt.Sprintf("conf_file.ReadConfFile: cannot unmarshal %s. json err %s", conf_file, um_err.Error()) return nil, errors.New(e) } var c conf.AWS_Conf // make sure the dynamo endpoint is available addrs, addrs_err := net.LookupIP(cf.Services.Dynamo_db.Host) if addrs_err != nil { e := fmt.Sprintf("conf_file.ReadConfFile: cannot lookup hostname %s", cf.Services.Dynamo_db.Host) return nil, errors.New(e) } dynamo_ip := (addrs[0]).String() // assign the values to our globally-available c struct instance c.Auth.AccessKey = cf.Services.Default_settings.Params.Access_key_id c.Auth.Secret = cf.Services.Default_settings.Params.Secret_access_key c.UseSysLog = cf.Services.Default_settings.Params.Use_sys_log c.Network.DynamoDB.Host = cf.Services.Dynamo_db.Host c.Network.DynamoDB.IP = dynamo_ip c.Network.DynamoDB.Zone = cf.Services.Dynamo_db.Zone scheme := "http" port := aws_const.PORT // already a string if cf.Services.Dynamo_db.Scheme != "" { scheme = cf.Services.Dynamo_db.Scheme } if cf.Services.Dynamo_db.Port != 0 { port = strconv.Itoa(cf.Services.Dynamo_db.Port) } c.Network.DynamoDB.Port = port c.Network.DynamoDB.Scheme = scheme c.Network.DynamoDB.URL = scheme + "://" + c.Network.DynamoDB.Host + ":" + port _, url_err := url.Parse(c.Network.DynamoDB.URL) if url_err != nil { return nil, errors.New("conf_file.ReadConfFile: conf.Network.DynamoDB.URL malformed") } // If set to true, programs that are written with godynamo may // opt to launch the keepalive goroutine to keep conns open. c.Network.DynamoDB.KeepAlive = cf.Services.Dynamo_db.KeepAlive // read in flags for IAM support if cf.Services.Dynamo_db.IAM.Use_iam == true { // caller will have to check the RoleProvider to dispatch further Roles features c.IAM.RoleProvider = cf.Services.Dynamo_db.IAM.Role_provider c.IAM.File.BaseDir = cf.Services.Dynamo_db.IAM.Base_dir c.IAM.File.AccessKey = cf.Services.Dynamo_db.IAM.Access_key c.IAM.File.Secret = cf.Services.Dynamo_db.IAM.Secret_key c.IAM.File.Token = cf.Services.Dynamo_db.IAM.Token if cf.Services.Dynamo_db.IAM.Watch == true { c.IAM.Watch = true } else { c.IAM.Watch = false } c.UseIAM = true } c.Initialized = true return &c, nil }