Commit 18521584 authored by Pawel Chojnacki's avatar Pawel Chojnacki

Remove the need to use health check token

in favor of whitelist that will be used to
control the access to monitoring resources
parent 5af1fcd6
module RequiresHealthToken module RequiresWhitelistedMonitoringClient
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
before_action :validate_health_check_access! before_action :validate_ip_whitelisted!
end end
private private
def validate_health_check_access! def validate_ip_whitelisted!
render_404 unless token_valid? render_404 unless client_ip_whitelisted?
end end
def token_valid? def client_ip_whitelisted?
token = params[:token].presence || request.headers['TOKEN'] Settings.monitoring.ip_whitelist.any? {|e| e.include?(Gitlab::RequestContext.client_ip) }
token.present? &&
ActiveSupport::SecurityUtils.variable_size_secure_compare(
token,
current_application_settings.health_check_access_token
)
end end
def render_404 def render_404
......
class HealthCheckController < HealthCheck::HealthCheckController class HealthCheckController < HealthCheck::HealthCheckController
include RequiresHealthToken include RequiresWhitelistedMonitoringClient
end end
class HealthController < ActionController::Base class HealthController < ActionController::Base
protect_from_forgery with: :exception protect_from_forgery with: :exception
include RequiresHealthToken include RequiresWhitelistedMonitoringClient
CHECKS = [ CHECKS = [
Gitlab::HealthChecks::DbCheck, Gitlab::HealthChecks::DbCheck,
......
class MetricsController < ActionController::Base class MetricsController < ActionController::Base
include RequiresHealthToken include RequiresWhitelistedMonitoringClient
protect_from_forgery with: :exception protect_from_forgery with: :exception
before_action :validate_prometheus_metrics before_action :validate_prometheus_metrics
def index def index
render text: metrics_service.metrics_text, content_type: 'text/plain; verssion=0.0.4' render text: metrics_service.metrics_text, content_type: 'text/plain; version=0.0.4'
end end
private private
......
...@@ -548,6 +548,12 @@ production: &base ...@@ -548,6 +548,12 @@ production: &base
# unicorn_sampler_interval: 10 # unicorn_sampler_interval: 10
## Monitoring
# Built in monitoring settings
monitoring:
# IP whitelist to access monitoring endpoints
access_whitelist: 127.0.0.0/8
# #
# 5. Extra customization # 5. Extra customization
# ========================== # ==========================
......
...@@ -494,6 +494,13 @@ Settings.webpack.dev_server['enabled'] ||= false ...@@ -494,6 +494,13 @@ Settings.webpack.dev_server['enabled'] ||= false
Settings.webpack.dev_server['host'] ||= 'localhost' Settings.webpack.dev_server['host'] ||= 'localhost'
Settings.webpack.dev_server['port'] ||= 3808 Settings.webpack.dev_server['port'] ||= 3808
#
# Monitoring settings
#
Settings['monitoring'] ||= Settingslogic.new({})
Settings.monitoring['ip_whitelist'] ||= %w{127.0.0.1/8}
Settings.monitoring.ip_whitelist.map!(&IPAddr.method(:new))
# #
# Prometheus metrics settings # Prometheus metrics settings
# #
......
...@@ -3,52 +3,57 @@ require 'spec_helper' ...@@ -3,52 +3,57 @@ require 'spec_helper'
describe HealthCheckController do describe HealthCheckController do
include StubENV include StubENV
let(:token) { current_application_settings.health_check_access_token }
let(:json_response) { JSON.parse(response.body) } let(:json_response) { JSON.parse(response.body) }
let(:xml_response) { Hash.from_xml(response.body)['hash'] } let(:xml_response) { Hash.from_xml(response.body)['hash'] }
let(:whitelisted_ip) { '127.0.0.1' }
let(:not_whitelisted_ip) { '127.0.0.2' }
before do before do
allow(Settings.monitoring).to receive(:ip_whitelist).and_return([IPAddr.new(whitelisted_ip)])
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end end
describe 'GET #index' do describe 'GET #index' do
context 'when services are up but NO access token' do context 'when services are up but accessed from outside whitelisted ips' do
before do
allow(Gitlab::RequestContext).to receive(:client_ip).and_return(not_whitelisted_ip)
end
it 'returns a not found page' do it 'returns a not found page' do
get :index get :index
expect(response).to be_not_found expect(response).to be_not_found
end end
end end
context 'when services are up and an access token is provided' do context 'when services are up and accessed from whitelisted ips' do
it 'supports passing the token in the header' do let(:ip) { '127.0.0.1' }
request.headers['TOKEN'] = token
get :index before do
expect(response).to be_success allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
expect(response.content_type).to eq 'text/plain'
end end
it 'supports successful plaintest response' do it 'supports successful plaintest response' do
get :index, token: token get :index
expect(response).to be_success expect(response).to be_success
expect(response.content_type).to eq 'text/plain' expect(response.content_type).to eq 'text/plain'
end end
it 'supports successful json response' do it 'supports successful json response' do
get :index, token: token, format: :json get :index, format: :json
expect(response).to be_success expect(response).to be_success
expect(response.content_type).to eq 'application/json' expect(response.content_type).to eq 'application/json'
expect(json_response['healthy']).to be true expect(json_response['healthy']).to be true
end end
it 'supports successful xml response' do it 'supports successful xml response' do
get :index, token: token, format: :xml get :index, format: :xml
expect(response).to be_success expect(response).to be_success
expect(response.content_type).to eq 'application/xml' expect(response.content_type).to eq 'application/xml'
expect(xml_response['healthy']).to be true expect(xml_response['healthy']).to be true
end end
it 'supports successful responses for specific checks' do it 'supports successful responses for specific checks' do
get :index, token: token, checks: 'email', format: :json get :index, checks: 'email', format: :json
expect(response).to be_success expect(response).to be_success
expect(response.content_type).to eq 'application/json' expect(response.content_type).to eq 'application/json'
expect(json_response['healthy']).to be true expect(json_response['healthy']).to be true
...@@ -62,29 +67,22 @@ describe HealthCheckController do ...@@ -62,29 +67,22 @@ describe HealthCheckController do
end end
end end
context 'when a service is down and an access token is provided' do context 'when a service is down and an endpoint is accessed from whitelisted ip' do
before do before do
allow(HealthCheck::Utils).to receive(:process_checks).with(['standard']).and_return('The server is on fire') allow(HealthCheck::Utils).to receive(:process_checks).with(['standard']).and_return('The server is on fire')
allow(HealthCheck::Utils).to receive(:process_checks).with(['email']).and_return('Email is on fire') allow(HealthCheck::Utils).to receive(:process_checks).with(['email']).and_return('Email is on fire')
end allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
it 'supports passing the token in the header' do
request.headers['TOKEN'] = token
get :index
expect(response).to have_http_status(500)
expect(response.content_type).to eq 'text/plain'
expect(response.body).to include('The server is on fire')
end end
it 'supports failure plaintest response' do it 'supports failure plaintest response' do
get :index, token: token get :index
expect(response).to have_http_status(500) expect(response).to have_http_status(500)
expect(response.content_type).to eq 'text/plain' expect(response.content_type).to eq 'text/plain'
expect(response.body).to include('The server is on fire') expect(response.body).to include('The server is on fire')
end end
it 'supports failure json response' do it 'supports failure json response' do
get :index, token: token, format: :json get :index, format: :json
expect(response).to have_http_status(500) expect(response).to have_http_status(500)
expect(response.content_type).to eq 'application/json' expect(response.content_type).to eq 'application/json'
expect(json_response['healthy']).to be false expect(json_response['healthy']).to be false
...@@ -92,7 +90,7 @@ describe HealthCheckController do ...@@ -92,7 +90,7 @@ describe HealthCheckController do
end end
it 'supports failure xml response' do it 'supports failure xml response' do
get :index, token: token, format: :xml get :index, format: :xml
expect(response).to have_http_status(500) expect(response).to have_http_status(500)
expect(response.content_type).to eq 'application/xml' expect(response.content_type).to eq 'application/xml'
expect(xml_response['healthy']).to be false expect(xml_response['healthy']).to be false
...@@ -100,7 +98,7 @@ describe HealthCheckController do ...@@ -100,7 +98,7 @@ describe HealthCheckController do
end end
it 'supports failure responses for specific checks' do it 'supports failure responses for specific checks' do
get :index, token: token, checks: 'email', format: :json get :index, checks: 'email', format: :json
expect(response).to have_http_status(500) expect(response).to have_http_status(500)
expect(response.content_type).to eq 'application/json' expect(response.content_type).to eq 'application/json'
expect(json_response['healthy']).to be false expect(json_response['healthy']).to be false
......
...@@ -3,17 +3,19 @@ require 'spec_helper' ...@@ -3,17 +3,19 @@ require 'spec_helper'
describe HealthController do describe HealthController do
include StubENV include StubENV
let(:token) { current_application_settings.health_check_access_token }
let(:json_response) { JSON.parse(response.body) } let(:json_response) { JSON.parse(response.body) }
let(:whitelisted_ip) { '127.0.0.1' }
let(:not_whitelisted_ip) { '127.0.0.2' }
before do before do
allow(Settings.monitoring).to receive(:ip_whitelist).and_return([IPAddr.new(whitelisted_ip)])
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end end
describe '#readiness' do describe '#readiness' do
context 'authorization token provided' do context 'accessed from whitelisted ip' do
before do before do
request.headers['TOKEN'] = token allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
end end
it 'returns proper response' do it 'returns proper response' do
...@@ -25,7 +27,11 @@ describe HealthController do ...@@ -25,7 +27,11 @@ describe HealthController do
end end
end end
context 'without authorization token' do context 'accessed from not whitelisted ip' do
before do
allow(Gitlab::RequestContext).to receive(:client_ip).and_return(not_whitelisted_ip)
end
it 'returns proper response' do it 'returns proper response' do
get :readiness get :readiness
expect(response.status).to eq(404) expect(response.status).to eq(404)
...@@ -34,9 +40,9 @@ describe HealthController do ...@@ -34,9 +40,9 @@ describe HealthController do
end end
describe '#liveness' do describe '#liveness' do
context 'authorization token provided' do context 'accessed from whitelisted ip' do
before do before do
request.headers['TOKEN'] = token allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
end end
it 'returns proper response' do it 'returns proper response' do
...@@ -47,7 +53,11 @@ describe HealthController do ...@@ -47,7 +53,11 @@ describe HealthController do
end end
end end
context 'without authorization token' do context 'accessed from not whitelisted ip' do
before do
allow(Gitlab::RequestContext).to receive(:client_ip).and_return(not_whitelisted_ip)
end
it 'returns proper response' do it 'returns proper response' do
get :liveness get :liveness
expect(response.status).to eq(404) expect(response.status).to eq(404)
......
...@@ -3,20 +3,22 @@ require 'spec_helper' ...@@ -3,20 +3,22 @@ require 'spec_helper'
describe MetricsController do describe MetricsController do
include StubENV include StubENV
let(:token) { current_application_settings.health_check_access_token }
let(:json_response) { JSON.parse(response.body) } let(:json_response) { JSON.parse(response.body) }
let(:metrics_multiproc_dir) { Dir.mktmpdir } let(:metrics_multiproc_dir) { Dir.mktmpdir }
let(:whitelisted_ip) { '127.0.0.1' }
let(:not_whitelisted_ip) { '127.0.0.2' }
before do before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
stub_env('prometheus_multiproc_dir', metrics_multiproc_dir) stub_env('prometheus_multiproc_dir', metrics_multiproc_dir)
allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(true) allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(true)
allow(Settings.monitoring).to receive(:ip_whitelist).and_return([IPAddr.new(whitelisted_ip)])
end end
describe '#index' do describe '#index' do
context 'authorization token provided' do context 'accessed from whitelisted ip' do
before do before do
request.headers['TOKEN'] = token allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
end end
it 'returns DB ping metrics' do it 'returns DB ping metrics' do
...@@ -59,7 +61,11 @@ describe MetricsController do ...@@ -59,7 +61,11 @@ describe MetricsController do
end end
end end
context 'without authorization token' do context 'accessed from not whitelisted ip' do
before do
allow(Gitlab::RequestContext).to receive(:client_ip).and_return(not_whitelisted_ip)
end
it 'returns proper response' do it 'returns proper response' do
get :index get :index
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment