diff options
Diffstat (limited to 'app/services/clusters/aws')
5 files changed, 0 insertions, 428 deletions
diff --git a/app/services/clusters/aws/authorize_role_service.rb b/app/services/clusters/aws/authorize_role_service.rb deleted file mode 100644 index 7ca20289bf7..00000000000 --- a/app/services/clusters/aws/authorize_role_service.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Aws - class AuthorizeRoleService - attr_reader :user - - Response = Struct.new(:status, :body) - - ERRORS = [ - ActiveRecord::RecordInvalid, - ActiveRecord::RecordNotFound, - Clusters::Aws::FetchCredentialsService::MissingRoleError, - ::Aws::Errors::MissingCredentialsError, - ::Aws::STS::Errors::ServiceError - ].freeze - - def initialize(user, params:) - @user = user - @role_arn = params[:role_arn] - @region = params[:region] - end - - def execute - ensure_role_exists! - update_role_arn! - - Response.new(:ok, credentials) - rescue *ERRORS => e - Gitlab::ErrorTracking.track_exception(e) - - Response.new(:unprocessable_entity, response_details(e)) - end - - private - - attr_reader :role, :role_arn, :region - - def ensure_role_exists! - @role = ::Aws::Role.find_by_user_id!(user.id) - end - - def update_role_arn! - role.update!(role_arn: role_arn, region: region) - end - - def credentials - Clusters::Aws::FetchCredentialsService.new(role).execute - end - - def response_details(exception) - message = - case exception - when ::Aws::STS::Errors::AccessDenied - _("Access denied: %{error}") % { error: exception.message } - when ::Aws::STS::Errors::ServiceError - _("AWS service error: %{error}") % { error: exception.message } - when ActiveRecord::RecordNotFound - _("Error: Unable to find AWS role for current user") - when ActiveRecord::RecordInvalid - exception.message - when Clusters::Aws::FetchCredentialsService::MissingRoleError - _("Error: No AWS provision role found for user") - when ::Aws::Errors::MissingCredentialsError - _("Error: No AWS credentials were supplied") - else - _('An error occurred while authorizing your role') - end - - { message: message }.compact - end - end - end -end diff --git a/app/services/clusters/aws/fetch_credentials_service.rb b/app/services/clusters/aws/fetch_credentials_service.rb deleted file mode 100644 index e38852c7ec7..00000000000 --- a/app/services/clusters/aws/fetch_credentials_service.rb +++ /dev/null @@ -1,80 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Aws - class FetchCredentialsService - attr_reader :provision_role - - MissingRoleError = Class.new(StandardError) - - def initialize(provision_role, provider: nil) - @provision_role = provision_role - @provider = provider - @region = provider&.region || provision_role&.region || Clusters::Providers::Aws::DEFAULT_REGION - end - - def execute - raise MissingRoleError, 'AWS provisioning role not configured' unless provision_role.present? - - ::Aws::AssumeRoleCredentials.new( - client: client, - role_arn: provision_role.role_arn, - role_session_name: session_name, - external_id: provision_role.role_external_id, - policy: session_policy - ).credentials - end - - private - - attr_reader :provider, :region - - def client - ::Aws::STS::Client.new(**client_args) - end - - def client_args - { region: region, credentials: gitlab_credentials }.compact - end - - def gitlab_credentials - # These are not needed for IAM instance profiles - return unless access_key_id.present? && secret_access_key.present? - - ::Aws::Credentials.new(access_key_id, secret_access_key) - end - - def access_key_id - Gitlab::CurrentSettings.eks_access_key_id - end - - def secret_access_key - Gitlab::CurrentSettings.eks_secret_access_key - end - - ## - # If we haven't created a provider record yet, - # we restrict ourselves to read-only access so - # that we can safely expose credentials to the - # frontend (to be used when populating the - # creation form). - def session_policy - if provider.nil? - File.read(read_only_policy) - end - end - - def read_only_policy - Rails.root.join('vendor', 'aws', 'iam', "eks_cluster_read_only_policy.json") - end - - def session_name - if provider.present? - "gitlab-eks-cluster-#{provider.cluster_id}-user-#{provision_role.user_id}" - else - "gitlab-eks-autofill-user-#{provision_role.user_id}" - end - end - end - end -end diff --git a/app/services/clusters/aws/finalize_creation_service.rb b/app/services/clusters/aws/finalize_creation_service.rb deleted file mode 100644 index 54f07e1d44c..00000000000 --- a/app/services/clusters/aws/finalize_creation_service.rb +++ /dev/null @@ -1,139 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Aws - class FinalizeCreationService - include Gitlab::Utils::StrongMemoize - - attr_reader :provider - - delegate :cluster, to: :provider - - def execute(provider) - @provider = provider - - configure_provider - create_gitlab_service_account! - configure_platform_kubernetes - configure_node_authentication! - - cluster.save! - rescue ::Aws::CloudFormation::Errors::ServiceError => e - log_service_error(e.class.name, provider.id, e.message) - provider.make_errored!(s_('ClusterIntegration|Failed to fetch CloudFormation stack: %{message}') % { message: e.message }) - rescue Kubeclient::HttpError => e - log_service_error(e.class.name, provider.id, e.message) - provider.make_errored!(s_('ClusterIntegration|Failed to run Kubeclient: %{message}') % { message: e.message }) - rescue ActiveRecord::RecordInvalid => e - log_service_error(e.class.name, provider.id, e.message) - provider.make_errored!(s_('ClusterIntegration|Failed to configure EKS provider: %{message}') % { message: e.message }) - end - - private - - def create_gitlab_service_account! - Clusters::Kubernetes::CreateOrUpdateServiceAccountService.gitlab_creator( - kube_client, - rbac: true - ).execute - end - - def configure_provider - provider.status_event = :make_created - end - - def configure_platform_kubernetes - cluster.build_platform_kubernetes( - api_url: cluster_endpoint, - ca_cert: cluster_certificate, - token: request_kubernetes_token) - end - - def request_kubernetes_token - Clusters::Kubernetes::FetchKubernetesTokenService.new( - kube_client, - Clusters::Kubernetes::GITLAB_ADMIN_TOKEN_NAME, - Clusters::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAMESPACE - ).execute - end - - def kube_client - @kube_client ||= build_kube_client!( - cluster_endpoint, - cluster_certificate - ) - end - - def build_kube_client!(api_url, ca_pem) - raise "Incomplete settings" unless api_url - - Gitlab::Kubernetes::KubeClient.new( - api_url, - auth_options: kubeclient_auth_options, - ssl_options: kubeclient_ssl_options(ca_pem), - http_proxy_uri: ENV['http_proxy'] - ) - end - - def kubeclient_auth_options - { bearer_token: Kubeclient::AmazonEksCredentials.token(provider.credentials, cluster.name) } - end - - def kubeclient_ssl_options(ca_pem) - opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER } - - if ca_pem.present? - opts[:cert_store] = OpenSSL::X509::Store.new - opts[:cert_store].add_cert(OpenSSL::X509::Certificate.new(ca_pem)) - end - - opts - end - - def cluster_stack - @cluster_stack ||= provider.api_client.describe_stacks(stack_name: provider.cluster.name).stacks.first - end - - def stack_output_value(key) - cluster_stack.outputs.detect { |output| output.output_key == key }.output_value - end - - def node_instance_role_arn - stack_output_value('NodeInstanceRole') - end - - def cluster_endpoint - strong_memoize(:cluster_endpoint) do - stack_output_value('ClusterEndpoint') - end - end - - def cluster_certificate - strong_memoize(:cluster_certificate) do - Base64.decode64(stack_output_value('ClusterCertificate')) - end - end - - def configure_node_authentication! - kube_client.create_config_map(node_authentication_config) - end - - def node_authentication_config - Gitlab::Kubernetes::ConfigMaps::AwsNodeAuth.new(node_instance_role_arn).generate - end - - def logger - @logger ||= Gitlab::Kubernetes::Logger.build - end - - def log_service_error(exception, provider_id, message) - logger.error( - exception: exception.class.name, - service: self.class.name, - provider_id: provider_id, - message: message - ) - end - end - end -end diff --git a/app/services/clusters/aws/provision_service.rb b/app/services/clusters/aws/provision_service.rb deleted file mode 100644 index b454a7a5f59..00000000000 --- a/app/services/clusters/aws/provision_service.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Aws - class ProvisionService - attr_reader :provider - - def execute(provider) - @provider = provider - - configure_provider_credentials - provision_cluster - - if provider.make_creating - WaitForClusterCreationWorker.perform_in( - Clusters::Aws::VerifyProvisionStatusService::INITIAL_INTERVAL, - provider.cluster_id - ) - else - provider.make_errored!("Failed to update provider record; #{provider.errors.full_messages}") - end - rescue Clusters::Aws::FetchCredentialsService::MissingRoleError - provider.make_errored!('Amazon role is not configured') - rescue ::Aws::Errors::MissingCredentialsError - provider.make_errored!('Amazon credentials are not configured') - rescue ::Aws::STS::Errors::ServiceError => e - provider.make_errored!("Amazon authentication failed; #{e.message}") - rescue ::Aws::CloudFormation::Errors::ServiceError => e - provider.make_errored!("Amazon CloudFormation request failed; #{e.message}") - end - - private - - def provision_role - provider.created_by_user&.aws_role - end - - def credentials - @credentials ||= Clusters::Aws::FetchCredentialsService.new( - provision_role, - provider: provider - ).execute - end - - def configure_provider_credentials - provider.update!( - access_key_id: credentials.access_key_id, - secret_access_key: credentials.secret_access_key, - session_token: credentials.session_token - ) - end - - def provision_cluster - provider.api_client.create_stack( - stack_name: provider.cluster.name, - template_body: stack_template, - parameters: parameters, - capabilities: ["CAPABILITY_IAM"] - ) - end - - def parameters - [ - parameter('ClusterName', provider.cluster.name), - parameter('ClusterRole', provider.role_arn), - parameter('KubernetesVersion', provider.kubernetes_version), - parameter('ClusterControlPlaneSecurityGroup', provider.security_group_id), - parameter('VpcId', provider.vpc_id), - parameter('Subnets', provider.subnet_ids.join(',')), - parameter('NodeAutoScalingGroupDesiredCapacity', provider.num_nodes.to_s), - parameter('NodeInstanceType', provider.instance_type), - parameter('KeyName', provider.key_name) - ] - end - - def parameter(key, value) - { parameter_key: key, parameter_value: value } - end - - def stack_template - File.read(Rails.root.join('vendor', 'aws', 'cloudformation', 'eks_cluster.yaml')) - end - end - end -end diff --git a/app/services/clusters/aws/verify_provision_status_service.rb b/app/services/clusters/aws/verify_provision_status_service.rb deleted file mode 100644 index 99532662bc4..00000000000 --- a/app/services/clusters/aws/verify_provision_status_service.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Aws - class VerifyProvisionStatusService - attr_reader :provider - - INITIAL_INTERVAL = 5.minutes - POLL_INTERVAL = 1.minute - TIMEOUT = 30.minutes - - def execute(provider) - @provider = provider - - case cluster_stack.stack_status - when 'CREATE_IN_PROGRESS' - continue_creation - when 'CREATE_COMPLETE' - finalize_creation - else - provider.make_errored!("Unexpected status; #{cluster_stack.stack_status}") - end - rescue ::Aws::CloudFormation::Errors::ServiceError => e - provider.make_errored!("Amazon CloudFormation request failed; #{e.message}") - end - - private - - def cluster_stack - @cluster_stack ||= provider.api_client.describe_stacks(stack_name: provider.cluster.name).stacks.first - end - - def continue_creation - if timeout_threshold.future? - WaitForClusterCreationWorker.perform_in(POLL_INTERVAL, provider.cluster_id) - else - provider.make_errored!(_('Kubernetes cluster creation time exceeds timeout; %{timeout}') % { timeout: TIMEOUT }) - end - end - - def timeout_threshold - cluster_stack.creation_time + TIMEOUT - end - - def finalize_creation - Clusters::Aws::FinalizeCreationService.new.execute(provider) - end - end - end -end |