forked from openshift/oc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
helpers.go
109 lines (95 loc) · 3.6 KB
/
helpers.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
package login
import (
"bytes"
"crypto/x509"
"fmt"
"io"
"net/http"
"net/url"
"os"
"k8s.io/apimachinery/pkg/util/sets"
restclient "k8s.io/client-go/rest"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
kclientcmdapi "k8s.io/client-go/tools/clientcmd/api"
kterm "k8s.io/kubernetes/pkg/kubectl/util/term"
"github.com/openshift/oc/pkg/helpers/term"
)
// getMatchingClusters examines the kubeconfig for all clusters that point to the same server
func getMatchingClusters(clientConfig restclient.Config, kubeconfig clientcmdapi.Config) sets.String {
ret := sets.String{}
for key, cluster := range kubeconfig.Clusters {
if (cluster.Server == clientConfig.Host) && (cluster.InsecureSkipTLSVerify == clientConfig.Insecure) && (cluster.CertificateAuthority == clientConfig.CAFile) && (bytes.Compare(cluster.CertificateAuthorityData, clientConfig.CAData) == 0) {
ret.Insert(key)
}
}
return ret
}
// findExistingClientCA returns *either* the existing client CA file name as a string,
// *or* data in a []byte for a given host, and true if it exists in the given config
func findExistingClientCA(host string, kubeconfig clientcmdapi.Config) (string, []byte, bool) {
for _, cluster := range kubeconfig.Clusters {
if cluster.Server == host {
if len(cluster.CertificateAuthority) > 0 {
return cluster.CertificateAuthority, nil, true
}
if len(cluster.CertificateAuthorityData) > 0 {
return "", cluster.CertificateAuthorityData, true
}
}
}
return "", nil, false
}
// dialToServer takes the Server URL from the given clientConfig and dials to
// make sure the server is reachable. Note the config received is not mutated.
func dialToServer(clientConfig restclient.Config) error {
// take a RoundTripper based on the config we already have (TLS, proxies, etc)
rt, err := restclient.TransportFor(&clientConfig)
if err != nil {
return err
}
parsedURL, err := url.Parse(clientConfig.Host)
if err != nil {
return err
}
// Do a HEAD request to serverPathToDial to make sure the server is alive.
// We don't care about the response, any err != nil is valid for the sake of reachability.
serverURLToDial := (&url.URL{Scheme: parsedURL.Scheme, Host: parsedURL.Host, Path: "/"}).String()
req, err := http.NewRequest(http.MethodHead, serverURLToDial, nil)
if err != nil {
return err
}
res, err := rt.RoundTrip(req)
if err != nil {
return err
}
defer res.Body.Close()
return nil
}
func promptForInsecureTLS(reader io.Reader, out io.Writer, reason error) bool {
var insecureTLSRequestReason string
if reason != nil {
switch reason.(type) {
case x509.UnknownAuthorityError:
insecureTLSRequestReason = "The server uses a certificate signed by an unknown authority."
case x509.HostnameError:
insecureTLSRequestReason = fmt.Sprintf("The server is using a certificate that does not match its hostname: %s", reason.Error())
case x509.CertificateInvalidError:
insecureTLSRequestReason = fmt.Sprintf("The server is using an invalid certificate: %s", reason.Error())
}
}
var input bool
if kterm.IsTerminal(reader) {
if len(insecureTLSRequestReason) > 0 {
fmt.Fprintln(out, insecureTLSRequestReason)
}
fmt.Fprintln(out, "You can bypass the certificate check, but any data you send to the server could be intercepted by others.")
input = term.PromptForBool(os.Stdin, out, "Use insecure connections? (y/n): ")
fmt.Fprintln(out)
}
return input
}
func hasExistingInsecureCluster(clientConfigToTest restclient.Config, kubeconfig kclientcmdapi.Config) bool {
clientConfigToTest.Insecure = true
matchingClusters := getMatchingClusters(clientConfigToTest, kubeconfig)
return len(matchingClusters) > 0
}