redis: Fix password auth with UNIX domain sockets
Previously if a Redis instance listened on a UNIX socket but a password were set, GitLab Rails would not be able to authenticate. This occurred because the UNIX URL doesn't contain a password. Both Ruby and Go Redis clients support URLs in the form: unix://<user>:<password>@</path/to/redis.sock>?db=<db_number> Relates to work started in https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/2194 Changelog: fixed
This commit is contained in:
parent
6fab34cacb
commit
656fb39a8c
|
@ -33,13 +33,17 @@ class RedisHelper
|
|||
|
||||
redis_socket = gitlab_rails['redis_socket']
|
||||
redis_socket = false if RedisHelper::Checks.is_gitlab_rails_redis_tcp?
|
||||
params = redis_params(support_sentinel_groupname: support_sentinel_groupname)
|
||||
|
||||
if redis_socket && !RedisHelper::Checks.has_sentinels?
|
||||
uri = URI('unix:/')
|
||||
uri = URI("unix://")
|
||||
uri.path = redis_socket
|
||||
else
|
||||
params = redis_params(support_sentinel_groupname: support_sentinel_groupname)
|
||||
|
||||
if params[2]
|
||||
password = encode_redis_password(params[2])
|
||||
uri.userinfo = ":#{password}"
|
||||
end
|
||||
else
|
||||
uri = build_redis_url(
|
||||
ssl: gitlab_rails['redis_ssl'],
|
||||
host: params[0],
|
||||
|
@ -97,6 +101,10 @@ class RedisHelper
|
|||
uri
|
||||
end
|
||||
|
||||
def encode_redis_password(password)
|
||||
URI::Generic::DEFAULT_PARSER.escape(password)
|
||||
end
|
||||
|
||||
def redis_sentinel_urls(sentinels_key)
|
||||
gitlab_rails = @node['gitlab']['gitlab_rails']
|
||||
|
||||
|
|
|
@ -28,5 +28,14 @@ module NewRedisHelper
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
# RFC 3986 says that the userinfo value should be percent-encoded:
|
||||
# https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1.
|
||||
# Note that CGI.escape and URI.encode_www_form_component encodes
|
||||
# a space as "+" instead of "%20". While this appears to be handled with
|
||||
# the Ruby client, the Go client doesn't work with "+".
|
||||
def encode_redis_password(password)
|
||||
URI::Generic::DEFAULT_PARSER.escape(password)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,12 +37,17 @@ module NewRedisHelper
|
|||
redis_socket
|
||||
end
|
||||
|
||||
if socket && !has_sentinels?
|
||||
uri = URI('unix:/')
|
||||
uri.path = socket
|
||||
else
|
||||
params = redis_credentials
|
||||
params = redis_credentials
|
||||
|
||||
if socket && !has_sentinels?
|
||||
uri = URI("unix://")
|
||||
uri.path = socket
|
||||
|
||||
if params[:password]
|
||||
password = NewRedisHelper.encode_redis_password(params[:password])
|
||||
uri.userinfo = ":#{password}"
|
||||
end
|
||||
else
|
||||
uri = NewRedisHelper.build_redis_url(
|
||||
ssl: redis_ssl,
|
||||
host: params[:host],
|
||||
|
|
|
@ -49,7 +49,7 @@ RSpec.describe RedisHelper do
|
|||
context '#redis_url' do
|
||||
context 'with default configuration' do
|
||||
it 'returns a unix socket' do
|
||||
expect(subject.redis_url.to_s).to eq('unix:/var/opt/gitlab/redis/redis.socket')
|
||||
expect(subject.redis_url.to_s).to eq('unix:///var/opt/gitlab/redis/redis.socket')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -210,20 +210,24 @@ RSpec.describe 'gitlab::gitlab-rails' do
|
|||
|
||||
context 'with redis settings' do
|
||||
let(:config_file) { '/var/opt/gitlab/gitlab-rails/etc/resque.yml' }
|
||||
let(:resque_yml_template) { chef_run.template('/var/opt/gitlab/gitlab-rails/etc/resque.yml') }
|
||||
let(:resque_yml_file_content) { ChefSpec::Renderer.new(chef_run, resque_yml_template).content }
|
||||
let(:resque_yml) { YAML.safe_load(resque_yml_file_content, aliases: true, symbolize_names: true) }
|
||||
|
||||
let(:chef_run) { ChefSpec::SoloRunner.new(step_into: %w(templatesymlink)).converge('gitlab::default') }
|
||||
|
||||
context 'and default configuration' do
|
||||
it 'creates the config file with the required redis settings' do
|
||||
expect(chef_run).to create_templatesymlink('Create a resque.yml and create a symlink to Rails root').with_variables(
|
||||
hash_including(
|
||||
redis_url: URI('unix:/var/opt/gitlab/redis/redis.socket'),
|
||||
redis_url: URI('unix:///var/opt/gitlab/redis/redis.socket'),
|
||||
redis_sentinels: [],
|
||||
redis_enable_client: true
|
||||
)
|
||||
)
|
||||
|
||||
expect(chef_run).to render_file(config_file).with_content { |content|
|
||||
expect(content).to match(%r(url: unix:/var/opt/gitlab/redis/redis.socket$))
|
||||
expect(content).to match(%r(url: unix:///var/opt/gitlab/redis/redis.socket$))
|
||||
expect(content).not_to match(/id:/)
|
||||
}
|
||||
end
|
||||
|
@ -231,14 +235,14 @@ RSpec.describe 'gitlab::gitlab-rails' do
|
|||
it 'creates cable.yml with the same settings' do
|
||||
expect(chef_run).to create_templatesymlink('Create a cable.yml and create a symlink to Rails root').with_variables(
|
||||
hash_including(
|
||||
redis_url: URI('unix:/var/opt/gitlab/redis/redis.socket'),
|
||||
redis_url: URI('unix:///var/opt/gitlab/redis/redis.socket'),
|
||||
redis_sentinels: [],
|
||||
redis_enable_client: true
|
||||
)
|
||||
)
|
||||
|
||||
expect(chef_run).to render_file('/var/opt/gitlab/gitlab-rails/etc/cable.yml').with_content { |content|
|
||||
expect(content).to match(%r(url: unix:/var/opt/gitlab/redis/redis.socket$))
|
||||
expect(content).to match(%r(url: unix:///var/opt/gitlab/redis/redis.socket$))
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -301,10 +305,6 @@ RSpec.describe 'gitlab::gitlab-rails' do
|
|||
end
|
||||
|
||||
context 'with TLS settings' do
|
||||
let(:resque_yml_template) { chef_run.template('/var/opt/gitlab/gitlab-rails/etc/resque.yml') }
|
||||
let(:resque_yml_file_content) { ChefSpec::Renderer.new(chef_run, resque_yml_template).content }
|
||||
let(:resque_yml) { YAML.safe_load(resque_yml_file_content, aliases: true, symbolize_names: true) }
|
||||
|
||||
before do
|
||||
stub_gitlab_rb(
|
||||
gitlab_rails: {
|
||||
|
@ -370,6 +370,38 @@ RSpec.describe 'gitlab::gitlab-rails' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with a password and UNIX socket' do
|
||||
let(:cable_yml_template) { chef_run.template('/var/opt/gitlab/gitlab-rails/etc/cable.yml') }
|
||||
let(:cable_yml_file_content) { ChefSpec::Renderer.new(chef_run, cable_yml_template).content }
|
||||
let(:cable_yml) { YAML.safe_load(cable_yml_file_content, aliases: true, symbolize_names: true) }
|
||||
|
||||
before do
|
||||
stub_gitlab_rb(
|
||||
gitlab_rails: {
|
||||
redis_password: 'my pass',
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'renders resque.yml with password' do
|
||||
expected_output = {
|
||||
url: "unix://:my%20pass@/var/opt/gitlab/redis/redis.socket",
|
||||
secret_file: "/var/opt/gitlab/gitlab-rails/shared/encrypted_settings/redis.yml.enc"
|
||||
}
|
||||
|
||||
expect(resque_yml[:production]).to eq(expected_output)
|
||||
end
|
||||
|
||||
it 'creates cable.yml with password' do
|
||||
expected_output = {
|
||||
adapter: 'redis',
|
||||
url: "unix://:my%20pass@/var/opt/gitlab/redis/redis.socket",
|
||||
}
|
||||
|
||||
expect(cable_yml[:production]).to eq(expected_output)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple instances' do
|
||||
context 'with action cable' do
|
||||
before do
|
||||
|
|
|
@ -504,7 +504,7 @@ RSpec.describe 'gitlab::gitlab-workhorse' do
|
|||
|
||||
context 'with default values for redis' do
|
||||
it 'should generate config file' do
|
||||
content_url = 'URL = "unix:/var/opt/gitlab/redis/redis.socket"'
|
||||
content_url = 'URL = "unix:///var/opt/gitlab/redis/redis.socket"'
|
||||
expect(chef_run).to render_file(config_file).with_content(content_url)
|
||||
expect(chef_run).not_to render_file(config_file).with_content(/Sentinel/)
|
||||
end
|
||||
|
@ -543,7 +543,7 @@ RSpec.describe 'gitlab::gitlab-workhorse' do
|
|||
end
|
||||
|
||||
it 'should generate config file with the specified values' do
|
||||
content_url = 'URL = "unix:/home/random/path.socket"'
|
||||
content_url = 'URL = "unix://:examplepassword@/home/random/path.socket"'
|
||||
content_password = 'Password = "examplepassword"'
|
||||
expect(chef_run).to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content_url)
|
||||
expect(chef_run).to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content_password)
|
||||
|
@ -653,7 +653,7 @@ RSpec.describe 'gitlab::gitlab-workhorse' do
|
|||
end
|
||||
|
||||
it 'should generate config file with the specified values' do
|
||||
content_url = 'URL = "unix:/home/random/path.socket"'
|
||||
content_url = 'URL = "unix://:some%20pass@/home/random/path.socket"'
|
||||
content_password = 'Password = "some pass"'
|
||||
expect(chef_run).to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content_url)
|
||||
expect(chef_run).to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content_password)
|
||||
|
|
|
@ -16,7 +16,7 @@ RSpec.describe NewRedisHelper::GitlabWorkhorse do
|
|||
context 'by default' do
|
||||
it 'returns information about the default Redis instance' do
|
||||
expect(subject.redis_params).to eq(
|
||||
url: 'unix:/var/opt/gitlab/redis/redis.socket',
|
||||
url: 'unix:///var/opt/gitlab/redis/redis.socket',
|
||||
password: nil,
|
||||
sentinels: [],
|
||||
sentinelMaster: 'gitlab-redis',
|
||||
|
@ -26,6 +26,26 @@ RSpec.describe NewRedisHelper::GitlabWorkhorse do
|
|||
end
|
||||
|
||||
context 'with user specified values' do
|
||||
context 'when password set for UNIX socket' do
|
||||
before do
|
||||
stub_gitlab_rb(
|
||||
gitlab_rails: {
|
||||
redis_password: 'redis-password'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns a UNIX socket URL with password' do
|
||||
expect(subject.redis_params).to eq(
|
||||
url: 'unix://:redis-password@/var/opt/gitlab/redis/redis.socket',
|
||||
password: 'redis-password',
|
||||
sentinels: [],
|
||||
sentinelMaster: 'gitlab-redis',
|
||||
sentinelPassword: nil
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when settings specified via gitlab_rails' do
|
||||
before do
|
||||
stub_gitlab_rb(
|
||||
|
|
Loading…
Reference in New Issue