From 6651ff0364c80273d4fee2ac48aec82fafac2d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Cluseau?= Date: Sun, 6 Jul 2025 10:18:54 +0200 Subject: [PATCH] add public key template functions --- cmd/dkl-dir2config/assemble.go | 2 +- cmd/dkl-dir2config/render-context.go | 10 +++++-- .../cluster-render-context.go | 28 +++++++++++++++++++ cmd/dkl-local-server/tls-ca.go | 11 ++++++-- cmd/dkl-local-server/ws-host.go | 25 +++++++++-------- 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/cmd/dkl-dir2config/assemble.go b/cmd/dkl-dir2config/assemble.go index 12513fc..59f713c 100644 --- a/cmd/dkl-dir2config/assemble.go +++ b/cmd/dkl-dir2config/assemble.go @@ -124,7 +124,7 @@ func eachFragment(path string, searchList []FS, walk func(io.Reader) error) (err log.Print("#!gen ", cmdArgs) } - cmd := "gen/" + cmdArgs[0] + cmd := *dir + "/gen/" + cmdArgs[0] args := cmdArgs[1:] genOutput, err := exec.Command(cmd, args...).Output() if err != nil { diff --git a/cmd/dkl-dir2config/render-context.go b/cmd/dkl-dir2config/render-context.go index 481ee42..5ea2a72 100644 --- a/cmd/dkl-dir2config/render-context.go +++ b/cmd/dkl-dir2config/render-context.go @@ -203,7 +203,7 @@ func (ctx *renderContext) renderConfigTo(buf io.Writer, configTemplate *clusters } } -func (ctx *renderContext) templateFuncs(ctxMap map[string]any) map[string]interface{} { +func (ctx *renderContext) templateFuncs(ctxMap map[string]any) map[string]any { cluster := ctx.Cluster.Name getKeyCert := func(name, funcName string) (s string, err error) { @@ -229,14 +229,15 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]any) map[string]interf key += "/" + ctx.Host.Name } - if funcName == "tls_dir" { + switch funcName { + case "tls_dir": // needs the dir name dir := "/etc/tls/" + name s = fmt.Sprintf("{{ %s %q %q %q %q %q %q %q }}", funcName, dir, cluster, req.CA, key, req.Profile, req.Label, buf.String()) - } else { + default: s = fmt.Sprintf("{{ %s %q %q %q %q %q %q }}", funcName, cluster, req.CA, key, req.Profile, req.Label, buf.String()) } @@ -266,6 +267,9 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]any) map[string]interf "tls_key": func(name string) (string, error) { return getKeyCert(name, "tls_key") }, + "tls_pubkey": func(name string) string { + return fmt.Sprintf("{{ tls_pubkey %q %q }}", ctx.Cluster.Name, name) + }, "tls_crt": func(name string) (s string, err error) { return getKeyCert(name, "tls_crt") diff --git a/cmd/dkl-local-server/cluster-render-context.go b/cmd/dkl-local-server/cluster-render-context.go index 4b0c5d0..07e4b78 100644 --- a/cmd/dkl-local-server/cluster-render-context.go +++ b/cmd/dkl-local-server/cluster-render-context.go @@ -1,8 +1,11 @@ package main import ( + "crypto" "crypto/rand" + "crypto/x509" "encoding/base32" + "encoding/base64" "encoding/json" "fmt" "log" @@ -12,6 +15,7 @@ import ( cfsslconfig "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/csr" + "github.com/cloudflare/cfssl/helpers" yaml "gopkg.in/yaml.v2" "novit.tech/direktil/pkg/bootstrapconfig" @@ -19,6 +23,14 @@ import ( ) func templateFuncs(sslCfg *cfsslconfig.Config) map[string]any { + getKey := func(cluster, caName string) (key crypto.Signer, err error) { + ca, err := getUsableClusterCA(cluster, caName) + if err != nil { + return + } + key, err = helpers.ParsePrivateKeyPEM(ca.Key) + return + } getKeyCert := func(cluster, caName, name, profile, label, reqJson string) (kc KeyCert, err error) { certReq := &csr.CertificateRequest{ KeyRequest: csr.NewKeyRequest(), @@ -133,6 +145,22 @@ func templateFuncs(sslCfg *cfsslconfig.Config) map[string]any { return }, + "tls_pubkey": func(cluster, caName string) (s string, err error) { + priv, err := getKey(cluster, caName) + if err != nil { + return + } + + ba, err := x509.MarshalPKIXPublicKey(priv.Public()) + if err != nil { + err = fmt.Errorf("marshal public key failed: %w", err) + return + } + + s = base64.StdEncoding.EncodeToString(ba) + 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 { diff --git a/cmd/dkl-local-server/tls-ca.go b/cmd/dkl-local-server/tls-ca.go index 5f7d43f..aa48a74 100644 --- a/cmd/dkl-local-server/tls-ca.go +++ b/cmd/dkl-local-server/tls-ca.go @@ -72,13 +72,20 @@ func (_ CA) newReq() *csr.CertificateRequest { } } +func (ca CA) ParseKey() (key crypto.Signer, err error) { + return helpers.ParsePrivateKeyPEM(ca.Key) +} +func (ca CA) ParseCert() (cert *x509.Certificate, err error) { + return helpers.ParseCertificatePEM(ca.Cert) +} + func (ca CA) Signer(policy *config.Signing) (result *local.Signer, err error) { - caCert, err := helpers.ParseCertificatePEM(ca.Cert) + caCert, err := ca.ParseCert() if err != nil { return } - caKey, err := helpers.ParsePrivateKeyPEM(ca.Key) + caKey, err := ca.ParseKey() if err != nil { return } diff --git a/cmd/dkl-local-server/ws-host.go b/cmd/dkl-local-server/ws-host.go index 9cb7a90..e6abe47 100644 --- a/cmd/dkl-local-server/ws-host.go +++ b/cmd/dkl-local-server/ws-host.go @@ -180,22 +180,10 @@ func renderHost(w http.ResponseWriter, r *http.Request, what string, host *local case "kernel": err = renderKernel(w, r, ctx) - - // boot v2 - case "bootstrap-config": - err = renderBootstrapConfig(w, r, ctx, false) - case "bootstrap-config.json": - err = renderBootstrapConfig(w, r, ctx, true) case "initrd": err = renderCtx(w, r, ctx, what, buildInitrd) case "bootstrap.tar": err = renderCtx(w, r, ctx, what, buildBootstrap) - case "boot.iso": - err = renderCtx(w, r, ctx, what, buildBootISO) - case "boot.tar": - err = renderCtx(w, r, ctx, what, buildBootTar) - case "boot-efi.tar": - err = renderCtx(w, r, ctx, what, buildBootEFITar) case "boot.img": err = renderCtx(w, r, ctx, what, buildBootImg) @@ -213,6 +201,19 @@ func renderHost(w http.ResponseWriter, r *http.Request, what string, host *local err = renderCtx(w, r, ctx, what, qemuImgBootImg("vmdk")) case "boot.vpc": err = renderCtx(w, r, ctx, what, qemuImgBootImg("vpc")) + case "boot.iso": + err = renderCtx(w, r, ctx, what, buildBootISO) + + case "boot.tar": + err = renderCtx(w, r, ctx, what, buildBootTar) + case "boot-efi.tar": + err = renderCtx(w, r, ctx, what, buildBootEFITar) + + // boot v2 + case "bootstrap-config": + err = renderBootstrapConfig(w, r, ctx, false) + case "bootstrap-config.json": + err = renderBootstrapConfig(w, r, ctx, true) default: http.NotFound(w, r)