github.com/kcburge/terraform@v0.11.12-beta1/svchost/auth/helper_program.go (about) 1 package auth 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "os/exec" 8 "path/filepath" 9 10 "github.com/hashicorp/terraform/svchost" 11 ) 12 13 type helperProgramCredentialsSource struct { 14 executable string 15 args []string 16 } 17 18 // HelperProgramCredentialsSource returns a CredentialsSource that runs the 19 // given program with the given arguments in order to obtain credentials. 20 // 21 // The given executable path must be an absolute path; it is the caller's 22 // responsibility to validate and process a relative path or other input 23 // provided by an end-user. If the given path is not absolute, this 24 // function will panic. 25 // 26 // When credentials are requested, the program will be run in a child process 27 // with the given arguments along with two additional arguments added to the 28 // end of the list: the literal string "get", followed by the requested 29 // hostname in ASCII compatibility form (punycode form). 30 func HelperProgramCredentialsSource(executable string, args ...string) CredentialsSource { 31 if !filepath.IsAbs(executable) { 32 panic("NewCredentialsSourceHelperProgram requires absolute path to executable") 33 } 34 35 fullArgs := make([]string, len(args)+1) 36 fullArgs[0] = executable 37 copy(fullArgs[1:], args) 38 39 return &helperProgramCredentialsSource{ 40 executable: executable, 41 args: fullArgs, 42 } 43 } 44 45 func (s *helperProgramCredentialsSource) ForHost(host svchost.Hostname) (HostCredentials, error) { 46 args := make([]string, len(s.args), len(s.args)+2) 47 copy(args, s.args) 48 args = append(args, "get") 49 args = append(args, string(host)) 50 51 outBuf := bytes.Buffer{} 52 errBuf := bytes.Buffer{} 53 54 cmd := exec.Cmd{ 55 Path: s.executable, 56 Args: args, 57 Stdin: nil, 58 Stdout: &outBuf, 59 Stderr: &errBuf, 60 } 61 err := cmd.Run() 62 if _, isExitErr := err.(*exec.ExitError); isExitErr { 63 errText := errBuf.String() 64 if errText == "" { 65 // Shouldn't happen for a well-behaved helper program 66 return nil, fmt.Errorf("error in %s, but it produced no error message", s.executable) 67 } 68 return nil, fmt.Errorf("error in %s: %s", s.executable, errText) 69 } else if err != nil { 70 return nil, fmt.Errorf("failed to run %s: %s", s.executable, err) 71 } 72 73 var m map[string]interface{} 74 err = json.Unmarshal(outBuf.Bytes(), &m) 75 if err != nil { 76 return nil, fmt.Errorf("malformed output from %s: %s", s.executable, err) 77 } 78 79 return HostCredentialsFromMap(m), nil 80 }