From dfa22da07271797c56157f60dba4fffadc641d71 Mon Sep 17 00:00:00 2001 From: Arsalan Khan Date: Fri, 13 Sep 2024 15:37:57 +0200 Subject: [PATCH] condigure bindingdb in metricsforwarder to authenticate neighbour app --- jobs/metricsforwarder/spec | 31 +++++ .../templates/binding_db.crt.erb | 3 + .../templates/binding_db.key.erb | 3 + .../templates/binding_db_ca.crt.erb | 3 + .../templates/metricsforwarder.yml.erb | 6 + spec/fixtures/metricsforwarder.yml | 15 +++ .../metricsforwarder/metricsforwarder_spec.rb | 14 +++ .../metricsforwarder_suite_test.go | 118 +++++++++++------- .../metricsforwarder/config/config.go | 3 + .../metricsforwarder/config/config_test.go | 16 +++ 10 files changed, 165 insertions(+), 47 deletions(-) create mode 100644 jobs/metricsforwarder/templates/binding_db.crt.erb create mode 100644 jobs/metricsforwarder/templates/binding_db.key.erb create mode 100644 jobs/metricsforwarder/templates/binding_db_ca.crt.erb diff --git a/jobs/metricsforwarder/spec b/jobs/metricsforwarder/spec index d8feaf1be3..54d60b5ec4 100644 --- a/jobs/metricsforwarder/spec +++ b/jobs/metricsforwarder/spec @@ -126,6 +126,37 @@ properties: autoscaler.policy_db_connection_config.connection_max_lifetime: default: 60s + autoscaler.binding_db.address: + description: "IP address on which the bindingdb server will listen" + default: "autoscalerpostgres.service.cf.internal" + autoscaler.binding_db.databases: + description: "The list of databases used in bindingdb database including name" + autoscaler.binding_db.db_scheme: + description: "Database scheme to be used to access bindingdb" + default: postgres + autoscaler.binding_db.port: + description: "Port on which the bindingdb server will listen" + autoscaler.binding_db.roles: + description: "The list of database roles used in bindingdb database including name/password" + autoscaler.binding_db.tls.ca: + default: '' + description: 'PEM-encoded ca certificate for TLS database server' + autoscaler.binding_db.tls.certificate: + default: '' + description: 'PEM-encoded certificate for TLS database client' + autoscaler.binding_db.tls.private_key: + default: '' + description: 'PEM-encoded key for TLS database client' + autoscaler.binding_db.sslmode: + default: disable + description: "sslmode to connect to postgres server" + autoscaler.binding_db_connection_config.max_open_connections: + default: 20 + autoscaler.binding_db_connection_config.max_idle_connections: + default: 10 + autoscaler.binding_db_connection_config.connection_max_lifetime: + default: 60s + autoscaler.storedprocedure_db.address: description: "IP address on which the storedproceduredb server will listen" default: "" diff --git a/jobs/metricsforwarder/templates/binding_db.crt.erb b/jobs/metricsforwarder/templates/binding_db.crt.erb new file mode 100644 index 0000000000..f848f28d79 --- /dev/null +++ b/jobs/metricsforwarder/templates/binding_db.crt.erb @@ -0,0 +1,3 @@ +<% if_p("autoscaler.binding_db.tls.certificate") do |value| %> +<%= value %> +<% end %> \ No newline at end of file diff --git a/jobs/metricsforwarder/templates/binding_db.key.erb b/jobs/metricsforwarder/templates/binding_db.key.erb new file mode 100644 index 0000000000..5aee693cbc --- /dev/null +++ b/jobs/metricsforwarder/templates/binding_db.key.erb @@ -0,0 +1,3 @@ +<% if_p("autoscaler.binding_db.tls.private_key") do |value| %> +<%= value %> +<% end %> \ No newline at end of file diff --git a/jobs/metricsforwarder/templates/binding_db_ca.crt.erb b/jobs/metricsforwarder/templates/binding_db_ca.crt.erb new file mode 100644 index 0000000000..5935a893b1 --- /dev/null +++ b/jobs/metricsforwarder/templates/binding_db_ca.crt.erb @@ -0,0 +1,3 @@ +<% if_p("autoscaler.binding_db.tls.ca") do |value| %> +<%= value %> +<% end %> \ No newline at end of file diff --git a/jobs/metricsforwarder/templates/metricsforwarder.yml.erb b/jobs/metricsforwarder/templates/metricsforwarder.yml.erb index e518676955..7bb5df81dc 100644 --- a/jobs/metricsforwarder/templates/metricsforwarder.yml.erb +++ b/jobs/metricsforwarder/templates/metricsforwarder.yml.erb @@ -38,6 +38,7 @@ end ########################################### job_name = 'metricsforwarder' policy_db_url = build_db_url('policy_db', job_name) + binding_db_url = build_db_url('binding_db', job_name) if p("autoscaler.storedprocedure_db.address") != '' storedprocedure_db_url = build_db_url('storedprocedure_db', job_name) end @@ -80,6 +81,11 @@ db: max_open_connections: <%= p("autoscaler.policy_db_connection_config.max_open_connections") %> max_idle_connections: <%= p("autoscaler.policy_db_connection_config.max_idle_connections") %> connection_max_lifetime: <%= p("autoscaler.policy_db_connection_config.connection_max_lifetime") %> + binding_db: + url: <%= binding_db_url %> + max_open_connections: <%= p("autoscaler.binding_db_connection_config.max_open_connections") %> + max_idle_connections: <%= p("autoscaler.binding_db_connection_config.max_idle_connections") %> + connection_max_lifetime: <%= p("autoscaler.binding_db_connection_config.connection_max_lifetime") %> <% if p("autoscaler.storedprocedure_db.address") != '' %> storedprocedure_db: url: <%= storedprocedure_db_url %> diff --git a/spec/fixtures/metricsforwarder.yml b/spec/fixtures/metricsforwarder.yml index 434d1bbfcb..8d7528741a 100644 --- a/spec/fixtures/metricsforwarder.yml +++ b/spec/fixtures/metricsforwarder.yml @@ -14,6 +14,21 @@ autoscaler: ca: BEGIN---CA---END certificate: BEGIN---CERT---END private_key: BEGIN---KEY---END + binding_db: + address: 10.11.137.101 + databases: + - name: foo + tag: default + db_scheme: postgres + port: 5432 + roles: + - name: foo + password: default + tag: default + tls: + ca: BEGIN---CA---END + certificate: BEGIN---CERT---END + private_key: BEGIN---KEY---END cf: api: https://api.cf.domain auth_endpoint: https://login.cf.domain diff --git a/spec/jobs/metricsforwarder/metricsforwarder_spec.rb b/spec/jobs/metricsforwarder/metricsforwarder_spec.rb index 140ca46a92..1496fc7249 100644 --- a/spec/jobs/metricsforwarder/metricsforwarder_spec.rb +++ b/spec/jobs/metricsforwarder/metricsforwarder_spec.rb @@ -114,6 +114,20 @@ end end end + context "binding_db" do + it "includes the ca, cert and key in url when configured" do + rendered_template["db"]["binding_db"]["url"].tap do |url| + check_if_certs_in_url(url, "binding_db") + end + end + + it "does not include the ca, cert and key in url when not configured" do + properties["autoscaler"]["binding_db"]["tls"] = nil + rendered_template["db"]["binding_db"]["url"].tap do |url| + check_if_certs_not_in_url(url, "binding_db") + end + end + end end end end diff --git a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_suite_test.go b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_suite_test.go index fb67b8ce82..3b385b8174 100644 --- a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_suite_test.go +++ b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_suite_test.go @@ -63,53 +63,8 @@ var _ = SynchronizedBeforeSuite(func() []byte { if err != nil { AbortSuite(fmt.Sprintf("DBURL not found: %s", err.Error())) } - - policyDB, err := sqlx.Open(database.DriverName, database.DataSourceName) - Expect(err).NotTo(HaveOccurred()) - - _, err = policyDB.Exec("DELETE from policy_json") - if err != nil { - AbortSuite(fmt.Sprintf("Failed clean policy_json %s", err.Error())) - } - _, err = policyDB.Exec("DELETE from credentials") - if err != nil { - AbortSuite(fmt.Sprintf("Failed clean credentials %s", err.Error())) - } - - policy := ` - { - "instance_min_count": 1, - "instance_max_count": 5, - "scaling_rules":[ - { - "metric_type":"custom", - "breach_duration_secs":600, - "threshold":30, - "operator":"<", - "cool_down_secs":300, - "adjustment":"-1" - } - ] - }` - query := policyDB.Rebind("INSERT INTO policy_json(app_id, policy_json, guid) values(?, ?, ?)") - _, err = policyDB.Exec(query, "an-app-id", policy, "1234") - if err != nil { - AbortSuite(fmt.Sprintf("Failed clean credentials %s", err.Error())) - } - - encryptedUsername, _ := bcrypt.GenerateFromPassword([]byte(username), 8) - encryptedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), 8) - - query = policyDB.Rebind("INSERT INTO credentials(id, username, password, updated_at) values(?, ?, ?, ?)") - _, err = policyDB.Exec(query, "an-app-id", encryptedUsername, encryptedPassword, "2011-06-18 15:36:38") - if err != nil { - AbortSuite(fmt.Sprintf("Failed to add credentials: %s", err.Error())) - } - - err = policyDB.Close() - if err != nil { - AbortSuite(fmt.Sprintf("Failed to close connection: %s", err.Error())) - } + preparePolicyDb(database) + prepareBindingDb(database) return []byte(mf) }, func(pathsByte []byte) { @@ -153,6 +108,12 @@ var _ = SynchronizedBeforeSuite(func() []byte { MaxIdleConnections: 5, ConnectionMaxLifetime: 10 * time.Second, } + cfg.Db[db.BindingDb] = db.DatabaseConfig{ + URL: dbUrl, + MaxOpenConnections: 10, + MaxIdleConnections: 5, + ConnectionMaxLifetime: 10 * time.Second, + } cfg.CredHelperImpl = "default" @@ -162,6 +123,69 @@ var _ = SynchronizedBeforeSuite(func() []byte { healthHttpClient = &http.Client{} }) +func preparePolicyDb(database *db.Database) { + policyDB, err := sqlx.Open(database.DriverName, database.DataSourceName) + Expect(err).NotTo(HaveOccurred()) + + _, err = policyDB.Exec("DELETE from policy_json") + if err != nil { + AbortSuite(fmt.Sprintf("Failed clean policy_json %s", err.Error())) + } + _, err = policyDB.Exec("DELETE from credentials") + if err != nil { + AbortSuite(fmt.Sprintf("Failed clean credentials %s", err.Error())) + } + + policy := ` + { + "instance_min_count": 1, + "instance_max_count": 5, + "scaling_rules":[ + { + "metric_type":"custom", + "breach_duration_secs":600, + "threshold":30, + "operator":"<", + "cool_down_secs":300, + "adjustment":"-1" + } + ] + }` + query := policyDB.Rebind("INSERT INTO policy_json(app_id, policy_json, guid) values(?, ?, ?)") + _, err = policyDB.Exec(query, "an-app-id", policy, "1234") + if err != nil { + AbortSuite(fmt.Sprintf("Failed clean credentials %s", err.Error())) + } + + encryptedUsername, _ := bcrypt.GenerateFromPassword([]byte(username), 8) + encryptedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), 8) + + query = policyDB.Rebind("INSERT INTO credentials(id, username, password, updated_at) values(?, ?, ?, ?)") + _, err = policyDB.Exec(query, "an-app-id", encryptedUsername, encryptedPassword, "2011-06-18 15:36:38") + if err != nil { + AbortSuite(fmt.Sprintf("Failed to add credentials: %s", err.Error())) + } + + err = policyDB.Close() + if err != nil { + AbortSuite(fmt.Sprintf("Failed to close connection: %s", err.Error())) + } +} + +func prepareBindingDb(database *db.Database) { + bindingDB, err := sqlx.Open(database.DriverName, database.DataSourceName) + Expect(err).NotTo(HaveOccurred()) + + _, err = bindingDB.Exec("DELETE from binding") + if err != nil { + AbortSuite(fmt.Sprintf("Failed clean policy_json %s", err.Error())) + } + err = bindingDB.Close() + if err != nil { + AbortSuite(fmt.Sprintf("Failed to close connection: %s", err.Error())) + } +} + var _ = SynchronizedAfterSuite(func() { grpcIngressTestServer.Stop() os.Remove(configFile.Name()) diff --git a/src/autoscaler/metricsforwarder/config/config.go b/src/autoscaler/metricsforwarder/config/config.go index 743ff79b61..5118de1636 100644 --- a/src/autoscaler/metricsforwarder/config/config.go +++ b/src/autoscaler/metricsforwarder/config/config.go @@ -182,6 +182,9 @@ func (c *Config) Validate() error { if c.Db[db.PolicyDb].URL == "" { return fmt.Errorf("Configuration error: Policy DB url is empty") } + if c.Db[db.BindingDb].URL == "" { + return fmt.Errorf("Configuration error: Binding DB url is empty") + } if c.UsingSyslog() { if c.SyslogConfig.TLS.CACertFile == "" { return fmt.Errorf("Configuration error: SyslogServer Loggregator CACert is empty") diff --git a/src/autoscaler/metricsforwarder/config/config_test.go b/src/autoscaler/metricsforwarder/config/config_test.go index 01c00332a9..b6f0addf0d 100644 --- a/src/autoscaler/metricsforwarder/config/config_test.go +++ b/src/autoscaler/metricsforwarder/config/config_test.go @@ -287,6 +287,12 @@ health: MaxIdleConnections: 5, ConnectionMaxLifetime: 60 * time.Second, } + conf.Db[db.BindingDb] = db.DatabaseConfig{ + URL: "postgres://pqgotest:password@localhost/pqgotest", + MaxOpenConnections: 10, + MaxIdleConnections: 5, + ConnectionMaxLifetime: 60 * time.Second, + } conf.RateLimit.MaxAmount = 10 conf.RateLimit.ValidDuration = 1 * time.Second @@ -362,6 +368,16 @@ health: }) }) + When("binding db url is not set", func() { + BeforeEach(func() { + conf.Db[db.BindingDb] = db.DatabaseConfig{URL: ""} + }) + + It("should error", func() { + Expect(err).To(MatchError(MatchRegexp("Configuration error: Binding DB url is empty"))) + }) + }) + When("Loggregator CACert is not set", func() { BeforeEach(func() { conf.LoggregatorConfig.TLS.CACertFile = ""