files/gitlab-cookbooks/gitlab-kas/libraries/gitlab_kas.rb (163 lines of code) (raw):
#
# Copyright:: Copyright (c) 2020 GitLab Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require_relative '../../package/libraries/helpers/secrets_helper'
module GitlabKas
class << self
def parse_variables
parse_address
parse_gitlab_external_url
parse_gitlab_kas_enabled
parse_gitlab_kas_external_url
parse_gitlab_kas_internal_url
parse_redis_settings
end
def parse_address
Gitlab['gitlab_kas']['gitlab_address'] ||= Gitlab['external_url']
end
def parse_gitlab_kas_enabled
# explicitly enabled or disabled, possibly external to this Omnibus instance
key = 'gitlab_kas_enabled'
return unless Gitlab['gitlab_rails'][key].nil?
# implicitly enable if installed and gitlab integration not explicitly disabled
Gitlab['gitlab_rails'][key] = gitlab_kas_attr('enable')
end
def parse_gitlab_kas_internal_url
key = 'gitlab_kas_internal_url'
return unless Gitlab['gitlab_rails'][key].nil?
return unless gitlab_kas_attr('enable')
network = gitlab_kas_attr('internal_api_listen_network')
case network
when 'unix'
scheme = 'unix'
when 'tcp', 'tcp4', 'tcp6'
scheme = 'grpc'
else
raise "gitlab_kas['internal_api_listen_network'] should be 'tcp', 'tcp4', 'tcp6' or 'unix' got '#{network}'"
end
address = gitlab_kas_attr('internal_api_listen_address')
Gitlab['gitlab_rails'][key] = "#{scheme}://#{address}"
end
def parse_gitlab_kas_external_url
return unless gitlab_kas_attr('enable')
# we need to return if `external_url` is not set because this is needed
# - to set the kas_url if `gitlab_kas_external_url` is not set
# - to check the domain of `gitlab_kas_external_url` against the GitLab url
return unless Gitlab['external_url']
Gitlab['gitlab_kas_external_url'] ||= build_default_gitlab_kas_external_url
if kas_domain_matches_gitlab_domain?
parse_gitlab_kas_external_url_with_gitlab_domain
parse_gitlab_kas_external_k8s_proxy_url_with_gitlab_domain
else
parse_gitlab_kas_external_url_using_own_subdomain
parse_gitlab_kas_external_k8s_proxy_url_using_own_subdomain
end
end
def parse_gitlab_external_url
return if Gitlab['external_url'].nil?
gitlab_uri = URI(Gitlab['external_url'])
Gitlab['gitlab_kas']['gitlab_external_url'] ||= "#{gitlab_uri.scheme}://#{gitlab_uri.host}"
end
def parse_secrets
Gitlab['gitlab_kas']['api_secret_key'] ||= Base64.strict_encode64(SecretsHelper.generate_hex(16))
Gitlab['gitlab_kas']['private_api_secret_key'] ||= Base64.strict_encode64(SecretsHelper.generate_hex(16))
Gitlab['gitlab_kas']['websocket_token_secret_key'] ||= SecretsHelper.generate_base64(72)
end
def validate_secrets
if Gitlab['gitlab_kas']['api_secret_key']
# KAS and GitLab expects exactly 32 bytes, encoded with base64
api_secret_key = Base64.strict_decode64(Gitlab['gitlab_kas']['api_secret_key'])
raise "gitlab_kas['api_secret_key'] should be exactly 32 bytes" if api_secret_key.length != 32
end
if Gitlab['gitlab_kas']['private_api_secret_key']
private_api_secret_key = Base64.strict_decode64(Gitlab['gitlab_kas']['private_api_secret_key'])
raise "gitlab_kas['private_api_secret_key'] should be exactly 32 bytes" if private_api_secret_key.length != 32
end
return unless Gitlab['gitlab_kas']['websocket_token_secret_key']
websocket_token_secret_key = Base64.strict_decode64(Gitlab['gitlab_kas']['websocket_token_secret_key'])
raise "gitlab_kas['websocket_token_secret_key'] should be exactly 72 bytes" if websocket_token_secret_key.length != 72
end
def parse_redis_settings
# If KAS has separate Redis instance specified, do not copy any other settings
return if Gitlab['gitlab_kas'].key?('redis_host') || Gitlab['gitlab_kas'].key?('redis_socket')
settings_copied_from_gitlab_rails = %w[
redis_socket
redis_host
redis_port
redis_password
redis_sentinels
redis_sentinels_password
redis_ssl
redis_tls_ca_cert_file
redis_tls_client_cert_file
redis_tls_client_key_file
]
settings_copied_from_gitlab_rails.each do |setting|
Gitlab['node'].default['gitlab_kas'][setting] = Gitlab['node']['gitlab']['gitlab_rails'][setting]
Gitlab['gitlab_kas'][setting] = Gitlab['gitlab_rails'][setting] unless Gitlab['gitlab_kas'].key?(setting)
end
Gitlab['node'].default['gitlab_kas']['redis_sentinels_master_name'] = Gitlab['node']['redis']['master_name']
Gitlab['gitlab_kas']['redis_sentinels_master_name'] = Gitlab['redis']['master_name'] unless Gitlab['gitlab_kas'].key?('redis_sentinels_master_name')
end
private
def parse_gitlab_kas_external_url_with_gitlab_domain
key = 'gitlab_kas_external_url'
return unless Gitlab['gitlab_rails'][key].nil?
Gitlab['gitlab_rails'][key] = Gitlab[key]
end
def parse_gitlab_kas_external_k8s_proxy_url_with_gitlab_domain
key = 'gitlab_kas_external_k8s_proxy_url'
return unless Gitlab['gitlab_rails'][key].nil?
gitlab_external_url = Gitlab['external_url']
return unless gitlab_external_url
# For now, the default external proxy URL is on the subpath /-/kubernetes-agent/k8s-proxy/
# See https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5784
Gitlab['gitlab_rails'][key] = "#{gitlab_external_url}/-/kubernetes-agent/k8s-proxy/"
end
def parse_gitlab_kas_external_url_using_own_subdomain
key = 'gitlab_kas_external_url'
return unless Gitlab['gitlab_rails'][key].nil?
kas_uri = URI(Gitlab[key].to_s)
raise "gitlab_kas_external_url must include a scheme and FQDN, e.g. wss://kas.gitlab.example.com/" unless kas_uri.host
# We are temporarily not supporting grpc/grpcs as this requires a bigger change in the NGINX configuration
raise "gitlab_kas_external_url scheme must be 'ws' or 'wss'" unless ws_scheme?(kas_uri.scheme)
raise "gitlab_kas['listen_websocket'] must be set to `true`" unless gitlab_kas_attr('listen_websocket')
use_ssl = kas_uri.scheme == 'wss'
Gitlab['gitlab_kas_nginx']['host'] ||= kas_uri.host
Gitlab['gitlab_kas_nginx']['port'] ||= use_ssl ? '443' : '80'
# set gitlab_kas_nginx configs
parse_gitlab_kas_nginx(kas_uri, use_ssl)
Gitlab['gitlab_rails'][key] = kas_uri.to_s
end
def parse_gitlab_kas_nginx(kas_uri, use_ssl)
Gitlab['gitlab_kas_nginx']['enable'] = true
Gitlab['gitlab_kas_nginx']['https'] ||= use_ssl
if use_ssl
Gitlab['gitlab_kas_nginx']['ssl_certificate'] ||= "/etc/gitlab/ssl/#{kas_uri.host}.crt"
Gitlab['gitlab_kas_nginx']['ssl_certificate_key'] ||= "/etc/gitlab/ssl/#{kas_uri.host}.key"
LetsEncryptHelper.add_service_alt_name('gitlab_kas')
end
Nginx.parse_proxy_headers('gitlab_kas_nginx', use_ssl, true)
end
def parse_gitlab_kas_external_k8s_proxy_url_using_own_subdomain
key = 'gitlab_kas_external_k8s_proxy_url'
return unless Gitlab['gitlab_rails'][key].nil?
kas_uri = URI(Gitlab['gitlab_kas_external_url'].to_s)
scheme = kas_uri.scheme == 'wss' ? 'https' : 'http'
Gitlab['gitlab_rails'][key] = "#{scheme}://#{kas_uri.host}/k8s-proxy/"
end
def build_default_gitlab_kas_external_url
# For now, the default external URL is on the subpath /-/kubernetes-agent/
# so whether to use TLS is determined from the primary external_url.
# See https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5784
gitlab_uri = URI(Gitlab['external_url'])
case gitlab_uri.scheme
when 'https'
scheme = gitlab_kas_attr('listen_websocket') ? 'wss' : 'grpcs'
port = gitlab_uri.port == 443 ? '' : ":#{port}"
when 'http'
scheme = gitlab_kas_attr('listen_websocket') ? 'ws' : 'grpc'
port = gitlab_uri.port == 80 ? '' : ":#{port}"
else
raise "external_url scheme should be 'http' or 'https', got '#{gitlab_uri.scheme}"
end
"#{scheme}://#{gitlab_uri.host}#{port}#{gitlab_uri.path}/-/kubernetes-agent/"
end
def kas_domain_matches_gitlab_domain?
gitlab_uri = URI(Gitlab['external_url'])
gitlab_kas_uri = URI(Gitlab['gitlab_kas_external_url'])
gitlab_uri.host == gitlab_kas_uri.host
end
def gitlab_kas_attr(key)
configured = Gitlab['gitlab_kas'][key]
return configured unless configured.nil?
Gitlab['node']['gitlab_kas'][key]
end
def ws_scheme?(scheme)
%w[ws wss].include?(scheme)
end
end
end