From ca6e4a862506b751b528e018bc36918ff1ccf5a4 Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 13:43:28 -0700 Subject: [PATCH 1/9] goreleaser: fix typo with builds.flags --- .goreleaser.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index fcf715b..5bd35f7 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -12,7 +12,7 @@ builds: - amd64 - arm64 flags: - - -tags:all + - -tags=all archives: - format: tar.gz # this name template makes the OS and Arch compatible with the results of uname. From e93bef79f2ff362a8fb1162dbe51a2fc6a8d7c2f Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 13:44:24 -0700 Subject: [PATCH 2/9] cmd: moved --cacert flag to use with 'serve' command --- cmd/generate.go | 2 -- cmd/root.go | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/generate.go b/cmd/generate.go index 8ce2093..c373b9b 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -20,7 +20,6 @@ var ( tokenFetchRetries int templatePaths []string pluginPath string - cacertPath string useCompression bool ) @@ -175,7 +174,6 @@ func init() { generateCmd.Flags().StringSliceVar(&templatePaths, "template", []string{}, "set the paths for the Jinja 2 templates to use") generateCmd.Flags().StringVar(&pluginPath, "plugin", "", "set the generator plugin path") generateCmd.Flags().StringVarP(&outputPath, "output", "o", "", "set the output path for config targets") - generateCmd.Flags().StringVar(&cacertPath, "cacert", "", "path to CA cert. (defaults to system CAs)") generateCmd.Flags().IntVar(&tokenFetchRetries, "fetch-retries", 5, "set the number of retries to fetch an access token") generateCmd.Flags().StringVar(&remoteHost, "host", "http://localhost", "set the remote host") generateCmd.Flags().IntVar(&remotePort, "port", 80, "set the remote port") diff --git a/cmd/root.go b/cmd/root.go index 26ccba7..6d323aa 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -10,8 +10,9 @@ import ( ) var ( - configPath string config configurator.Config + configPath string + cacertPath string verbose bool targets []string outputPath string @@ -42,6 +43,7 @@ func init() { cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "./config.yaml", "set the config path") rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "set to enable verbose output") + rootCmd.PersistentFlags().StringVar(&cacertPath, "cacert", "", "path to CA cert. (defaults to system CAs)") } func initConfig() { From 2a9e7c72dc7aea8b12ff6289bc7acd8445514dec Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 13:45:19 -0700 Subject: [PATCH 3/9] generator: added warn when default generator not found and fix error messages --- pkg/generator/generator.go | 2 ++ pkg/server/server.go | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 7fff8d8..e46b576 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -12,6 +12,7 @@ import ( "github.com/OpenCHAMI/configurator/pkg/util" "github.com/nikolalohinski/gonja/v2" "github.com/nikolalohinski/gonja/v2/exec" + "github.com/rs/zerolog/log" ) type ( @@ -440,6 +441,7 @@ func GenerateWithTarget(config *configurator.Config, params Params) (FileMap, er generator, ok = DefaultGenerators[params.Target] if !ok { // only load the plugin needed for this target if we don't find default + log.Error().Msg("did not find target in default generators") generator, err = LoadPlugin(target.PluginPath) if err != nil { return nil, fmt.Errorf("failed to load plugin: %w", err) diff --git a/pkg/server/server.go b/pkg/server/server.go index 89e0d71..66fdc58 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -76,7 +76,7 @@ func (s *Server) Serve() error { var err error tokenAuth, err = configurator.FetchPublicKeyFromURL(s.Config.Server.Jwks.Uri) if err != nil { - logrus.Errorf("failed to fetch JWKS: %w", err) + logrus.Errorf("failed to fetch JWKS: %v", err) continue } break @@ -138,7 +138,7 @@ func (s *Server) Generate(w http.ResponseWriter, r *http.Request) { // generate a new config file from supplied params outputs, err := generator.GenerateWithTarget(s.Config, s.GeneratorParams) if err != nil { - writeErrorResponse(w, "failed to generate file: %w", err) + writeErrorResponse(w, "failed to generate file: %v", err) return } @@ -146,12 +146,12 @@ func (s *Server) Generate(w http.ResponseWriter, r *http.Request) { tmp := generator.ConvertContentsToString(outputs) b, err := json.Marshal(tmp) if err != nil { - writeErrorResponse(w, "failed to marshal output: %w", err) + writeErrorResponse(w, "failed to marshal output: %v", err) return } _, err = w.Write(b) if err != nil { - writeErrorResponse(w, "failed to write response: %w", err) + writeErrorResponse(w, "failed to write response: %v", err) return } } @@ -163,7 +163,7 @@ func (s *Server) Generate(w http.ResponseWriter, r *http.Request) { func (s *Server) ManageTemplates(w http.ResponseWriter, r *http.Request) { _, err := w.Write([]byte("this is not implemented yet")) if err != nil { - writeErrorResponse(w, "failed to write response: %w", err) + writeErrorResponse(w, "failed to write response: %v", err) return } } From 4bd4dac1297b9bf4243d438b8b76e19bcec1dcc8 Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 16:21:04 -0700 Subject: [PATCH 4/9] cmd: removed flag and added check for cacert --- cmd/serve.go | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/cmd/serve.go b/cmd/serve.go index f7e4401..507d330 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -4,11 +4,15 @@ package cmd import ( + "crypto/tls" + "crypto/x509" "encoding/json" "errors" "fmt" + "net" "net/http" "os" + "time" "github.com/OpenCHAMI/configurator/pkg/generator" "github.com/OpenCHAMI/configurator/pkg/server" @@ -55,13 +59,33 @@ var serveCmd = &cobra.Command{ Retries: config.Server.Jwks.Retries, }, GeneratorParams: generator.Params{ - Args: args, - PluginPath: pluginPath, + Args: args, + // PluginPath: pluginPath, // Target: target, // NOTE: targets are set via HTTP requests (ex: curl http://configurator:3334/generate?target=dnsmasq) Verbose: verbose, }, } + // add cert to client if `--cacert` flag is passed + if cacertPath != "" { + cacert, _ := os.ReadFile(cacertPath) + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM(cacert) + server.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: certPool, + InsecureSkipVerify: true, + }, + DisableKeepAlives: true, + Dial: (&net.Dialer{ + Timeout: 120 * time.Second, + KeepAlive: 120 * time.Second, + }).Dial, + TLSHandshakeTimeout: 120 * time.Second, + ResponseHeaderTimeout: 120 * time.Second, + } + } + // start listening with the server err := server.Serve() if errors.Is(err, http.ErrServerClosed) { @@ -78,7 +102,7 @@ var serveCmd = &cobra.Command{ func init() { serveCmd.Flags().StringVar(&config.Server.Host, "host", config.Server.Host, "set the server host") serveCmd.Flags().IntVar(&config.Server.Port, "port", config.Server.Port, "set the server port") - serveCmd.Flags().StringVar(&pluginPath, "plugin", "", "set the generator plugins directory path") + // serveCmd.Flags().StringVar(&pluginPath, "plugin", "", "set the generator plugins directory path") serveCmd.Flags().StringVar(&config.Server.Jwks.Uri, "jwks-uri", config.Server.Jwks.Uri, "set the JWKS url to fetch public key") serveCmd.Flags().IntVar(&config.Server.Jwks.Retries, "jwks-fetch-retries", config.Server.Jwks.Retries, "set the JWKS fetch retry count") rootCmd.AddCommand(serveCmd) From b5d492d6c01d20135412206d62cad86433c52f62 Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 16:26:17 -0700 Subject: [PATCH 5/9] cmd: added error when specifying config path but not found --- cmd/root.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 6d323aa..ab190da 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,6 +6,7 @@ import ( configurator "github.com/OpenCHAMI/configurator/pkg" "github.com/OpenCHAMI/configurator/pkg/util" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -41,12 +42,13 @@ func Execute() { func init() { cobra.OnInitialize(initConfig) - rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "./config.yaml", "set the config path") + rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "set the config path") rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "set to enable verbose output") rootCmd.PersistentFlags().StringVar(&cacertPath, "cacert", "", "path to CA cert. (defaults to system CAs)") } func initConfig() { + // empty from not being set if configPath != "" { exists, err := util.PathExists(configPath) if err != nil { @@ -55,9 +57,13 @@ func initConfig() { } else if exists { config = configurator.LoadConfig(configPath) } else { - config = configurator.NewConfig() + // show error and exit since a path was specified + log.Error().Str("path", configPath).Msg("config file not found") + os.Exit(1) } } else { + // set to the default value and create a new one + configPath = "./config.yaml" config = configurator.NewConfig() } From 043f8ec1201b078d2a003165b1a8c9a35508cfd2 Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 16:30:26 -0700 Subject: [PATCH 6/9] goreleaser/docker: removed lib/ refs and other minor changes --- .goreleaser.yaml | 2 -- Dockerfile | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 5bd35f7..d91d3e3 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -27,7 +27,6 @@ archives: - LICENSE - CHANGELOG.md - README.md - - lib/ dockers: - image_templates: @@ -45,7 +44,6 @@ dockers: - LICENSE - CHANGELOG.md - README.md - - lib/ checksum: name_template: 'checksums.txt' snapshot: diff --git a/Dockerfile b/Dockerfile index b36b37d..3a1e3a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,15 +2,13 @@ FROM cgr.dev/chainguard/wolfi-base RUN apk add --no-cache tini bash RUN mkdir -p /configurator -RUN mkdir -p /configurator/lib # nobody 65534:65534 USER 65534:65534 # copy the binary and all of the default plugins COPY configurator /configurator/configurator -COPY lib/* /configurator/lib/* -CMD ["/configurator"] +CMD ["/configurator/configurator"] ENTRYPOINT [ "/sbin/tini", "--" ] \ No newline at end of file From dac6c2306f7a3c9d5ae3f03c76b6a27f537f7e90 Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 16:53:00 -0700 Subject: [PATCH 7/9] client: moved cacert logic from 'serve' cmd to client --- cmd/serve.go | 28 +------------ pkg/generator/generator.go | 18 ++++++--- pkg/server/server.go | 83 +++++++++++++++++++++++++------------- 3 files changed, 70 insertions(+), 59 deletions(-) diff --git a/cmd/serve.go b/cmd/serve.go index 507d330..647482b 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -4,15 +4,11 @@ package cmd import ( - "crypto/tls" - "crypto/x509" "encoding/json" "errors" "fmt" - "net" "net/http" "os" - "time" "github.com/OpenCHAMI/configurator/pkg/generator" "github.com/OpenCHAMI/configurator/pkg/server" @@ -48,7 +44,7 @@ var serveCmd = &cobra.Command{ fmt.Printf("%v\n", string(b)) } - // set up the routes and start the server + // set up the routes and start the serve server := server.Server{ Config: &config, Server: &http.Server{ @@ -66,28 +62,8 @@ var serveCmd = &cobra.Command{ }, } - // add cert to client if `--cacert` flag is passed - if cacertPath != "" { - cacert, _ := os.ReadFile(cacertPath) - certPool := x509.NewCertPool() - certPool.AppendCertsFromPEM(cacert) - server.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: certPool, - InsecureSkipVerify: true, - }, - DisableKeepAlives: true, - Dial: (&net.Dialer{ - Timeout: 120 * time.Second, - KeepAlive: 120 * time.Second, - }).Dial, - TLSHandshakeTimeout: 120 * time.Second, - ResponseHeaderTimeout: 120 * time.Second, - } - } - // start listening with the server - err := server.Serve() + err := server.Serve(cacertPath) if errors.Is(err, http.ErrServerClosed) { if verbose { fmt.Printf("Server closed.") diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index e46b576..e705e16 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -36,6 +36,7 @@ type ( TemplatePaths []string PluginPath string Target string + Client *configurator.SmdClient Verbose bool } ) @@ -409,17 +410,24 @@ func Generate(config *configurator.Config, params Params) (FileMap, error) { func GenerateWithTarget(config *configurator.Config, params Params) (FileMap, error) { // load generator plugins to generate configs or to print var ( + client configurator.SmdClient + target configurator.Target + generator Generator + err error + ok bool + ) + + // check if we have a client from params first and create new one if not + if params.Client == nil { client = configurator.NewSmdClient( configurator.WithHost(config.SmdClient.Host), configurator.WithPort(config.SmdClient.Port), configurator.WithAccessToken(config.AccessToken), configurator.WithCertPoolFile(config.CertPath), ) - target configurator.Target - generator Generator - err error - ok bool - ) + } else { + client = *params.Client + } // check if a target is supplied if len(params.Args) == 0 && params.Target == "" { diff --git a/pkg/server/server.go b/pkg/server/server.go index 66fdc58..9afc7db 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -4,8 +4,11 @@ package server import ( + "crypto/tls" + "crypto/x509" "encoding/json" "fmt" + "net" "net/http" "os" "time" @@ -60,13 +63,33 @@ func New(config *configurator.Config) *Server { } // Main function to start up configurator as a service. -func (s *Server) Serve() error { +func (s *Server) Serve(cacertPath string) error { // create client just for the server to use to fetch data from SMD - _ = &configurator.SmdClient{ + client := &configurator.SmdClient{ Host: s.Config.SmdClient.Host, Port: s.Config.SmdClient.Port, } + // add cert to client if `--cacert` flag is passed + if cacertPath != "" { + cacert, _ := os.ReadFile(cacertPath) + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM(cacert) + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: certPool, + InsecureSkipVerify: true, + }, + DisableKeepAlives: true, + Dial: (&net.Dialer{ + Timeout: 120 * time.Second, + KeepAlive: 120 * time.Second, + }).Dial, + TLSHandshakeTimeout: 120 * time.Second, + ResponseHeaderTimeout: 120 * time.Second, + } + } + // set the server address with config values s.Server.Addr = fmt.Sprintf("%s:%d", s.Config.Server.Host, s.Config.Server.Port) @@ -104,12 +127,12 @@ func (s *Server) Serve() error { ) // protected routes if using auth - r.HandleFunc("/generate", s.Generate) + r.HandleFunc("/generate", s.Generate(client)) r.HandleFunc("/templates", s.ManageTemplates) }) } else { // public routes without auth - router.HandleFunc("/generate", s.Generate) + router.HandleFunc("/generate", s.Generate(client)) router.HandleFunc("/templates", s.ManageTemplates) } @@ -127,32 +150,36 @@ func (s *Server) Close() { // This is the corresponding service function to generate templated files, that // works similarly to the CLI variant. This function takes similiar arguments as // query parameters that are included in the HTTP request URL. -func (s *Server) Generate(w http.ResponseWriter, r *http.Request) { - // get all of the expect query URL params and validate - s.GeneratorParams.Target = r.URL.Query().Get("target") - if s.GeneratorParams.Target == "" { - writeErrorResponse(w, "must specify a target") - return - } +func (s *Server) Generate(client *configurator.SmdClient) func(w http.ResponseWriter, r *http.Request) { + + return func(w http.ResponseWriter, r *http.Request) { + // get all of the expect query URL params and validate + s.GeneratorParams.Target = r.URL.Query().Get("target") + s.GeneratorParams.Client = client + if s.GeneratorParams.Target == "" { + writeErrorResponse(w, "must specify a target") + return + } - // generate a new config file from supplied params - outputs, err := generator.GenerateWithTarget(s.Config, s.GeneratorParams) - if err != nil { - writeErrorResponse(w, "failed to generate file: %v", err) - return - } + // generate a new config file from supplied params + outputs, err := generator.GenerateWithTarget(s.Config, s.GeneratorParams) + if err != nil { + writeErrorResponse(w, "failed to generate file: %v", err) + return + } - // marshal output to JSON then send response to client - tmp := generator.ConvertContentsToString(outputs) - b, err := json.Marshal(tmp) - if err != nil { - writeErrorResponse(w, "failed to marshal output: %v", err) - return - } - _, err = w.Write(b) - if err != nil { - writeErrorResponse(w, "failed to write response: %v", err) - return + // marshal output to JSON then send response to client + tmp := generator.ConvertContentsToString(outputs) + b, err := json.Marshal(tmp) + if err != nil { + writeErrorResponse(w, "failed to marshal output: %v", err) + return + } + _, err = w.Write(b) + if err != nil { + writeErrorResponse(w, "failed to write response: %v", err) + return + } } } From 516f100075da089e3991d1d1a26c578ffe69592a Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 17:06:49 -0700 Subject: [PATCH 8/9] chore: moved contents of dist/ to res/ --- {dist => res}/archlinux/PKGBUILD | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {dist => res}/archlinux/PKGBUILD (100%) diff --git a/dist/archlinux/PKGBUILD b/res/archlinux/PKGBUILD similarity index 100% rename from dist/archlinux/PKGBUILD rename to res/archlinux/PKGBUILD From f0c48d5d77260e8ad03b3380e999fcfefa5eb12c Mon Sep 17 00:00:00 2001 From: "David J. Allen" Date: Thu, 14 Nov 2024 17:07:26 -0700 Subject: [PATCH 9/9] gitignore: added dist/ to file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e848d1d..a51dd2f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ **.conf **.ignore **.tar.gz +dist/