186 lines
4.0 KiB
Go
186 lines
4.0 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base32"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"path"
|
|
"strconv"
|
|
"strings"
|
|
|
|
cfsslconfig "github.com/cloudflare/cfssl/config"
|
|
"github.com/cloudflare/cfssl/csr"
|
|
yaml "gopkg.in/yaml.v2"
|
|
|
|
"novit.tech/direktil/pkg/bootstrapconfig"
|
|
"novit.tech/direktil/pkg/config"
|
|
)
|
|
|
|
func templateFuncs(sslCfg *cfsslconfig.Config) map[string]any {
|
|
getKeyCert := func(cluster, caName, name, profile, label, reqJson string) (kc KeyCert, err error) {
|
|
certReq := &csr.CertificateRequest{
|
|
KeyRequest: csr.NewKeyRequest(),
|
|
}
|
|
|
|
err = json.Unmarshal([]byte(reqJson), certReq)
|
|
if err != nil {
|
|
log.Print("CSR unmarshal failed on: ", reqJson)
|
|
return
|
|
}
|
|
|
|
return getUsableKeyCert(cluster, caName, name, profile, label, certReq, sslCfg)
|
|
}
|
|
|
|
hash := func(plain, seed []byte, hashAlg string) (hashed string, err error) {
|
|
switch hashAlg {
|
|
case "sha512crypt":
|
|
return sha512crypt(plain, seed)
|
|
|
|
case "bootstrap":
|
|
return bootstrapconfig.JoinSeedAndHash(seed, bootstrapconfig.PasswordHashFromSeed(seed, plain)), nil
|
|
|
|
default:
|
|
return "", fmt.Errorf("unknown hash alg: %q", hashAlg)
|
|
}
|
|
}
|
|
|
|
return map[string]any{
|
|
"quote": strconv.Quote,
|
|
|
|
"password": func(cluster, name, hashAlg string) (password string, err error) {
|
|
key := cluster + "/" + name
|
|
|
|
seed, err := seeds.GetOrCreate(key, func() (seed []byte, err error) {
|
|
seed = make([]byte, 16)
|
|
_, err = rand.Read(seed)
|
|
return
|
|
})
|
|
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get seed: %w", err)
|
|
}
|
|
|
|
password, err = clusterPasswords.GetOrCreate(key, func() (password string, err error) {
|
|
raw := make([]byte, 10)
|
|
_, err = rand.Read(raw)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate password: %w", err)
|
|
}
|
|
|
|
password = strings.ToLower(base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(raw))
|
|
return
|
|
})
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return hash([]byte(password), seed, hashAlg)
|
|
},
|
|
|
|
"token": getOrCreateClusterToken,
|
|
|
|
"ca_key": func(cluster, name string) (s string, err error) {
|
|
ca, err := getUsableClusterCA(cluster, name)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
s = string(ca.Key)
|
|
return
|
|
},
|
|
|
|
"ca_crt": func(cluster, name string) (s string, err error) {
|
|
ca, err := getUsableClusterCA(cluster, name)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
s = string(ca.Cert)
|
|
return
|
|
},
|
|
|
|
"ca_dir": func(cluster, name string) (s string, err error) {
|
|
ca, err := getUsableClusterCA(cluster, name)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
dir := "/etc/tls-ca/" + name
|
|
|
|
return asYaml([]config.FileDef{
|
|
{
|
|
Path: path.Join(dir, "ca.crt"),
|
|
Mode: 0644,
|
|
Content: string(ca.Cert),
|
|
},
|
|
{
|
|
Path: path.Join(dir, "ca.key"),
|
|
Mode: 0600,
|
|
Content: string(ca.Key),
|
|
},
|
|
})
|
|
},
|
|
|
|
"tls_key": func(cluster, caName, name, profile, label, reqJson string) (s string, err error) {
|
|
kc, err := getKeyCert(cluster, caName, name, profile, label, reqJson)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
s = string(kc.Key)
|
|
return
|
|
},
|
|
|
|
"tls_crt": func(cluster, caName, name, profile, label, reqJson string) (s string, err error) {
|
|
kc, err := getKeyCert(cluster, caName, name, profile, label, reqJson)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
s = string(kc.Cert)
|
|
return
|
|
},
|
|
|
|
"tls_dir": func(dir, cluster, caName, name, profile, label, reqJson string) (s string, err error) {
|
|
ca, err := getUsableClusterCA(cluster, caName)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
kc, err := getKeyCert(cluster, caName, name, profile, label, reqJson)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return asYaml([]config.FileDef{
|
|
{
|
|
Path: path.Join(dir, "ca.crt"),
|
|
Mode: 0644,
|
|
Content: string(ca.Cert),
|
|
},
|
|
{
|
|
Path: path.Join(dir, "tls.crt"),
|
|
Mode: 0644,
|
|
Content: string(kc.Cert),
|
|
},
|
|
{
|
|
Path: path.Join(dir, "tls.key"),
|
|
Mode: 0600,
|
|
Content: string(kc.Key),
|
|
},
|
|
})
|
|
},
|
|
}
|
|
}
|
|
|
|
func asYaml(v interface{}) (string, error) {
|
|
ba, err := yaml.Marshal(v)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(ba), nil
|
|
}
|