From 3be8c0c6edef2d875493acddb5f3bba13f60ea1d Mon Sep 17 00:00:00 2001 From: ihatemodels Date: Fri, 29 Mar 2024 14:15:54 +0000 Subject: [PATCH] FEATURE: add files envs for secrets --- .gitignore | 4 +- CONTRIBUTING.md | 45 +++++++++ Makefile | 2 +- README.md | 71 ++++++++------ internal/collector/collector_test.go | 13 ++- internal/options/collectors.go | 34 +++++++ internal/options/exporter.go | 29 ++++++ internal/options/init.go | 13 +++ internal/options/log.go | 38 +++++++ internal/options/ops.go | 142 +++++++++++++++++++++++++++ internal/options/ops_test.go | 18 ++++ main.go | 128 ++++++------------------ opnsense/client.go | 13 +-- 13 files changed, 405 insertions(+), 145 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 internal/options/collectors.go create mode 100644 internal/options/exporter.go create mode 100644 internal/options/init.go create mode 100644 internal/options/log.go create mode 100644 internal/options/ops.go create mode 100644 internal/options/ops_test.go diff --git a/.gitignore b/.gitignore index 5ef7822..8890392 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,6 @@ # Go workspace file go.work *opnsense-exporter-local -local.Makefile \ No newline at end of file +local.Makefile +key +secret \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ea2a0cc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,45 @@ +## Contributing + +### Requirements + +- Go 1.22 +- GNU Make +- Docker (optional) +- OPNsense Box with admin access + +### Environment + +This guide is for osx and Linux. + +### Create API key and secret in OPNsense + +`SYSTEM>ACCESS>USERS>[user]>API KEYS` + +[OPNsense Documentation](https://docs.opnsense.org/development/how-tos/api.html#creating-keys) + +### Run the exporter locally + +```bash +OPS_ADDRESS="ops.example.com" OPS_API_KEY=your-api-key OPS_API_SECRET=your-api-secret make local-run +``` + +- test it + +```bash +curl http://localhost:8080/metrics +``` + +### Before PR + +- Make sure to sync the vendor if the dependencies have changed. + +```bash +make sync-vendor +``` + +- Make sure to run the tests and linters. + +```bash +make test +make lint +``` diff --git a/Makefile b/Makefile index dbd9a92..970cf94 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ local-run: --web.disable-exporter-metrics \ test: - go test -v ./... + go test ./... clean: gofmt -s -w $(shell find . -type f -name '*.go'| grep -v "/vendor/\|/.git/") diff --git a/README.md b/README.md index 0a7003d..0968836 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ The missing OPNsense exporter for Prometheus ## Table of Contents - **[About](#about)** +- **[Contributing](./CONTRIBUTING.md)** - **[OPNsense User Permissions](#opnsense-user-permissions)** -- **[Development](#development)** - **[Usage](#usage)** - **[Docker](#docker)** - **[Docker Compose](#docker-compose)** @@ -31,37 +31,6 @@ Focusing specifically on OPNsense, this exporter provides metrics about OPNsense While the `node_exporter` must be installed on the firewall itself, this exporter can be installed on any machine that has network access to the OPNsense API. -## Development - -This guide is for osx and Linux. - -### Create API key and secret in OPNsense - -`SYSTEM>ACCESS>USERS>[user]>API KEYS` - -[OPNsense Documentation](https://docs.opnsense.org/development/how-tos/api.html#creating-keys) - -### Run the exporter locally - -```bash -OPS_ADDRESS="ops.example.com" OPS_API_KEY=your-api-key OPS_API_SECRET=your-api-secret make local-run -curl http://localhost:8080/metrics -``` - -### Before PR - -- Make sure to sync the vendor if the dependencies have changed. - -```bash -make sync-vendor -``` - -- Make sure to run the tests and linters. - -```bash -make test -make lint -``` ## OPNsense user permissions @@ -92,6 +61,8 @@ TODO: Add example how to add custom CA certificates to the container. ### Docker Compose +- With environment variables + ```yaml version: '3' services: @@ -114,6 +85,42 @@ services: - "8080:8080" ``` +- With docker secrets + +Create the secrets + +```bash +echo "" | docker secret create opnsense-api-key - +echo "" | docker secret create opnsense-api-secret - +``` + +Run the compose + +```yaml +version: '3' +services: + opnsense-exporter: + image: ghcr.io/athennamind/opnsense-exporter:latest + container_name: opensense-exporter + restart: always + command: + - /opnsense-exporter + - --opnsense.protocol=https + - --opnsense.address=ops.example.com + - --exporter.instance-label=instance1 + - --web.listen-address=:8080 + #- --exporter.disable-arp-table + #- --exporter.disable-cron-table + environment: + OPS_API_KEY_FILE: /run/secrets/opnsense-api-key + OPS_API_SECRET_FILE: /run/secrets/opnsense-api-secret + secrets: + - opnsense_api_key + - opnsense_api_secret + ports: + - "8080:8080" +``` + ### Systemd **TODO** diff --git a/internal/collector/collector_test.go b/internal/collector/collector_test.go index 17b75ad..5ccf633 100644 --- a/internal/collector/collector_test.go +++ b/internal/collector/collector_test.go @@ -3,20 +3,23 @@ package collector import ( "testing" + "github.com/AthennaMind/opnsense-exporter/internal/options" "github.com/AthennaMind/opnsense-exporter/opnsense" "github.com/go-kit/log" ) func TestWithoutArpCollector(t *testing.T) { + conf := options.OPNSenseConfig{ + Protocol: "http", + APIKey: "test", + } + client, err := opnsense.NewClient( + conf, "test", - "test", - "test", - "test", - "test", - false, log.NewNopLogger(), ) + if err != nil { t.Errorf("Expected no error, got %v", err) } diff --git a/internal/options/collectors.go b/internal/options/collectors.go new file mode 100644 index 0000000..0b8fcb2 --- /dev/null +++ b/internal/options/collectors.go @@ -0,0 +1,34 @@ +package options + +import "github.com/alecthomas/kingpin/v2" + +var ( + arpTableCollectorDisabled = kingpin.Flag( + "exporter.disable-arp-table", + "Disable the scraping of the ARP table", + ).Envar("OPNSENSE_EXPORTER_DISABLE_ARP_TABLE").Default("false").Bool() + cronTableCollectorDisabled = kingpin.Flag( + "exporter.disable-cron-table", + "Disable the scraping of the cron table", + ).Envar("OPNSENSE_EXPORTER_DISABLE_CRON_TABLE").Default("false").Bool() + wireguardCollectorDisabled = kingpin.Flag( + "exporter.disable-wireguard", + "Disable the scraping of Wireguard service", + ).Envar("OPNSENSE_EXPORTER_DISABLE_WIREGUARD").Default("false").Bool() +) + +// Collectors holds the configuration for the collectors +type CollectorsSwitches struct { + ARP bool + Cron bool + Wireguard bool +} + +// Collectors returns the configuration for the collectors +func Collectors() CollectorsSwitches { + return CollectorsSwitches{ + ARP: !*arpTableCollectorDisabled, + Cron: !*cronTableCollectorDisabled, + Wireguard: !*wireguardCollectorDisabled, + } +} diff --git a/internal/options/exporter.go b/internal/options/exporter.go new file mode 100644 index 0000000..53f1964 --- /dev/null +++ b/internal/options/exporter.go @@ -0,0 +1,29 @@ +package options + +import ( + "github.com/alecthomas/kingpin/v2" + "github.com/prometheus/exporter-toolkit/web/kingpinflag" +) + +var ( + MetricsPath = kingpin.Flag( + "web.telemetry-path", + "Path under which to expose metrics.", + ).Default("/metrics").String() + DisableExporterMetrics = kingpin.Flag( + "web.disable-exporter-metrics", + "Exclude metrics about the exporter itself (promhttp_*, process_*, go_*).", + ).Envar("OPNSENSE_EXPORTER_DISABLE_EXPORTER_METRICS").Bool() + MaxProcs = kingpin.Flag( + "runtime.gomaxprocs", + "The target number of CPUs that the Go runtime will run on (GOMAXPROCS)", + ).Envar("GOMAXPROCS").Default("2").Int() + InstanceLabel = kingpin.Flag( + "exporter.instance-label", + "Label to use to identify the instance in every metric. "+ + "If you have multiple instances of the exporter, you can differentiate them by using "+ + "different value in this flag, that represents the instance of the target OPNsense.", + ).Envar("OPNSENSE_EXPORTER_INSTANCE_LABEL").Required().String() + + WebConfig = kingpinflag.AddFlags(kingpin.CommandLine, ":8080") +) diff --git a/internal/options/init.go b/internal/options/init.go new file mode 100644 index 0000000..1491244 --- /dev/null +++ b/internal/options/init.go @@ -0,0 +1,13 @@ +package options + +import ( + "os" + + "github.com/alecthomas/kingpin/v2" +) + +func Init() { + kingpin.CommandLine.UsageWriter(os.Stdout) + kingpin.HelpFlag.Short('h') + kingpin.Parse() +} diff --git a/internal/options/log.go b/internal/options/log.go new file mode 100644 index 0000000..ad945e1 --- /dev/null +++ b/internal/options/log.go @@ -0,0 +1,38 @@ +package options + +import ( + "github.com/alecthomas/kingpin/v2" + "github.com/go-kit/log" + "github.com/prometheus/common/promlog" +) + +var ( + logLevel = kingpin.Flag( + "log.level", + "Log level. One of: [debug, info, warn, error]"). + Default("info"). + String() + logFormat = kingpin.Flag( + "log.format", + "Log format. One of: [logfmt, json]"). + Default("logfmt"). + String() +) + +func Logger() (log.Logger, error) { + + promlogConfig := &promlog.Config{ + Level: &promlog.AllowedLevel{}, + Format: &promlog.AllowedFormat{}, + } + + if err := promlogConfig.Level.Set(*logLevel); err != nil { + return nil, err + } + + if err := promlogConfig.Format.Set(*logFormat); err != nil { + return nil, err + } + + return promlog.New(promlogConfig), nil +} diff --git a/internal/options/ops.go b/internal/options/ops.go new file mode 100644 index 0000000..4c3d4de --- /dev/null +++ b/internal/options/ops.go @@ -0,0 +1,142 @@ +package options + +import ( + "bufio" + "errors" + "fmt" + "os" + "strings" + + "github.com/alecthomas/kingpin/v2" +) + +var ( + opnsenseProtocol = kingpin.Flag( + "opnsense.protocol", + "Protocol to use to connect to OPNsense API. One of: [http, https]", + ).Envar("OPNSENSE_EXPORTER_OPS_PROTOCOL").Required().String() + opnsenseAPI = kingpin.Flag( + "opnsense.address", + "Hostname or IP address of OPNsense API", + ).Envar("OPNSENSE_EXPORTER_OPS_API").Required().String() + opnsenseAPIKey = kingpin.Flag( + "opnsense.api-key", + "API key to use to connect to OPNsense API. This flag/ENV or the OPS_API_KEY_FILE my be set.", + ).Default("").Envar("OPNSENSE_EXPORTER_OPS_API_KEY").String() + opnsenseAPISecret = kingpin.Flag( + "opnsense.api-secret", + "API secret to use to connect to OPNsense API. This flag/ENV or the OPS_API_SECRET_FILE my be set.", + ).Default("").Envar("OPNSENSE_EXPORTER_OPS_API_SECRET").String() + opnsenseInsecure = kingpin.Flag( + "opnsense.insecure", + "Disable TLS certificate verification", + ).Envar("OPNSENSE_EXPORTER_OPS_INSECURE").Default("false").Bool() +) + +// ReadFirstLine opens a file and reads its first line. +// It returns the first line as a string and any error encountered. +func getLineFromFile(filePath string) (string, error) { + file, err := os.Open(filePath) + if err != nil { + return "", err // Return an empty string and the error + } + defer file.Close() + + scanner := bufio.NewScanner(file) + if scanner.Scan() { + return strings.TrimSpace(scanner.Text()), nil + } + + if err := scanner.Err(); err != nil { + return "", err + } + + return "", nil +} + +func opsAPISecret() (string, error) { + if env, ok := os.LookupEnv("OPS_API_SECRET_FILE"); ok { + apiKey, err := getLineFromFile(env) + if err != nil { + return "", errors.Join(fmt.Errorf("failed to read OPS_API_SECRET_FILE"), err) + } + if len(apiKey) > 0 { + return apiKey, nil + } + } + if *opnsenseAPIKey == "" { + return "", fmt.Errorf("opnsense.api-secret or OPS_API_SECRET_FILE must be set") + } + + return *opnsenseAPISecret, nil +} + +func opsAPIKey() (string, error) { + if env, ok := os.LookupEnv("OPS_API_KEY_FILE"); ok { + apiSecret, err := getLineFromFile(env) + if err != nil { + return "", errors.Join(fmt.Errorf("failed to read OPS_API_KEY_FILE"), err) + } + if len(apiSecret) > 0 { + return apiSecret, nil + } + } + if *opnsenseAPISecret == "" { + return "", fmt.Errorf("opnsense.api-key or OPS_API_KEY_FILE must be set") + } + + return *opnsenseAPIKey, nil +} + +type OPNSenseConfig struct { + Protocol string + Host string + APIKey string + APISecret string + Insecure bool +} + +func (c *OPNSenseConfig) String() string { + return fmt.Sprintf("Protocol: %s, Host: %s, APIKey: %s, APISecret: %s, Insecure: %t", + c.Protocol, c.Host, c.APIKey, c.APISecret, c.Insecure) +} + +func (c *OPNSenseConfig) Validate() error { + if c.Protocol != "http" && c.Protocol != "https" { + return fmt.Errorf("protocol must be one of: [http, https]") + } + if c.Host == "" { + return fmt.Errorf("host must be set") + } + if c.APIKey == "" { + return fmt.Errorf("api-key must be set") + } + if c.APISecret == "" { + return fmt.Errorf("api-secret must be set") + } + return nil +} + +func OPNSense() (*OPNSenseConfig, error) { + apiKey, err := opsAPIKey() + if err != nil { + return nil, err + } + apiSecret, err := opsAPISecret() + if err != nil { + return nil, err + } + conf := &OPNSenseConfig{ + Protocol: strings.TrimSpace(*opnsenseProtocol), + Host: strings.TrimSpace(*opnsenseAPI), + APIKey: apiKey, + APISecret: apiSecret, + Insecure: *opnsenseInsecure, + } + + if err := conf.Validate(); err != nil { + return nil, err + } + + return conf, nil +} diff --git a/internal/options/ops_test.go b/internal/options/ops_test.go new file mode 100644 index 0000000..f094068 --- /dev/null +++ b/internal/options/ops_test.go @@ -0,0 +1,18 @@ +package options + +import ( + "testing" +) + +func TestOPNSenseConfig(t *testing.T) { + conf := OPNSenseConfig{ + Protocol: "ftp", + Host: "test", + APIKey: "test", + APISecret: "test", + } + + if err := conf.Validate(); err == nil { + t.Errorf("expected invalid protocol error, got nil") + } +} diff --git a/main.go b/main.go index e369473..ddb58c3 100644 --- a/main.go +++ b/main.go @@ -9,121 +9,47 @@ import ( "syscall" "github.com/AthennaMind/opnsense-exporter/internal/collector" + "github.com/AthennaMind/opnsense-exporter/internal/options" "github.com/AthennaMind/opnsense-exporter/opnsense" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" promcollectors "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/prometheus/common/promlog" "github.com/prometheus/exporter-toolkit/web" - "github.com/prometheus/exporter-toolkit/web/kingpinflag" ) var version = "" func main() { - var ( - logLevel = kingpin.Flag( - "log.level", - "Log level. One of: [debug, info, warn, error]"). - Default("info"). - String() - logFormat = kingpin.Flag( - "log.format", - "Log format. One of: [logfmt, json]"). - Default("logfmt"). - String() - metricsPath = kingpin.Flag( - "web.telemetry-path", - "Path under which to expose metrics.", - ).Default("/metrics").String() - disableExporterMetrics = kingpin.Flag( - "web.disable-exporter-metrics", - "Exclude metrics about the exporter itself (promhttp_*, process_*, go_*).", - ).Envar("OPNSENSE_EXPORTER_DISABLE_EXPORTER_METRICS").Bool() - maxProcs = kingpin.Flag( - "runtime.gomaxprocs", - "The target number of CPUs that the Go runtime will run on (GOMAXPROCS)", - ).Envar("GOMAXPROCS").Default("2").Int() - instanceLabel = kingpin.Flag( - "exporter.instance-label", - "Label to use to identify the instance in every metric. "+ - "If you have multiple instances of the exporter, you can differentiate them by using "+ - "different value in this flag, that represents the instance of the target OPNsense.", - ).Envar("OPNSENSE_EXPORTER_INSTANCE_LABEL").Required().String() - arpTableCollectorDisabled = kingpin.Flag( - "exporter.disable-arp-table", - "Disable the scraping of the ARP table", - ).Envar("OPNSENSE_EXPORTER_DISABLE_ARP_TABLE").Default("false").Bool() - cronTableCollectorDisabled = kingpin.Flag( - "exporter.disable-cron-table", - "Disable the scraping of the cron table", - ).Envar("OPNSENSE_EXPORTER_DISABLE_CRON_TABLE").Default("false").Bool() - wireguardCollectorDisabled = kingpin.Flag( - "exporter.disable-wireguard", - "Disable the scraping of Wireguard service", - ).Envar("OPNSENSE_EXPORTER_DISABLE_WIREGUARD").Default("false").Bool() - opnsenseProtocol = kingpin.Flag( - "opnsense.protocol", - "Protocol to use to connect to OPNsense API. One of: [http, https]", - ).Envar("OPNSENSE_EXPORTER_OPS_PROTOCOL").Required().String() - opnsenseAPI = kingpin.Flag( - "opnsense.address", - "Hostname or IP address of OPNsense API", - ).Envar("OPNSENSE_EXPORTER_OPS_API").Required().String() - opnsenseAPIKey = kingpin.Flag( - "opnsense.api-key", - "API key to use to connect to OPNsense API", - ).Envar("OPNSENSE_EXPORTER_OPS_API_KEY").Required().String() - opnsenseAPISecret = kingpin.Flag( - "opnsense.api-secret", - "API secret to use to connect to OPNsense API", - ).Envar("OPNSENSE_EXPORTER_OPS_API_SECRET").Required().String() - opnsenseInsecure = kingpin.Flag( - "opnsense.insecure", - "Disable TLS certificate verification", - ).Envar("OPNSENSE_EXPORTER_OPS_INSECURE").Default("false").Bool() - - webConfig = kingpinflag.AddFlags(kingpin.CommandLine, ":8080") - ) - - kingpin.CommandLine.UsageWriter(os.Stdout) - kingpin.HelpFlag.Short('h') - kingpin.Parse() - - promlogConfig := &promlog.Config{ - Level: &promlog.AllowedLevel{}, - Format: &promlog.AllowedFormat{}, - } + options.Init() - if err := promlogConfig.Level.Set(*logLevel); err != nil { - fmt.Fprintf(os.Stderr, "error setting log level: %v\n", err) - os.Exit(1) - } + logger, err := options.Logger() - if err := promlogConfig.Format.Set(*logFormat); err != nil { - fmt.Fprintf(os.Stderr, "error setting log format: %v\n", err) + if err != nil { + fmt.Fprintf(os.Stderr, "error creating logger: %v\n", err) os.Exit(1) } - logger := promlog.New(promlogConfig) - level.Info(logger). - Log("msg", "Starting opnsense-exporter", "version", version) + Log("msg", "starting opnsense-exporter", "version", version) - runtime.GOMAXPROCS(*maxProcs) + runtime.GOMAXPROCS(*options.MaxProcs) level.Debug(logger). Log("msg", "settings Go MAXPROCS", "procs", runtime.GOMAXPROCS(0)) + opnsConfig, err := options.OPNSense() + + if err != nil { + level.Error(logger). + Log("msg", "failed to assemble OPNsense configuration", "err", err) + os.Exit(1) + } + + fmt.Printf("opnsConfig: %v+\n", opnsConfig) opnsenseClient, err := opnsense.NewClient( - *opnsenseProtocol, - *opnsenseAPI, - *opnsenseAPIKey, - *opnsenseAPISecret, + *opnsConfig, version, - *opnsenseInsecure, logger, ) @@ -139,7 +65,7 @@ func main() { r := prometheus.NewRegistry() - if !*disableExporterMetrics { + if !*options.DisableExporterMetrics { r.MustRegister( promcollectors.NewProcessCollector(promcollectors.ProcessCollectorOpts{}), ) @@ -148,19 +74,21 @@ func main() { collectorOptionFuncs := []collector.Option{} - if *arpTableCollectorDisabled { + collectorsSwitches := options.Collectors() + + if collectorsSwitches.ARP { collectorOptionFuncs = append(collectorOptionFuncs, collector.WithoutArpTableCollector()) } - if *cronTableCollectorDisabled { + if collectorsSwitches.Cron { collectorOptionFuncs = append(collectorOptionFuncs, collector.WithoutCronCollector()) } - if *wireguardCollectorDisabled { + if collectorsSwitches.Wireguard { collectorOptionFuncs = append(collectorOptionFuncs, collector.WithoutWireguardCollector()) } - collectorInstance, err := collector.New(&opnsenseClient, logger, *instanceLabel, collectorOptionFuncs...) + collectorInstance, err := collector.New(&opnsenseClient, logger, *options.InstanceLabel, collectorOptionFuncs...) if err != nil { level.Error(logger). @@ -170,16 +98,16 @@ func main() { r.MustRegister(collectorInstance) handler := promhttp.HandlerFor(r, promhttp.HandlerOpts{}) - http.Handle(*metricsPath, handler) + http.Handle(*options.MetricsPath, handler) - if *metricsPath != "/" && *metricsPath != "" { + if *options.MetricsPath != "/" && *options.MetricsPath != "" { landingConfig := web.LandingConfig{ Name: "OPNsense Exporter", Description: "Prometheus OPNsense Firewall Exporter", Version: version, Links: []web.LandingLinks{ { - Address: *metricsPath, + Address: *options.MetricsPath, Text: "Metrics", }, }, @@ -198,7 +126,7 @@ func main() { srv := &http.Server{} go func() { - if err := web.ListenAndServe(srv, webConfig, logger); err != nil { + if err := web.ListenAndServe(srv, options.WebConfig, logger); err != nil { level.Error(logger). Log("msg", "Error received from the HTTP server", "err", err) close(srvClose) diff --git a/opnsense/client.go b/opnsense/client.go index 7b5627f..f0c9749 100644 --- a/opnsense/client.go +++ b/opnsense/client.go @@ -13,6 +13,7 @@ import ( "runtime" "time" + "github.com/AthennaMind/opnsense-exporter/internal/options" "github.com/go-kit/log" "github.com/go-kit/log/level" ) @@ -42,7 +43,7 @@ type Client struct { } // NewClient creates a new OPNsense API Client -func NewClient(protocol, address, key, secret, userAgentVersion string, sslInsecure bool, log log.Logger) (Client, error) { +func NewClient(cfg options.OPNSenseConfig, userAgentVersion string, log log.Logger) (Client, error) { sslPool, err := x509.SystemCertPool() @@ -62,9 +63,9 @@ func NewClient(protocol, address, key, secret, userAgentVersion string, sslInsec } client := Client{ log: log, - baseURL: fmt.Sprintf("%s://%s", protocol, address), - key: key, - secret: secret, + baseURL: fmt.Sprintf("%s://%s", cfg.Protocol, cfg.Host), + key: cfg.APIKey, + secret: cfg.APISecret, gatewayLossRegex: gatewayLossRegex, gatewayRTTRegex: gatewayRTTRegex, endpoints: map[EndpointName]EndpointPath{ @@ -85,12 +86,12 @@ func NewClient(protocol, address, key, secret, userAgentVersion string, sslInsec "User-Agent": fmt.Sprintf("prometheus-opnsense-exporter/%s", userAgentVersion), "Accept-Encoding": "gzip, deflate, br", }, - sslInsecure: sslInsecure, + sslInsecure: cfg.Insecure, httpClient: &http.Client{ Timeout: 10 * time.Second, Transport: &http.Transport{ TLSClientConfig: &tls.Config{ - InsecureSkipVerify: sslInsecure, + InsecureSkipVerify: cfg.Insecure, RootCAs: sslPool, }, IdleConnTimeout: 90 * time.Second,