diff --git a/Makefile b/Makefile index 333f80cfe8..527fae36d7 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ clean-scheduler: @rm -rf src/scheduler/src/test/resources/certs clean-certs: @echo " - cleaning test certs" - @rm -f testcerts/* + @rm -f test-certs/* clean-bosh-release: @echo " - cleaning bosh dev releases" @rm -rf dev_releases diff --git a/scripts/generate_test_certs.sh b/scripts/generate_test_certs.sh index 9397172a43..029cc3cc16 100755 --- a/scripts/generate_test_certs.sh +++ b/scripts/generate_test_certs.sh @@ -1,6 +1,7 @@ #!/bin/bash set -e + script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" # Place keys and certificates here @@ -20,11 +21,17 @@ ${CERTSTRAP} --depot-path "${depot_path}" init --passphrase '' --common-name log mv -f "${depot_path}"/loggregatorCA.crt "${depot_path}"/loggregator-ca.crt mv -f "${depot_path}"/loggregatorCA.key "${depot_path}"/loggregator-ca.key +# CA to distribute to dummy syslog emitter certs +${CERTSTRAP} --depot-path "${depot_path}" init --passphrase '' --common-name LogCacheSyslogServerCA --years "20" +mv -f "${depot_path}"/LogCacheSyslogServerCA.crt "${depot_path}"/log-cache-syslog-server-ca.crt +mv -f "${depot_path}"/LogCacheSyslogServerCA.key "${depot_path}"/log-cache-syslog-server-ca.key + # CA for local testing mTLS certs ${CERTSTRAP} --depot-path "${depot_path}" init --passphrase '' --common-name validMTLSLocalCA --years "20" mv -f "${depot_path}"/validMTLSLocalCA.crt "${depot_path}"/valid-mtls-local-ca-1.crt mv -f "${depot_path}"/validMTLSLocalCA.key "${depot_path}"/valid-mtls-local-ca-1.key rm -f "${depot_path}"/validMTLSLocalCA.crl + ${CERTSTRAP} --depot-path "${depot_path}" init --passphrase '' --common-name validMTLSLocalCA --years "20" mv -f "${depot_path}"/validMTLSLocalCA.crt "${depot_path}"/valid-mtls-local-ca-2.crt mv -f "${depot_path}"/validMTLSLocalCA.key "${depot_path}"/valid-mtls-local-ca-2.key @@ -88,6 +95,11 @@ ${CERTSTRAP} --depot-path "${depot_path}" sign metricserver_client --CA autoscal ${CERTSTRAP} --depot-path "${depot_path}" request-cert --passphrase '' --domain metron ${CERTSTRAP} --depot-path "${depot_path}" sign metron --CA loggregator-ca --years "20" + +# metricsforwarder certificate for log-cache-syslog-server +${CERTSTRAP} --depot-path "${depot_path}" request-cert --passphrase '' --domain cf-app +${CERTSTRAP} --depot-path "${depot_path}" sign cf-app --CA log-cache-syslog-server-ca --years "20" + # mTLS client certificate for local testing ## certstrap with multiple OU not working at the moment. Pull request is created in the upstream. Therefore, using openssl at the moment ## https://github.com/square/certstrap/pull/120 diff --git a/src/autoscaler/metricsforwarder/config/config.go b/src/autoscaler/metricsforwarder/config/config.go index fc380ed11a..c46d2a9679 100644 --- a/src/autoscaler/metricsforwarder/config/config.go +++ b/src/autoscaler/metricsforwarder/config/config.go @@ -60,8 +60,9 @@ type LoggregatorConfig struct { } type SyslogConfig struct { - ServerAddress string `yaml:"server_address"` - Port int `yaml:"port"` + ServerAddress string `yaml:"server_address"` + Port int `yaml:"port"` + TLS models.TLSCerts `yaml:"tls"` } func LoadConfig(reader io.Reader) (*Config, error) { diff --git a/src/autoscaler/metricsforwarder/forwarder/deleteme b/src/autoscaler/metricsforwarder/forwarder/deleteme new file mode 100644 index 0000000000..dad38f418b --- /dev/null +++ b/src/autoscaler/metricsforwarder/forwarder/deleteme @@ -0,0 +1,3 @@ + <14>1 1970-01-01T00:00:00.012345+00:00 test-hostname test-app-id [1] - [gauge@47450 name=\"disk_quota\" value=\"1024\" unit=\"bytes\"] +128 <14>1 2024-05-08T10:00:53.338737+00:00 test-hostname dummy-guid [1] - [gauge@47450 name="queuelength" value="12.5" unit="bytes"] + diff --git a/src/autoscaler/metricsforwarder/forwarder/syslog_emitter.go b/src/autoscaler/metricsforwarder/forwarder/syslog_emitter.go index 01849b7123..8be1d76e9e 100644 --- a/src/autoscaler/metricsforwarder/forwarder/syslog_emitter.go +++ b/src/autoscaler/metricsforwarder/forwarder/syslog_emitter.go @@ -9,13 +9,13 @@ import ( "code.cloudfoundry.org/app-autoscaler/src/autoscaler/models" "code.cloudfoundry.org/go-loggregator/v9/rpc/loggregator_v2" "code.cloudfoundry.org/lager/v3" + "code.cloudfoundry.org/loggregator-agent-release/src/pkg/egress" "code.cloudfoundry.org/loggregator-agent-release/src/pkg/egress/syslog" ) type SyslogEmitter struct { - url string - hostname string - netConf syslog.NetworkTimeoutConfig + netConf syslog.NetworkTimeoutConfig + Writer egress.WriteCloser } type Counter struct{} @@ -31,31 +31,31 @@ func NewSyslogEmitter(logger lager.Logger, conf *config.Config) (Emitter, error) DialTimeout: 100 * time.Millisecond, } - return &SyslogEmitter{ - url: conf.SyslogConfig.ServerAddress, - hostname: "test-hostname", - netConf: netConf, - }, nil -} - -func (mf *SyslogEmitter) EmitMetric(metric *models.CustomMetric) { - url, _ := url.Parse(fmt.Sprintf("syslog-tls://%s", mf.url)) + url, _ := url.Parse(fmt.Sprintf("syslog-tls://%s", conf.SyslogConfig.ServerAddress)) binding := &syslog.URLBinding{ URL: url, - Hostname: mf.hostname, + Hostname: "test-hostname", } - w := syslog.NewTCPWriter( + writer := syslog.NewTCPWriter( binding, - mf.netConf, + netConf, &Counter{}, syslog.NewConverter(), ) + return &SyslogEmitter{ + Writer: writer, + }, nil +} + +func (mf *SyslogEmitter) EmitMetric(metric *models.CustomMetric) { + e := &loggregator_v2.Envelope{ - Timestamp: time.Now().UnixNano(), - SourceId: metric.AppGUID, + InstanceId: fmt.Sprintf("%d", metric.InstanceIndex), + Timestamp: time.Now().UnixNano(), + SourceId: metric.AppGUID, Message: &loggregator_v2.Envelope_Gauge{ Gauge: &loggregator_v2.Gauge{ Metrics: map[string]*loggregator_v2.GaugeValue{ @@ -68,6 +68,6 @@ func (mf *SyslogEmitter) EmitMetric(metric *models.CustomMetric) { }, } - w.Write(e) + mf.Writer.Write(e) } diff --git a/src/autoscaler/metricsforwarder/forwarder/syslog_emitter_test.go b/src/autoscaler/metricsforwarder/forwarder/syslog_emitter_test.go index 8e7850689b..8ed45d4729 100644 --- a/src/autoscaler/metricsforwarder/forwarder/syslog_emitter_test.go +++ b/src/autoscaler/metricsforwarder/forwarder/syslog_emitter_test.go @@ -5,38 +5,42 @@ import ( "fmt" "net" "net/url" + "path/filepath" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/metricsforwarder/config" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/metricsforwarder/forwarder" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/models" "code.cloudfoundry.org/lager/v3" + "code.cloudfoundry.org/loggregator-agent-release/src/pkg/egress/syslog" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) var _ = Describe("SyslogEmitter", func() { var ( - listener net.Listener - err error - conf *config.Config - emitter forwarder.Emitter + listener net.Listener + err error + conf *config.Config + syslogConfig *config.SyslogConfig + emitter forwarder.Emitter ) BeforeEach(func() { port := 10000 + GinkgoParallelProcess() listener, err = net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) - Expect(err).ToNot(HaveOccurred()) url, err := url.Parse(fmt.Sprintf("syslog://%s", listener.Addr())) Expect(err).ToNot(HaveOccurred()) - conf = &config.Config{ - SyslogConfig: config.SyslogConfig{ - ServerAddress: url.Host, - Port: port, - }, + syslogConfig = &config.SyslogConfig{ + ServerAddress: url.Host, + Port: port, } + }) + + JustBeforeEach(func() { + conf = &config.Config{SyslogConfig: *syslogConfig} logger := lager.NewLogger("metricsforwarder-test") emitter, err = forwarder.NewSyslogEmitter(logger, conf) @@ -46,18 +50,62 @@ var _ = Describe("SyslogEmitter", func() { listener.Close() }) - It("should send message to syslog server", func() { - metric := &models.CustomMetric{Name: "queuelength", Value: 12.5, Unit: "unit", InstanceIndex: 123, AppGUID: "dummy-guid"} - emitter.EmitMetric(metric) + Describe("EmitMetric", func() { + Context("When tls config is provided", func() { + BeforeEach(func() { + testCertDir := "../../../../test-certs" + //on server + //filepath.Join(testCertDir, "metron.crt"), + //filepath.Join(testCertDir, "metron.key"), + //filepath.Join(testCertDir, "loggregator-ca.crt"), + // + conf.SyslogConfig.TLS = models.TLSCerts{ + KeyFile: filepath.Join(testCertDir, "cf-app.key"), + CertFile: filepath.Join(testCertDir, "cf-app.crt"), + CACertFile: filepath.Join(testCertDir, "log-cache-syslog-server-ca.crt"), + } + }) - conn, err := listener.Accept() - Expect(err).ToNot(HaveOccurred()) - buf := bufio.NewReader(conn) + XIt("should send message to syslog server", func() { + emitter, err = forwarder.NewSyslogEmitter(lager.NewLogger("metricsforwarder-test"), conf) + Expect(err).ToNot(HaveOccurred()) - actual, err := buf.ReadString('\n') - Expect(err).ToNot(HaveOccurred()) + // cast emitter to syslogEmitter to access writer + Expect(emitter.(*forwarder.SyslogEmitter).Writer).To(BeAssignableToTypeOf(syslog.TLSWriter{})) + + metric := &models.CustomMetric{Name: "queuelength", Value: 12, Unit: "bytes", InstanceIndex: 123, AppGUID: "dummy-guid"} + emitter.EmitMetric(metric) + + conn, err := listener.Accept() + Expect(err).ToNot(HaveOccurred()) + buf := bufio.NewReader(conn) + + actual, err := buf.ReadString('\n') + Expect(err).ToNot(HaveOccurred()) + + expected := fmt.Sprintf(`130 <14>1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+\d{2}:\d{2} test-hostname %s \[%d\] - \[gauge@47450 name="%s" value="%.0f" unit="%s"\]`, metric.AppGUID, metric.InstanceIndex, metric.Name, metric.Value, metric.Unit) + Expect(actual).To(MatchRegexp(expected)) + }) + + }) + + Context("When tls config is not provided", func() { + It("should send message to syslog server", func() { + metric := &models.CustomMetric{Name: "queuelength", Value: 12, Unit: "bytes", InstanceIndex: 123, AppGUID: "dummy-guid"} + + Expect(emitter.(*forwarder.SyslogEmitter).Writer).To(BeAssignableToTypeOf(&syslog.TCPWriter{})) + emitter.EmitMetric(metric) + + conn, err := listener.Accept() + Expect(err).ToNot(HaveOccurred()) + buf := bufio.NewReader(conn) + + actual, err := buf.ReadString('\n') + Expect(err).ToNot(HaveOccurred()) - expected := fmt.Sprintf(`128 <14>1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+\d{2}:\d{2} test-hostname %s [] - [gauge@47450 name="%s" value="%.2f" unit="%s"]`, metric.AppGUID, metric.Name, metric.Value, metric.Unit) - Expect(actual).To(MatchRegexp(expected)) + expected := fmt.Sprintf(`130 <14>1 \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+\d{2}:\d{2} test-hostname %s \[%d\] - \[gauge@47450 name="%s" value="%.0f" unit="%s"\]`, metric.AppGUID, metric.InstanceIndex, metric.Name, metric.Value, metric.Unit) + Expect(actual).To(MatchRegexp(expected)) + }) + }) }) }) diff --git a/templates/app-autoscaler.yml b/templates/app-autoscaler.yml index 50c0dc7b2b..7e25879ea4 100644 --- a/templates/app-autoscaler.yml +++ b/templates/app-autoscaler.yml @@ -162,6 +162,7 @@ instance_groups: databases: &database # property is not in https://bosh.io/jobs/postgres?source=github.com/cloudfoundry/postgres-release&version=48 # sslmode: verify-full + sslmode: disable tls: &db_tls ca: ((postgres_ca.ca)) certificate: ((postgres_server.certificate)) @@ -170,10 +171,10 @@ instance_groups: - name: autoscaler tag: default # property is not in https://bosh.io/jobs/postgres?source=github.com/cloudfoundry/postgres-release&version=48 - # db_scheme: postgres - # address: *postgres_domain + db_scheme: postgres + address: *postgres_domain # property default value is already 5432 https://bosh.io/jobs/postgres?source=github.com/cloudfoundry/postgres-release&version=48 - # port: 5432 + port: 5432 roles: - name: postgres password: "((database_password))"