diff options
author | Vladimir Shushlin <vshushlin@gitlab.com> | 2022-06-03 13:25:31 +0300 |
---|---|---|
committer | Vladimir Shushlin <vshushlin@gitlab.com> | 2022-06-03 13:25:31 +0300 |
commit | fd62cfc0771c627bd1bda001fd1fa71178dd447b (patch) | |
tree | dc70546496ad01228802f6fa6298c7ae7f7827ea /internal | |
parent | 3c89945269c643b8b3b55d1d967c19922101c48c (diff) | |
parent | 1ddad1bd6ab55120e7862c61e033632b20e66d6f (diff) |
Merge branch 'tls-metrics' into 'master'
Add TLS for metrics
See merge request gitlab-org/gitlab-pages!772
Diffstat (limited to 'internal')
-rw-r--r-- | internal/config/config.go | 55 | ||||
-rw-r--r-- | internal/config/config_test.go | 85 | ||||
-rw-r--r-- | internal/config/flags.go | 2 |
3 files changed, 140 insertions, 2 deletions
diff --git a/internal/config/config.go b/internal/config/config.go index f3650ffb..18fe33eb 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,7 +1,9 @@ package config import ( + "crypto/tls" "encoding/base64" + "errors" "fmt" "os" "strings" @@ -23,6 +25,7 @@ type Config struct { Server Server TLS TLS Zip ZipServing + Metrics Metrics // These fields contain the raw strings passed for listen-http, // listen-https, listen-proxy and listen-https-proxyv2 settings. It is used @@ -39,7 +42,6 @@ type General struct { Domain string MaxConns int MaxURILength int - MetricsAddress string RedirectHTTP bool RootCertificate []byte RootDir string @@ -146,6 +148,16 @@ type Server struct { ListenKeepAlive time.Duration } +type Metrics struct { + Address string + TLSConfig *tls.Config +} + +var ( + errMetricsNoCertificate = errors.New("metrics certificate path must not be empty") + errMetricsNoKey = errors.New("metrics private key path must not be empty") +) + func internalGitlabServerFromFlags() string { if *internalGitLabServer != "" { return *internalGitLabServer @@ -186,13 +198,45 @@ func setGitLabAPISecretKey(secretFile string, config *Config) error { return nil } +func loadMetricsConfig() (metrics Metrics, err error) { + // don't validate anything if metrics are disabled + if *metricsAddress == "" { + return metrics, nil + } + metrics.Address = *metricsAddress + + // no error when using HTTP + if *metricsCertificate == "" && *metricsKey == "" { + return metrics, nil + } + + if *metricsCertificate == "" { + return metrics, errMetricsNoCertificate + } + + if *metricsKey == "" { + return metrics, errMetricsNoKey + } + + cert, err := tls.LoadX509KeyPair(*metricsCertificate, *metricsKey) + if err != nil { + return metrics, err + } + + metrics.TLSConfig = &tls.Config{ + Certificates: []tls.Certificate{cert}, + MinVersion: tls.VersionTLS12, + } + + return metrics, nil +} + func loadConfig() (*Config, error) { config := &Config{ General: General{ Domain: strings.ToLower(*pagesDomain), MaxConns: *maxConns, MaxURILength: *maxURILength, - MetricsAddress: *metricsAddress, RedirectHTTP: *redirectHTTP, RootDir: *pagesRoot, StatusPath: *pagesStatus, @@ -276,6 +320,11 @@ func loadConfig() (*Config, error) { var err error + // Validating and populating Metrics config + if config.Metrics, err = loadMetricsConfig(); err != nil { + return nil, err + } + // Populating remaining General settings for _, file := range []struct { contents *[]byte @@ -319,6 +368,8 @@ func LogConfig(config *Config) { "listen-https-proxyv2": listenHTTPSProxyv2, "log-format": *logFormat, "metrics-address": *metricsAddress, + "metrics-certificate": *metricsCertificate, + "metrics-key": *metricsKey, "pages-domain": *pagesDomain, "pages-root": *pagesRoot, "pages-status": *pagesStatus, diff --git a/internal/config/config_test.go b/internal/config/config_test.go new file mode 100644 index 00000000..f120d17d --- /dev/null +++ b/internal/config/config_test.go @@ -0,0 +1,85 @@ +package config + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "gitlab.com/gitlab-org/gitlab-pages/internal/fixture" +) + +func Test_loadMetricsConfig(t *testing.T) { + defaultMetricsAdress := ":9325" + defaultDir, defaultMetricsKey, defaultMetricsCertificate := setupHTTPSFixture(t) + + tests := map[string]struct { + metricsAddress string + metricsCertificate string + metricsKey string + expectedError error + }{ + "no metrics": {}, + "http metrics": { + metricsAddress: defaultMetricsAdress, + }, + "https metrics": { + metricsAddress: defaultMetricsAdress, + metricsCertificate: defaultMetricsCertificate, + metricsKey: defaultMetricsKey, + }, + "https metrics no certificate": { + metricsAddress: defaultMetricsAdress, + metricsKey: defaultMetricsKey, + expectedError: errMetricsNoCertificate, + }, + "https metrics no key": { + metricsAddress: defaultMetricsAdress, + metricsCertificate: defaultMetricsCertificate, + expectedError: errMetricsNoKey, + }, + "https metrics invalid certificate path": { + metricsAddress: defaultMetricsAdress, + metricsCertificate: filepath.Join(defaultDir, "domain.certificate.missing"), + metricsKey: defaultMetricsKey, + expectedError: os.ErrNotExist, + }, + "https metrics invalid key path": { + metricsAddress: defaultMetricsAdress, + metricsCertificate: defaultMetricsCertificate, + metricsKey: filepath.Join(defaultDir, "domain.key.missing"), + expectedError: os.ErrNotExist, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + metricsAddress = &tc.metricsAddress + metricsCertificate = &tc.metricsCertificate + metricsKey = &tc.metricsKey + _, err := loadMetricsConfig() + require.ErrorIs(t, err, tc.expectedError) + }) + } +} + +func setupHTTPSFixture(t *testing.T) (dir string, key string, cert string) { + t.Helper() + + tmpDir := t.TempDir() + + keyfile, err := os.CreateTemp(tmpDir, "https-fixture") + require.NoError(t, err) + key = keyfile.Name() + keyfile.Close() + + certfile, err := os.CreateTemp(tmpDir, "https-fixture") + require.NoError(t, err) + cert = certfile.Name() + certfile.Close() + + require.NoError(t, os.WriteFile(key, []byte(fixture.Key), 0644)) + require.NoError(t, os.WriteFile(cert, []byte(fixture.Certificate), 0644)) + + return tmpDir, keyfile.Name(), certfile.Name() +} diff --git a/internal/config/flags.go b/internal/config/flags.go index 23da47ed..88ebbb15 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -40,6 +40,8 @@ var ( artifactsServerTimeout = flag.Int("artifacts-server-timeout", 10, "Timeout (in seconds) for a proxied request to the artifacts server") pagesStatus = flag.String("pages-status", "", "The url path for a status page, e.g., /@status") metricsAddress = flag.String("metrics-address", "", "The address to listen on for metrics requests") + metricsCertificate = flag.String("metrics-certificate", "", "The default path to file certificate to serve metrics requests") + metricsKey = flag.String("metrics-key", "", "The default path to file private key to serve metrics requests") sentryDSN = flag.String("sentry-dsn", "", "The address for sending sentry crash reporting to") sentryEnvironment = flag.String("sentry-environment", "", "The environment for sentry crash reporting") propagateCorrelationID = flag.Bool("propagate-correlation-id", false, "Reuse existing Correlation-ID from the incoming request header `X-Request-ID` if present") |