Merge pull request #22 from OpenCHAMI/fix-minor-issues

Fix minor issues
This commit is contained in:
David Allen 2024-11-14 17:25:38 -07:00 committed by GitHub
commit 5b351d2cac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 91 additions and 51 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@
**.conf **.conf
**.ignore **.ignore
**.tar.gz **.tar.gz
dist/

View file

@ -12,7 +12,7 @@ builds:
- amd64 - amd64
- arm64 - arm64
flags: flags:
- -tags:all - -tags=all
archives: archives:
- format: tar.gz - format: tar.gz
# this name template makes the OS and Arch compatible with the results of uname. # this name template makes the OS and Arch compatible with the results of uname.
@ -27,7 +27,6 @@ archives:
- LICENSE - LICENSE
- CHANGELOG.md - CHANGELOG.md
- README.md - README.md
- lib/
dockers: dockers:
- -
image_templates: image_templates:
@ -45,7 +44,6 @@ dockers:
- LICENSE - LICENSE
- CHANGELOG.md - CHANGELOG.md
- README.md - README.md
- lib/
checksum: checksum:
name_template: 'checksums.txt' name_template: 'checksums.txt'
snapshot: snapshot:

View file

@ -2,15 +2,13 @@ FROM cgr.dev/chainguard/wolfi-base
RUN apk add --no-cache tini bash RUN apk add --no-cache tini bash
RUN mkdir -p /configurator RUN mkdir -p /configurator
RUN mkdir -p /configurator/lib
# nobody 65534:65534 # nobody 65534:65534
USER 65534:65534 USER 65534:65534
# copy the binary and all of the default plugins # copy the binary and all of the default plugins
COPY configurator /configurator/configurator COPY configurator /configurator/configurator
COPY lib/* /configurator/lib/*
CMD ["/configurator"] CMD ["/configurator/configurator"]
ENTRYPOINT [ "/sbin/tini", "--" ] ENTRYPOINT [ "/sbin/tini", "--" ]

View file

@ -20,7 +20,6 @@ var (
tokenFetchRetries int tokenFetchRetries int
templatePaths []string templatePaths []string
pluginPath string pluginPath string
cacertPath string
useCompression bool 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().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().StringVar(&pluginPath, "plugin", "", "set the generator plugin path")
generateCmd.Flags().StringVarP(&outputPath, "output", "o", "", "set the output path for config targets") 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().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().StringVar(&remoteHost, "host", "http://localhost", "set the remote host")
generateCmd.Flags().IntVar(&remotePort, "port", 80, "set the remote port") generateCmd.Flags().IntVar(&remotePort, "port", 80, "set the remote port")

View file

@ -6,12 +6,14 @@ import (
configurator "github.com/OpenCHAMI/configurator/pkg" configurator "github.com/OpenCHAMI/configurator/pkg"
"github.com/OpenCHAMI/configurator/pkg/util" "github.com/OpenCHAMI/configurator/pkg/util"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var ( var (
configPath string
config configurator.Config config configurator.Config
configPath string
cacertPath string
verbose bool verbose bool
targets []string targets []string
outputPath string outputPath string
@ -40,11 +42,13 @@ func Execute() {
func init() { func init() {
cobra.OnInitialize(initConfig) 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().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() { func initConfig() {
// empty from not being set
if configPath != "" { if configPath != "" {
exists, err := util.PathExists(configPath) exists, err := util.PathExists(configPath)
if err != nil { if err != nil {
@ -53,9 +57,13 @@ func initConfig() {
} else if exists { } else if exists {
config = configurator.LoadConfig(configPath) config = configurator.LoadConfig(configPath)
} else { } 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 { } else {
// set to the default value and create a new one
configPath = "./config.yaml"
config = configurator.NewConfig() config = configurator.NewConfig()
} }

View file

@ -44,7 +44,7 @@ var serveCmd = &cobra.Command{
fmt.Printf("%v\n", string(b)) 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{ server := server.Server{
Config: &config, Config: &config,
Server: &http.Server{ Server: &http.Server{
@ -55,15 +55,15 @@ var serveCmd = &cobra.Command{
Retries: config.Server.Jwks.Retries, Retries: config.Server.Jwks.Retries,
}, },
GeneratorParams: generator.Params{ GeneratorParams: generator.Params{
Args: args, Args: args,
PluginPath: pluginPath, // PluginPath: pluginPath,
// Target: target, // NOTE: targets are set via HTTP requests (ex: curl http://configurator:3334/generate?target=dnsmasq) // Target: target, // NOTE: targets are set via HTTP requests (ex: curl http://configurator:3334/generate?target=dnsmasq)
Verbose: verbose, Verbose: verbose,
}, },
} }
// start listening with the server // start listening with the server
err := server.Serve() err := server.Serve(cacertPath)
if errors.Is(err, http.ErrServerClosed) { if errors.Is(err, http.ErrServerClosed) {
if verbose { if verbose {
fmt.Printf("Server closed.") fmt.Printf("Server closed.")
@ -78,7 +78,7 @@ var serveCmd = &cobra.Command{
func init() { func init() {
serveCmd.Flags().StringVar(&config.Server.Host, "host", config.Server.Host, "set the server host") 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().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().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") serveCmd.Flags().IntVar(&config.Server.Jwks.Retries, "jwks-fetch-retries", config.Server.Jwks.Retries, "set the JWKS fetch retry count")
rootCmd.AddCommand(serveCmd) rootCmd.AddCommand(serveCmd)

View file

@ -12,6 +12,7 @@ import (
"github.com/OpenCHAMI/configurator/pkg/util" "github.com/OpenCHAMI/configurator/pkg/util"
"github.com/nikolalohinski/gonja/v2" "github.com/nikolalohinski/gonja/v2"
"github.com/nikolalohinski/gonja/v2/exec" "github.com/nikolalohinski/gonja/v2/exec"
"github.com/rs/zerolog/log"
) )
type ( type (
@ -35,6 +36,7 @@ type (
TemplatePaths []string TemplatePaths []string
PluginPath string PluginPath string
Target string Target string
Client *configurator.SmdClient
Verbose bool Verbose bool
} }
) )
@ -408,17 +410,24 @@ func Generate(config *configurator.Config, params Params) (FileMap, error) {
func GenerateWithTarget(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 // load generator plugins to generate configs or to print
var ( 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( client = configurator.NewSmdClient(
configurator.WithHost(config.SmdClient.Host), configurator.WithHost(config.SmdClient.Host),
configurator.WithPort(config.SmdClient.Port), configurator.WithPort(config.SmdClient.Port),
configurator.WithAccessToken(config.AccessToken), configurator.WithAccessToken(config.AccessToken),
configurator.WithCertPoolFile(config.CertPath), configurator.WithCertPoolFile(config.CertPath),
) )
target configurator.Target } else {
generator Generator client = *params.Client
err error }
ok bool
)
// check if a target is supplied // check if a target is supplied
if len(params.Args) == 0 && params.Target == "" { if len(params.Args) == 0 && params.Target == "" {
@ -440,6 +449,7 @@ func GenerateWithTarget(config *configurator.Config, params Params) (FileMap, er
generator, ok = DefaultGenerators[params.Target] generator, ok = DefaultGenerators[params.Target]
if !ok { if !ok {
// only load the plugin needed for this target if we don't find default // 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) generator, err = LoadPlugin(target.PluginPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load plugin: %w", err) return nil, fmt.Errorf("failed to load plugin: %w", err)

View file

@ -4,8 +4,11 @@
package server package server
import ( import (
"crypto/tls"
"crypto/x509"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net"
"net/http" "net/http"
"os" "os"
"time" "time"
@ -60,13 +63,33 @@ func New(config *configurator.Config) *Server {
} }
// Main function to start up configurator as a service. // 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 // create client just for the server to use to fetch data from SMD
_ = &configurator.SmdClient{ client := &configurator.SmdClient{
Host: s.Config.SmdClient.Host, Host: s.Config.SmdClient.Host,
Port: s.Config.SmdClient.Port, 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 // set the server address with config values
s.Server.Addr = fmt.Sprintf("%s:%d", s.Config.Server.Host, s.Config.Server.Port) s.Server.Addr = fmt.Sprintf("%s:%d", s.Config.Server.Host, s.Config.Server.Port)
@ -76,7 +99,7 @@ func (s *Server) Serve() error {
var err error var err error
tokenAuth, err = configurator.FetchPublicKeyFromURL(s.Config.Server.Jwks.Uri) tokenAuth, err = configurator.FetchPublicKeyFromURL(s.Config.Server.Jwks.Uri)
if err != nil { if err != nil {
logrus.Errorf("failed to fetch JWKS: %w", err) logrus.Errorf("failed to fetch JWKS: %v", err)
continue continue
} }
break break
@ -104,12 +127,12 @@ func (s *Server) Serve() error {
) )
// protected routes if using auth // protected routes if using auth
r.HandleFunc("/generate", s.Generate) r.HandleFunc("/generate", s.Generate(client))
r.HandleFunc("/templates", s.ManageTemplates) r.HandleFunc("/templates", s.ManageTemplates)
}) })
} else { } else {
// public routes without auth // public routes without auth
router.HandleFunc("/generate", s.Generate) router.HandleFunc("/generate", s.Generate(client))
router.HandleFunc("/templates", s.ManageTemplates) router.HandleFunc("/templates", s.ManageTemplates)
} }
@ -127,32 +150,36 @@ func (s *Server) Close() {
// This is the corresponding service function to generate templated files, that // This is the corresponding service function to generate templated files, that
// works similarly to the CLI variant. This function takes similiar arguments as // works similarly to the CLI variant. This function takes similiar arguments as
// query parameters that are included in the HTTP request URL. // query parameters that are included in the HTTP request URL.
func (s *Server) Generate(w http.ResponseWriter, r *http.Request) { func (s *Server) Generate(client *configurator.SmdClient) 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")
if s.GeneratorParams.Target == "" {
writeErrorResponse(w, "must specify a target")
return
}
// generate a new config file from supplied params return func(w http.ResponseWriter, r *http.Request) {
outputs, err := generator.GenerateWithTarget(s.Config, s.GeneratorParams) // get all of the expect query URL params and validate
if err != nil { s.GeneratorParams.Target = r.URL.Query().Get("target")
writeErrorResponse(w, "failed to generate file: %w", err) s.GeneratorParams.Client = client
return if s.GeneratorParams.Target == "" {
} writeErrorResponse(w, "must specify a target")
return
}
// marshal output to JSON then send response to client // generate a new config file from supplied params
tmp := generator.ConvertContentsToString(outputs) outputs, err := generator.GenerateWithTarget(s.Config, s.GeneratorParams)
b, err := json.Marshal(tmp) if err != nil {
if err != nil { writeErrorResponse(w, "failed to generate file: %v", err)
writeErrorResponse(w, "failed to marshal output: %w", err) return
return }
}
_, err = w.Write(b) // marshal output to JSON then send response to client
if err != nil { tmp := generator.ConvertContentsToString(outputs)
writeErrorResponse(w, "failed to write response: %w", err) b, err := json.Marshal(tmp)
return 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
}
} }
} }
@ -163,7 +190,7 @@ func (s *Server) Generate(w http.ResponseWriter, r *http.Request) {
func (s *Server) ManageTemplates(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")) _, err := w.Write([]byte("this is not implemented yet"))
if err != nil { if err != nil {
writeErrorResponse(w, "failed to write response: %w", err) writeErrorResponse(w, "failed to write response: %v", err)
return return
} }
} }