docbrown/app/controllers/api/v0/health_checks_controller.rb
Joe Doss 6406b0727b
Allow localhost or 127.0.0.1 to access api/health_checks without health-check-token (#8231)
* This change allows access to api/health_checks if you are coming from localhost
or 127.0.0.1. Pretty sweet huh?

The reason for this change is because I want to easily get to these healthcheck
end points from localhost without having to get the health-check-token beforehand.

Buttttt.... this addition has some issues. You can spoof the host header pretty
easily:

https://daniel.haxx.se/blog/2018/04/05/curl-another-host/

I thought about doing `return if !request.ssl? && request.local?`

to check of the request was over https or not. Any localhost healthcheck we do
directly to puma will be over http. Checking for TLS seemed like a logical next
check, but since we force https on the edge and not necessarily from the edge to
Puma the Host header can still be spoofed to get at these end points.

More info on host header attacks and what Rails 6 is doing about it:

https://github.com/rails/rails/issues/29893

While I do think it is a good idea to protect these healthcheck end points from
the outside world, I do want to be able to get to them easily locally. WWYD?

* Fix Health Check spec by stubbing request

Co-authored-by: mstruve <mollylbs@gmail.com>
2020-06-02 11:29:04 -04:00

53 lines
1.4 KiB
Ruby

module Api
module V0
class HealthChecksController < ApiController
before_action :authenticate_with_token
def app
render json: { message: "App is up!" }, status: :ok
end
def search
if Search::Client.ping
render json: { message: "Search ping succeeded!" }, status: :ok
else
render json: { message: "Search ping failed!" }, status: :internal_server_error
end
end
def database
if ActiveRecord::Base.connected?
render json: { message: "Database connected" }, status: :ok
else
render json: { message: "Database NOT connected!" }, status: :internal_server_error
end
end
def cache
if all_cache_instances_connected?
render json: { message: "Redis connected" }, status: :ok
else
render json: { message: "Redis NOT connected!" }, status: :internal_server_error
end
end
private
def authenticate_with_token
return if request.local?
key = request.headers["health-check-token"]
return if key == SiteConfig.health_check_token
error_unauthorized
end
def all_cache_instances_connected?
[ENV["REDIS_URL"], ENV["REDIS_SESSIONS_URL"], ENV["REDIS_SIDEKIQ_URL"]].compact.all? do |url|
Redis.new(url: url).ping == "PONG"
end
end
end
end
end