/
configmanager.go
148 lines (127 loc) · 4.48 KB
/
configmanager.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 util
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/kubernetes"
)
// ArgoCDSettings holds in-memory runtime configuration options.
type ArgoCDSettings struct {
// LocalUsers holds users local to (stored on) the server. This is to be distinguished from any potential alternative future login providers (LDAP, SAML, etc.) that might ever be added.
LocalUsers map[string]string
}
type configMapData struct {
rootCredentialsSecretName string
}
const (
// defaultConfigMapName default name of config map with argo-cd settings
defaultConfigMapName = "argo-cd-cm"
// defaultRootCredentialsSecretName contains default name of secret with root user credentials
defaultRootCredentialsSecretName = "argo-cd-root-credentials"
// configManagerRootUsernameKey designates the root username inside a Kubernetes secret.
configManagerRootUsernameKey = "root.username"
// configManagerRootPasswordKey designates the root password inside a Kubernetes secret.
configManagerRootPasswordKey = "root.password"
)
// ConfigManager holds config info for a new manager with which to access Kubernetes ConfigMaps.
type ConfigManager struct {
clientset kubernetes.Interface
namespace string
configMapName string
}
// GetSettings retrieves settings from the ConfigManager.
func (mgr *ConfigManager) GetSettings() (ArgoCDSettings, error) {
settings := ArgoCDSettings{}
settings.LocalUsers = make(map[string]string)
data, err := mgr.getConfigMapData()
if err != nil {
return settings, err
}
// Try to retrieve the secret
rootCredentials, err := mgr.readSecret(data.rootCredentialsSecretName)
if err != nil {
if errors.IsNotFound(err) {
return settings, nil
} else {
return settings, err
}
}
// Retrieve credential info from the secret
rootUsername, okUsername := rootCredentials.Data[configManagerRootUsernameKey]
rootPassword, okPassword := rootCredentials.Data[configManagerRootPasswordKey]
if okUsername && okPassword {
// Store credential info inside LocalUsers
settings.LocalUsers[string(rootUsername)] = string(rootPassword)
}
return settings, nil
}
func (mgr *ConfigManager) SetRootUserCredentials(username string, password string) error {
data, err := mgr.getConfigMapData()
if err != nil {
return err
}
// Don't commit plaintext passwords
passwordHash, err := HashPassword(password)
if err != nil {
return err
}
credentials := map[string]string{
configManagerRootUsernameKey: username,
configManagerRootPasswordKey: passwordHash,
}
// See if we've already written this secret
secret, err := mgr.clientset.CoreV1().Secrets(mgr.namespace).Get(data.rootCredentialsSecretName, metav1.GetOptions{})
if err != nil {
newSecret := &apiv1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: data.rootCredentialsSecretName,
},
}
newSecret.StringData = credentials
_, err = mgr.clientset.CoreV1().Secrets(mgr.namespace).Create(newSecret)
} else {
secret.StringData = credentials
_, err = mgr.clientset.CoreV1().Secrets(mgr.namespace).Update(secret)
}
return err
}
// NewConfigManager generates a new ConfigManager pointer and returns it
func NewConfigManager(clientset kubernetes.Interface, namespace, configMapName string) (mgr *ConfigManager) {
if configMapName == "" {
configMapName = defaultConfigMapName
}
mgr = &ConfigManager{
clientset: clientset,
namespace: namespace,
configMapName: configMapName,
}
return
}
func (mgr *ConfigManager) getConfigMapData() (configMapData, error) {
data := configMapData{}
configMap, err := mgr.readConfigMap(mgr.configMapName)
if err != nil {
if errors.IsNotFound(err) {
data.rootCredentialsSecretName = defaultRootCredentialsSecretName
return data, nil
} else {
return data, err
}
}
rootCredentialsSecretName, ok := configMap.Data[defaultRootCredentialsSecretName]
if !ok {
rootCredentialsSecretName = defaultRootCredentialsSecretName
}
data.rootCredentialsSecretName = rootCredentialsSecretName
return data, nil
}
// ReadConfigMap retrieves a config map from Kubernetes.
func (mgr *ConfigManager) readConfigMap(name string) (configMap *apiv1.ConfigMap, err error) {
configMap, err = mgr.clientset.CoreV1().ConfigMaps(mgr.namespace).Get(name, metav1.GetOptions{})
return
}
// ReadSecret retrieves a secret from Kubernetes.
func (mgr *ConfigManager) readSecret(name string) (secret *apiv1.Secret, err error) {
secret, err = mgr.clientset.CoreV1().Secrets(mgr.namespace).Get(name, metav1.GetOptions{})
return
}