/
conn.go
143 lines (122 loc) · 3.62 KB
/
conn.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package main
import (
"crypto/tls"
"crypto/x509"
"github.com/codegangsta/cli"
"github.com/hashicorp/consul/api"
log "github.com/sirupsen/logrus"
"io/ioutil"
"net/http"
"net/url"
"os"
)
var certDirectories = []string{
"/system/etc/security/cacerts", // Android
"/usr/local/share/ca-certificates", // Debian derivatives
"/etc/pki/ca-trust/source/anchors", // RedHat derivatives
"/etc/ca-certificates", // Misc alternatives
"/usr/share/ca-certificates", // Misc alternatives
}
type AppConfig struct {
client *api.Client
queryOpts *api.QueryOptions
writeOpts *api.WriteOptions
}
func addCACert(path string, roots *x509.CertPool) *x509.CertPool {
f, err := os.Open(path)
if err != nil {
log.Printf("Could not open CA cert: %v", err)
return roots
}
fBytes, err := ioutil.ReadAll(f)
if err != nil {
log.Printf("Failed to read CA cert: %v", err)
return roots
}
if !roots.AppendCertsFromPEM(fBytes) {
log.Printf("Could not add client CA to pool: %v", err)
}
return roots
}
func loadSystemRootCAs() (systemRoots *x509.CertPool, err error) {
systemRoots = x509.NewCertPool()
for _, directory := range certDirectories {
fis, err := ioutil.ReadDir(directory)
if err != nil {
continue
}
for _, fi := range fis {
data, err := ioutil.ReadFile(directory + "/" + fi.Name())
if err == nil && systemRoots.AppendCertsFromPEM(data) {
log.Printf("Loaded Root CA %s", fi.Name())
}
}
}
return
}
func NewAppConfig(c *cli.Context) (cfg *AppConfig, err error) {
// Start with the default Consul API config
config := api.DefaultConfig()
// Create a TLS config to be populated with flag-defined certs if applicable
tlsConf := &tls.Config{}
consulUrl, err := url.Parse(c.GlobalString("addr"))
if err != nil {
log.Errorf("Invalid Consul URL: %v", err)
return
}
config.Scheme = consulUrl.Scheme
config.Address = consulUrl.Host
config.Datacenter = c.GlobalString("datacenter")
// Check for insecure flag
if c.GlobalBool("insecure") {
tlsConf.InsecureSkipVerify = true
}
// Load default system root CAs
// ignore errors since the TLS config
// will only be applied if SSL is used
tlsConf.ClientCAs, _ = loadSystemRootCAs()
// If --cert and --key are defined, load them and apply the TLS config
if len(c.GlobalString("cert")) > 0 && len(c.GlobalString("key")) > 0 {
// Make sure scheme is HTTPS when certs are used, regardless of the flag
config.Scheme = "https"
// Load cert and key files
cert, err := tls.LoadX509KeyPair(c.GlobalString("cert"), c.GlobalString("key"))
if err != nil {
log.Errorf("Could not parse SSL cert: %v", err)
}
tlsConf.Certificates = append(tlsConf.Certificates, cert)
// If cacert is defined, add it to the cert pool
// else just use system roots
if len(c.GlobalString("cacert")) > 0 {
tlsConf.ClientCAs = addCACert(c.GlobalString("cacert"), tlsConf.ClientCAs)
tlsConf.RootCAs = tlsConf.ClientCAs
}
}
if config.Scheme == "https" {
// Set Consul's transport to the TLS config
config.HttpClient.Transport = &http.Transport{
TLSClientConfig: tlsConf,
}
}
// Check for HTTP auth flags
if len(c.GlobalString("user")) > 0 && len(c.GlobalString("pass")) > 0 {
config.HttpAuth = &api.HttpBasicAuth{
Username: c.GlobalString("user"),
Password: c.GlobalString("pass"),
}
}
// Generate and return the API client
cl, err := api.NewClient(config)
cfg = &AppConfig{
client: cl,
queryOpts: &api.QueryOptions{
Datacenter: c.GlobalString("datacenter"),
Token: c.GlobalString("token"),
},
writeOpts: &api.WriteOptions{
Datacenter: c.GlobalString("datacenter"),
Token: c.GlobalString("token"),
},
}
return
}