Search code examples
gogo-http

How To Pull Secrets as Config File in Golang


So I am pretty new to Go and I am curious about how to import passwords and URLs dynamically without exposing them within my scripts. In python, I was able to implement this with a JSON payload and would basically import JSON, load the payload, and specify whenever I needed to pass a spec that needed secrecy.

Here is My Go Script:

package main

import (
    "io/ioutil"
    "net/http"
    "fmt"

    "gopkg.in/yaml.v2"
)
// curl -u <username>:<password> <some_url>

func main() {
    type Config struct {
    URL      string `yaml:"url"`
    Username string `yaml:"username"`
    Token    string `yaml:"token"`
    }

    func readConfig() (*Config, error) {
    config := &Config{}
    cfgFile, err := ioutil.ReadFile("config.yaml")
    if err != nil {
        return nil, err
    }
    err = yaml.Unmarshal(cfgFile, config)
    return config, err
    }

    req, err := http.NewRequest("GET", config.URL, nil)
    if err != nil {
        // handle err
    }

    req.SetBasicAuth(config.Username, config.Token)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        // handle err
    }

    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}

As one can imagine I am not having much luck in loading my passwords, when I change the following with direct tokens exposing my passwords in the scripts it functions and produces a JSON payload in Jira.

config.URL
config.Username
config.Token

So if I have a config file in YAML as such:

config:
    URL: "<some_URL>"
    Username: "<some_username>"
    Token: "<some_token>"

How can I load the YAML file into my script? How can I load a JSON equivalent?

{
  "config": {
    "URL": "<some_URL>"
    "Username": "<some_username>",
    "Token": "<some_token>"
  }
}

Solution

  • Okay so there are a couple problems here.

    1. You can't declare functions inside of another function unless you use variable declaration syntax
    func main() {
        // This
        var myFunc = func() {
            // ...
        }
        // Not this
        func myFunc() {
            // ...
        }
    }
    
    1. The Config struct is telling the YAML unmarshaler to expect. Your struct should have yaml tags that match the casing and structure of the yaml file.
    // It is expecting this
    url: "<some_URL>"
    username: "<some_username>"
    token: "<some_token>"
    
    // Your yaml looks like this
    config:
      Url: "<some_URL>"
      Username: "<some_username>"
      Token: "<some_token>"
    

    The following works for me:

    package main
    
    import (
        "fmt"
        "io/ioutil"
        "net/http"
    
        "gopkg.in/yaml.v2"
    )
    
    type YAMLFile struct {
        Config Config `yaml:"config"`
    }
    type Config struct {
        URL      string `yaml:"url"`
        Username string `yaml:"username"`
        Token    string `yaml:"token"`
    }
    
    func main() {
        config, err := readConfig()
        if err != nil {
            panic(err)
        }
        fmt.Printf("%+v", config)
        req, err := http.NewRequest("GET", config.URL, nil)
        if err != nil {
            panic(err)
        }
        req.SetBasicAuth(config.Username, config.Token)
        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            panic(err)
        }
        defer resp.Body.Close()
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            panic(err)
        }
        fmt.Println(string(body))
    }
    
    func readConfig() (*Config, error) {
        config := &YAMLFile{}
        cfgFile, err := ioutil.ReadFile("./config.yaml")
        if err != nil {
            return nil, err
        }
        err = yaml.Unmarshal(cfgFile, config)
        return &config.Config, err
    }