2020-10-24 23:57:45 +05:30
# frozen_string_literal: true
module API
# Kubernetes Internal API
module Internal
2021-01-03 14:25:43 +05:30
class Kubernetes < :: API :: Base
2022-08-27 11:52:29 +05:30
include Gitlab :: Utils :: StrongMemoize
2020-11-24 15:15:51 +05:30
before do
check_feature_enabled
authenticate_gitlab_kas_request!
end
2020-10-24 23:57:45 +05:30
helpers do
2020-11-24 15:15:51 +05:30
def authenticate_gitlab_kas_request!
2021-04-29 21:17:54 +05:30
render_api_error! ( 'KAS JWT authentication invalid' , 401 ) unless Gitlab :: Kas . verify_api_request ( headers )
2020-11-24 15:15:51 +05:30
end
2020-10-24 23:57:45 +05:30
def agent_token
@agent_token || = cluster_agent_token_from_authorization_token
end
def agent
@agent || = agent_token . agent
end
def repo_type
Gitlab :: GlRepository :: PROJECT
end
def gitaly_info ( project )
shard = repo_type . repository_for ( project ) . shard
{
address : Gitlab :: GitalyClient . address ( shard ) ,
token : Gitlab :: GitalyClient . token ( shard ) ,
features : Feature :: Gitaly . server_feature_flags
}
end
def gitaly_repository ( project )
{
storage_name : project . repository_storage ,
relative_path : project . disk_path + '.git' ,
gl_repository : repo_type . identifier_for_container ( project ) ,
gl_project_path : repo_type . repository_for ( project ) . full_path
}
end
def check_feature_enabled
2023-05-27 22:25:52 +05:30
not_found! ( 'Internal API not found' ) unless Feature . enabled? ( :kubernetes_agent_internal_api , type : :ops )
2020-10-24 23:57:45 +05:30
end
def check_agent_token
2021-04-29 21:17:54 +05:30
unauthorized! unless agent_token
2021-03-11 19:13:27 +05:30
2022-06-21 17:19:12 +05:30
:: Clusters :: AgentTokens :: TrackUsageService . new ( agent_token ) . execute
2020-10-24 23:57:45 +05:30
end
2022-08-27 11:52:29 +05:30
def agent_has_access_to_project? ( project )
Guest . can? ( :download_code , project ) || agent . has_access_to? ( project )
end
def increment_unique_events
events = params [ :unique_counters ] & . slice ( :agent_users_using_ci_tunnel )
events & . each do | event , entity_ids |
increment_unique_values ( event , entity_ids )
end
end
2023-01-13 00:05:48 +05:30
def increment_count_events
events = params [ :counters ] & . slice ( :gitops_sync , :k8s_api_proxy_request )
Gitlab :: UsageDataCounters :: KubernetesAgentCounter . increment_event_counts ( events )
end
2020-10-24 23:57:45 +05:30
end
namespace 'internal' do
namespace 'kubernetes' do
before do
check_agent_token
end
desc 'Gets agent info' do
detail 'Retrieves agent info for the given token'
end
route_setting :authentication , cluster_agent_token_allowed : true
2023-03-04 22:38:38 +05:30
get '/agent_info' , feature_category : :kubernetes_management , urgency : :low do
2020-10-24 23:57:45 +05:30
project = agent . project
status 200
{
project_id : project . id ,
agent_id : agent . id ,
agent_name : agent . name ,
gitaly_info : gitaly_info ( project ) ,
2022-08-13 15:12:31 +05:30
gitaly_repository : gitaly_repository ( project ) ,
default_branch : project . default_branch_or_main
2020-10-24 23:57:45 +05:30
}
end
2022-08-27 11:52:29 +05:30
desc 'Gets project info' do
detail 'Retrieves project info (if authorized)'
end
route_setting :authentication , cluster_agent_token_allowed : true
2023-03-04 22:38:38 +05:30
get '/project_info' , feature_category : :kubernetes_management , urgency : :low do
2022-08-27 11:52:29 +05:30
project = find_project ( params [ :id ] )
not_found! unless agent_has_access_to_project? ( project )
status 200
{
project_id : project . id ,
gitaly_info : gitaly_info ( project ) ,
gitaly_repository : gitaly_repository ( project ) ,
default_branch : project . default_branch_or_main
}
end
2020-10-24 23:57:45 +05:30
end
2020-11-24 15:15:51 +05:30
2023-04-23 21:23:45 +05:30
namespace 'kubernetes/agent_configuration' do
2021-11-11 11:23:49 +05:30
desc 'POST agent configuration' do
detail 'Store configuration for an agent'
end
params do
requires :agent_id , type : Integer , desc : 'ID of the configured Agent'
requires :agent_config , type : JSON , desc : 'Configuration for the Agent'
end
2023-04-23 21:23:45 +05:30
post '/' , feature_category : :kubernetes_management , urgency : :low do
2022-06-21 17:19:12 +05:30
agent = :: Clusters :: Agent . find ( params [ :agent_id ] )
2021-11-11 11:23:49 +05:30
2022-06-21 17:19:12 +05:30
:: Clusters :: Agents :: RefreshAuthorizationService . new ( agent , config : params [ :agent_config ] ) . execute
2021-11-11 11:23:49 +05:30
no_content!
end
end
2023-05-27 22:25:52 +05:30
namespace 'kubernetes/authorize_proxy_user' do
desc 'Authorize a proxy user request'
params do
requires :agent_id , type : Integer , desc : 'ID of the agent accessed'
requires :access_type , type : String , values : [ 'session_cookie' ] , desc : 'The type of the access key being verified.'
requires :access_key , type : String , desc : 'The authentication secret for the given access type.'
given access_type : - > ( val ) { val == 'session_cookie' } do
requires :csrf_token , type : String , allow_blank : false , desc : 'CSRF token that must be checked when access_type is "session_cookie", to ensure the request originates from a GitLab browsing session.'
end
end
post '/' , feature_category : :kubernetes_management do
# Load session
public_session_id_string =
begin
Gitlab :: Kas :: UserAccess . decrypt_public_session_id ( params [ :access_key ] )
rescue StandardError
bad_request! ( 'Invalid access_key' )
end
session_id = Rack :: Session :: SessionId . new ( public_session_id_string )
session = ActiveSession . sessions_from_ids ( [ session_id . private_id ] ) . first
unauthorized! ( 'Invalid session' ) unless session
# CSRF check
unless :: Gitlab :: Kas :: UserAccess . valid_authenticity_token? ( session . symbolize_keys , params [ :csrf_token ] )
unauthorized! ( 'CSRF token does not match' )
end
# Load user
user = Warden :: SessionSerializer . new ( 'rack.session' = > session ) . fetch ( :user )
unauthorized! ( 'Invalid user in session' ) unless user
# Load agent
agent = :: Clusters :: Agent . find ( params [ :agent_id ] )
unauthorized! ( 'Feature disabled for agent' ) unless :: Gitlab :: Kas :: UserAccess . enabled_for? ( agent )
service_response = :: Clusters :: Agents :: AuthorizeProxyUserService . new ( user , agent ) . execute
render_api_error! ( service_response [ :message ] , service_response [ :reason ] ) unless service_response . success?
service_response . payload
end
end
2020-11-24 15:15:51 +05:30
namespace 'kubernetes/usage_metrics' do
desc 'POST usage metrics' do
detail 'Updates usage metrics for agent'
end
params do
2022-08-27 11:52:29 +05:30
optional :counters , type : Hash do
optional :gitops_sync , type : Integer , desc : 'The count to increment the gitops_sync metric by'
2023-01-13 00:05:48 +05:30
optional :k8s_api_proxy_request , type : Integer , desc : 'The count to increment the k8s_api_proxy_request metric by'
2022-08-27 11:52:29 +05:30
end
optional :unique_counters , type : Hash do
2023-03-04 22:38:38 +05:30
optional :agent_users_using_ci_tunnel , type : Array [ Integer ] , desc : 'An array of user ids that have interacted with CI Tunnel'
2022-08-27 11:52:29 +05:30
end
2020-11-24 15:15:51 +05:30
end
2023-03-04 22:38:38 +05:30
post '/' , feature_category : :kubernetes_management do
2023-01-13 00:05:48 +05:30
increment_count_events
2022-08-27 11:52:29 +05:30
increment_unique_events
2020-11-24 15:15:51 +05:30
2021-06-08 01:23:25 +05:30
no_content!
rescue ArgumentError = > e
bad_request! ( e . message )
2020-11-24 15:15:51 +05:30
end
end
2020-10-24 23:57:45 +05:30
end
end
end
end
2021-02-22 17:27:13 +05:30
2021-06-08 01:23:25 +05:30
API :: Internal :: Kubernetes . prepend_mod_with ( 'API::Internal::Kubernetes' )