-
Notifications
You must be signed in to change notification settings - Fork 90
/
reset-password.go
148 lines (126 loc) · 3.74 KB
/
reset-password.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
144
145
146
147
148
package cli
import (
"context"
"fmt"
"os"
"github.com/manifoldco/promptui"
"github.com/pkg/errors"
"github.com/replicatedhq/kots/pkg/k8sutil"
"github.com/replicatedhq/kots/pkg/logger"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/crypto/bcrypt"
corev1 "k8s.io/api/core/v1"
kuberneteserrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func ResetPasswordCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "reset-password [namespace]",
Short: "Change the password on the admin console",
Long: `Change the password on the Admin Console`,
SilenceUsage: true,
SilenceErrors: false,
PreRun: func(cmd *cobra.Command, args []string) {
viper.BindPFlags(cmd.Flags())
},
RunE: func(cmd *cobra.Command, args []string) error {
v := viper.GetViper()
log := logger.NewCLILogger()
// use namespace-as-arg if provided, else use namespace from -n/--namespace
namespace := v.GetString("namespace")
if len(args) == 1 {
namespace = args[0]
} else if len(args) > 1 {
fmt.Printf("more than one argument supplied: %+v\n", args)
os.Exit(1)
}
if namespace == "" {
fmt.Printf("a namespace must be provided as an argument or via -n/--namespace\n")
os.Exit(1)
}
log.ActionWithoutSpinner("Reset the admin console password for %s", namespace)
newPassword, err := promptForNewPassword()
if err != nil {
os.Exit(1)
}
if err := setKotsadmPassword(newPassword, namespace); err != nil {
return errors.Wrap(err, "failed to set new password")
}
log.ActionWithoutSpinner("The admin console password has been reset")
return nil
},
}
return cmd
}
func promptForNewPassword() (string, error) {
templates := &promptui.PromptTemplates{
Prompt: "{{ . | bold }} ",
Valid: "{{ . | green }} ",
Invalid: "{{ . | red }} ",
Success: "{{ . | bold }} ",
}
prompt := promptui.Prompt{
Label: "Enter a new password to be used for the Admin Console:",
Templates: templates,
Mask: rune('•'),
Validate: func(input string) error {
if len(input) < 6 {
return errors.New("please enter a longer password")
}
return nil
},
}
for {
result, err := prompt.Run()
if err != nil {
if err == promptui.ErrInterrupt {
os.Exit(-1)
}
continue
}
return result, nil
}
}
func setKotsadmPassword(password string, namespace string) error {
bcryptPassword, err := bcrypt.GenerateFromPassword([]byte(password), 10)
if err != nil {
return errors.Wrap(err, "failed to create encrypt password")
}
clientset, err := k8sutil.GetClientset()
if err != nil {
return errors.Wrap(err, "failed to create k8s client")
}
existingSecret, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), "kotsadm-password", metav1.GetOptions{})
if err != nil {
if !kuberneteserrors.IsNotFound(err) {
return errors.Wrap(err, "failed to lookup secret")
}
newSecret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: "kotsadm-password",
Namespace: namespace,
},
Data: map[string][]byte{
"passwordBcrypt": []byte(bcryptPassword),
},
}
_, err := clientset.CoreV1().Secrets(namespace).Create(context.TODO(), newSecret, metav1.CreateOptions{})
if err != nil {
return errors.Wrap(err, "failed to create secret")
}
} else {
existingSecret.Data["passwordBcrypt"] = []byte(bcryptPassword)
delete(existingSecret.Labels, "numAttempts")
delete(existingSecret.Labels, "lastFailure")
_, err := clientset.CoreV1().Secrets(namespace).Update(context.TODO(), existingSecret, metav1.UpdateOptions{})
if err != nil {
return errors.Wrap(err, "failed to update secret")
}
}
return nil
}