Skip to content

Zero downtime password rotation #389

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Some tests
  • Loading branch information
levkk committed Mar 30, 2023
commit db3d6c3baa6388bab7490f8918f12e3b49928c7f
39 changes: 39 additions & 0 deletions tests/ruby/auth_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true
require_relative 'spec_helper'


describe "Authentication" do
describe "multiple secrets configured" do
let(:secrets) { ["one_secret", "two_secret"] }
let(:processes) { Helpers::Pgcat.three_shard_setup("sharded_db", 5, pool_mode="transaction", lb_mode="random", log_level="info", secrets=["one_secret", "two_secret"]) }

after do
processes.all_databases.map(&:reset)
processes.pgcat.shutdown
end

it "can connect using all secrets and postgres password" do
secrets.push("sharding_user").each do |secret|
conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user", password=secret))
conn.exec("SELECT current_user")
end
end
end

describe "no secrets configured" do
let(:secrets) { [] }
let(:processes) { Helpers::Pgcat.three_shard_setup("sharded_db", 5, pool_mode="transaction", lb_mode="random", log_level="info") }

after do
processes.all_databases.map(&:reset)
processes.pgcat.shutdown
end

it "can connect using only the password" do
conn = PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user"))
conn.exec("SELECT current_user")

expect { PG.connect(processes.pgcat.connection_string("sharded_db", "sharding_user", password="secret_one")) }.to raise_error PG::ConnectionBad
end
end
end
18 changes: 14 additions & 4 deletions tests/ruby/helpers/pgcat_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,26 @@ def deep_merge(second)

module Helpers
module Pgcat
def self.three_shard_setup(pool_name, pool_size, pool_mode="transaction", lb_mode="random", log_level="info")
def self.three_shard_setup(pool_name, pool_size, pool_mode="transaction", lb_mode="random", log_level="info", secrets=nil)
user = {
"password" => "sharding_user",
"pool_size" => pool_size,
"statement_timeout" => 0,
"username" => "sharding_user"
"username" => "sharding_user",
}

if !secrets.nil?
user["secrets"] = secrets
end

pgcat = PgcatProcess.new(log_level)
primary0 = PgInstance.new(5432, user["username"], user["password"], "shard0")
primary1 = PgInstance.new(7432, user["username"], user["password"], "shard1")
primary2 = PgInstance.new(8432, user["username"], user["password"], "shard2")

pgcat_cfg = pgcat.current_config
pgcat_cfg["pools"] = {
"#{pool_name}" => {
"#{pool_name}" => {
"default_role" => "any",
"pool_mode" => pool_mode,
"load_balancing_mode" => lb_mode,
Expand All @@ -41,8 +45,14 @@ def self.three_shard_setup(pool_name, pool_size, pool_mode="transaction", lb_mod
"2" => { "database" => "shard2", "servers" => [["localhost", primary2.port.to_s, "primary"]] },
},
"users" => { "0" => user }
}
},
}

if !secrets.nil?
pgcat_cfg["general"]["tls_certificate"] = "../../.circleci/server.cert"
pgcat_cfg["general"]["tls_private_key"] = "../../.circleci/server.key"
end

pgcat.update_config(pgcat_cfg)

pgcat.start
Expand Down
7 changes: 5 additions & 2 deletions tests/ruby/helpers/pgcat_process.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,13 @@ def admin_connection_string
"postgresql://#{username}:#{password}@0.0.0.0:#{@port}/pgcat"
end

def connection_string(pool_name, username, password = nil)
def connection_string(pool_name, username, password=nil)
cfg = current_config
user_idx, user_obj = cfg["pools"][pool_name]["users"].detect { |k, user| user["username"] == username }
"postgresql://#{username}:#{password || user_obj["password"]}@0.0.0.0:#{@port}/#{pool_name}"

password = if password.nil? then user_obj["password"] else password end

"postgresql://#{username}:#{password}@0.0.0.0:#{@port}/#{pool_name}"
end

def example_connection_string
Expand Down