-
Notifications
You must be signed in to change notification settings - Fork 687
/
do_login.go
143 lines (122 loc) · 3.99 KB
/
do_login.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 edgectl
import (
"context"
"crypto/rsa"
"fmt"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/pkg/browser"
"github.com/pkg/errors"
k8sTypesMetaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sClientCoreV1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
"github.com/datawire/ambassador/pkg/k8s"
)
const SecretName = "ambassador-internal"
type LoginClaimsV1 struct {
LoginTokenVersion string `json:"login_token_version"`
jwt.StandardClaims
}
func DoLogin() error {
url := "https://app.getambassador.io/cloud/catalog"
err := browser.OpenURL(url)
if err != nil {
fmt.Println("Unexpected error while trying to open your browser.")
return errors.Wrap(err, "browse")
}
return nil
}
func DoLoginLegacy(kubeinfo *k8s.KubeInfo, context, namespace, hostname string, openInBrowser, showURL, showToken, showWelcome bool) error {
restconfig, err := kubeinfo.GetRestConfig()
if err != nil {
return errors.Wrap(err, "Failed to connect to cluster (rest)")
}
// Obtain signing key
// -> kubectl -n $namespace get secret $SecretName -o json
privateKey, err := getSigningKey(restconfig, namespace)
if err != nil {
fmt.Println()
fmt.Println("Failed to obtain expected information from the cluster.")
fmt.Println("Is kubectl configured to connect to the correct cluster?")
fmt.Printf("Is %s the namespace where Ambassador is installed?\n\n", namespace)
fmt.Printf(" kubectl -n %s get svc,deploy\n\n", namespace)
return err
}
// FIXME: validate that hostname by querying
// https://{{hostname}}/edge_stack/admin/api/ambassador_cluster_id and
// verifying that it returns the same UUID via direct access and via
// port-forward/teleproxy. This avoids leaking login credentials to the
// operator of a different website.
// Construct claims
now := time.Now()
duration := 30 * time.Minute
claims := &LoginClaimsV1{
"v1",
jwt.StandardClaims{
IssuedAt: now.Unix(),
NotBefore: now.Unix(),
ExpiresAt: (now.Add(duration)).Unix(),
},
}
// Generate JWT
token := jwt.NewWithClaims(jwt.GetSigningMethod("PS512"), claims)
tokenString, err := token.SignedString(privateKey)
if err != nil {
return errors.Wrap(err, "Unexpected error generating JWT")
}
// Output
url := ""
if showWelcome {
url = fmt.Sprintf("https://%s/edge_stack/admin/?welcome=true#%s", hostname, tokenString)
} else {
url = fmt.Sprintf("https://%s/edge_stack/admin/#%s", hostname, tokenString)
}
// Remember if the browser successfully opened the URL
browserOpened := false
if openInBrowser {
err = browser.OpenURL(url)
if err == nil {
browserOpened = true
} else {
fmt.Println("Unexpected error while trying to open your browser.")
err = errors.Wrap(err, "browse")
}
}
if showURL {
if browserOpened {
fmt.Println("We've opened the Ambassador Edge Policy Console for you in your browser:")
} else {
fmt.Println("Visit the following URL to access the Ambassador Edge Policy Console:")
}
fmt.Println(url)
// Whitespace if we are also showing the token or opening in the browser
if showToken {
fmt.Println()
}
}
if showToken {
fmt.Println("The login token is")
fmt.Println(" ", tokenString)
}
return err
}
// getSigningKey retrieves the designated secret from the cluster and returns
// the private key extracted from the secret data
func getSigningKey(restconfig *rest.Config, namespace string) (*rsa.PrivateKey, error) {
coreClient, err := k8sClientCoreV1.NewForConfig(restconfig)
if err != nil {
return nil, errors.Wrap(err, "Failed to connect to cluster (core)")
}
secretInterface := coreClient.Secrets(namespace)
secret, err := secretInterface.Get(context.TODO(), SecretName, k8sTypesMetaV1.GetOptions{})
if err != nil {
return nil, err
}
// Parse out the private key from the secret
privatePEM, ok := secret.Data["rsa.key"]
if !ok {
return nil, errors.Errorf("secret name=%q namespace=%q exists but does not contain an %q %s field",
SecretName, namespace, "rsa.key", "private-key")
}
return jwt.ParseRSAPrivateKeyFromPEM(privatePEM)
}