dls: password support

This commit is contained in:
Mikaël Cluseau 2019-04-13 10:36:58 +01:00
parent 6a0cd6da02
commit 456722a616
5 changed files with 107 additions and 6 deletions

View File

@ -160,6 +160,10 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]interface{}) map[strin
} }
return map[string]interface{}{ return map[string]interface{}{
"password": func(name string) (s string) {
return fmt.Sprintf("{{ password %q %q }}", cluster, name)
},
"token": func(name string) (s string) { "token": func(name string) (s string) {
return fmt.Sprintf("{{ token %q %q }}", cluster, name) return fmt.Sprintf("{{ token %q %q }}", cluster, name)
}, },

View File

@ -5,6 +5,7 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"log" "log"
"net/http" "net/http"
@ -135,6 +136,14 @@ func (ctx *renderContext) templateFuncs() map[string]interface{} {
} }
return map[string]interface{}{ return map[string]interface{}{
"password": func(cluster, name string) (password string, err error) {
password = secretData.Password(cluster, name)
if len(password) == 0 {
err = fmt.Errorf("password %q not defined for cluster %q", name, cluster)
}
return
},
"token": func(cluster, name string) (s string, err error) { "token": func(cluster, name string) (s string, err error) {
return secretData.Token(cluster, name) return secretData.Token(cluster, name)
}, },

View File

@ -10,6 +10,7 @@ import (
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"sync" "sync"
"github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/config"
@ -36,8 +37,9 @@ type SecretData struct {
} }
type ClusterSecrets struct { type ClusterSecrets struct {
CAs map[string]*CA CAs map[string]*CA
Tokens map[string]string Tokens map[string]string
Passwords map[string]string
} }
type CA struct { type CA struct {
@ -101,6 +103,14 @@ func (sd *SecretData) Save() error {
return ioutil.WriteFile(secretDataPath(), ba, 0600) return ioutil.WriteFile(secretDataPath(), ba, 0600)
} }
func newClusterSecrets() *ClusterSecrets {
return &ClusterSecrets{
CAs: make(map[string]*CA),
Tokens: make(map[string]string),
Passwords: make(map[string]string),
}
}
func (sd *SecretData) cluster(name string) (cs *ClusterSecrets) { func (sd *SecretData) cluster(name string) (cs *ClusterSecrets) {
cs, ok := sd.clusters[name] cs, ok := sd.clusters[name]
if ok { if ok {
@ -112,15 +122,47 @@ func (sd *SecretData) cluster(name string) (cs *ClusterSecrets) {
log.Info("secret-data: new cluster: ", name) log.Info("secret-data: new cluster: ", name)
cs = &ClusterSecrets{ cs = newClusterSecrets()
CAs: make(map[string]*CA),
Tokens: make(map[string]string),
}
sd.clusters[name] = cs sd.clusters[name] = cs
sd.changed = true sd.changed = true
return return
} }
func (sd *SecretData) Passwords(cluster string) (passwords []string) {
cs := sd.cluster(cluster)
passwords = make([]string, 0, len(cs.Passwords))
for name := range cs.Passwords {
passwords = append(passwords, name)
}
sort.Strings(passwords)
return
}
func (sd *SecretData) Password(cluster, name string) (password string) {
cs := sd.cluster(cluster)
if cs.Passwords == nil {
cs.Passwords = make(map[string]string)
}
password = cs.Passwords[name]
return
}
func (sd *SecretData) SetPassword(cluster, name, password string) {
cs := sd.cluster(cluster)
if cs.Passwords == nil {
cs.Passwords = make(map[string]string)
}
cs.Passwords[name] = password
sd.changed = true
}
func (sd *SecretData) Token(cluster, name string) (token string, err error) { func (sd *SecretData) Token(cluster, name string) (token string, err error) {
cs := sd.cluster(cluster) cs := sd.cluster(cluster)

View File

@ -61,3 +61,42 @@ func wsClusterAddons(req *restful.Request, resp *restful.Response) {
resp.Write([]byte(cluster.Addons)) resp.Write([]byte(cluster.Addons))
} }
func wsClusterPasswords(req *restful.Request, resp *restful.Response) {
cluster := wsReadCluster(req, resp)
if cluster == nil {
return
}
resp.WriteEntity(secretData.Passwords(cluster.Name))
}
func wsClusterPassword(req *restful.Request, resp *restful.Response) {
cluster := wsReadCluster(req, resp)
if cluster == nil {
return
}
name := req.PathParameter("password-name")
resp.WriteEntity(secretData.Password(cluster.Name, name))
}
func wsClusterSetPassword(req *restful.Request, resp *restful.Response) {
cluster := wsReadCluster(req, resp)
if cluster == nil {
return
}
name := req.PathParameter("password-name")
var password string
if err := req.ReadEntity(&password); err != nil {
wsError(resp, err) // FIXME this is a BadRequest
return
}
secretData.SetPassword(cluster.Name, name, password)
if err := secretData.Save(); err != nil {
wsError(resp, err)
}
}

View File

@ -31,6 +31,13 @@ func buildWS() *restful.WebService {
Returns(http.StatusOK, "OK", nil). Returns(http.StatusOK, "OK", nil).
Returns(http.StatusNotFound, "The cluster does not exists or does not have addons defined", nil)) Returns(http.StatusNotFound, "The cluster does not exists or does not have addons defined", nil))
ws.Route(ws.GET("/clusters/{cluster-name}/passwords").Filter(adminAuth).To(wsClusterPasswords).
Doc("List cluster's passwords"))
ws.Route(ws.GET("/clusters/{cluster-name}/passwords/{password-name}").Filter(adminAuth).To(wsClusterPassword).
Doc("Get cluster's password"))
ws.Route(ws.PUT("/clusters/{cluster-name}/passwords/{password-name}").Filter(adminAuth).To(wsClusterSetPassword).
Doc("Set cluster's password"))
// hosts API // hosts API
ws.Route(ws.GET("/hosts").Filter(hostsAuth).To(wsListHosts). ws.Route(ws.GET("/hosts").Filter(hostsAuth).To(wsListHosts).
Doc("List hosts")) Doc("List hosts"))