summaryrefslogtreecommitdiff
path: root/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
blob: b1820474c9df5c55eb991f9c6842e00fbae3932a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# frozen_string_literal: true

module Clusters
  module Kubernetes
    class CreateOrUpdateServiceAccountService
      def initialize(kubeclient, service_account_name:, service_account_namespace:, service_account_namespace_labels: nil, token_name:, rbac:, namespace_creator: false, role_binding_name: nil)
        @kubeclient = kubeclient
        @service_account_name = service_account_name
        @service_account_namespace = service_account_namespace
        @service_account_namespace_labels = service_account_namespace_labels
        @token_name = token_name
        @rbac = rbac
        @namespace_creator = namespace_creator
        @role_binding_name = role_binding_name
      end

      def self.gitlab_creator(kubeclient, rbac:)
        self.new(
          kubeclient,
          service_account_name: Clusters::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAME,
          service_account_namespace: Clusters::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAMESPACE,
          token_name: Clusters::Kubernetes::GITLAB_ADMIN_TOKEN_NAME,
          rbac: rbac
        )
      end

      def self.namespace_creator(kubeclient, service_account_name:, service_account_namespace:, service_account_namespace_labels:, rbac:)
        self.new(
          kubeclient,
          service_account_name: service_account_name,
          service_account_namespace: service_account_namespace,
          service_account_namespace_labels: service_account_namespace_labels,
          token_name: "#{service_account_namespace}-token",
          rbac: rbac,
          namespace_creator: true,
          role_binding_name: "gitlab-#{service_account_namespace}"
        )
      end

      def execute
        ensure_project_namespace_exists if namespace_creator

        kubeclient.create_or_update_service_account(service_account_resource)
        kubeclient.create_or_update_secret(service_account_token_resource)

        return unless rbac

        create_role_or_cluster_role_binding

        return unless namespace_creator

        create_or_update_knative_serving_role
        create_or_update_knative_serving_role_binding
        create_or_update_crossplane_database_role
        create_or_update_crossplane_database_role_binding
      end

      private

      attr_reader :kubeclient, :service_account_name, :service_account_namespace, :service_account_namespace_labels, :token_name, :rbac, :namespace_creator, :role_binding_name

      def ensure_project_namespace_exists
        Gitlab::Kubernetes::Namespace.new(
          service_account_namespace,
          kubeclient,
          labels: service_account_namespace_labels
        ).ensure_exists!
      end

      def create_role_or_cluster_role_binding
        if namespace_creator
          kubeclient.create_or_update_role_binding(role_binding_resource)
        else
          kubeclient.create_or_update_cluster_role_binding(cluster_role_binding_resource)
        end
      end

      def create_or_update_knative_serving_role
        kubeclient.update_role(knative_serving_role_resource)
      end

      def create_or_update_knative_serving_role_binding
        kubeclient.update_role_binding(knative_serving_role_binding_resource)
      end

      def create_or_update_crossplane_database_role
        kubeclient.update_role(crossplane_database_role_resource)
      end

      def create_or_update_crossplane_database_role_binding
        kubeclient.update_role_binding(crossplane_database_role_binding_resource)
      end

      def service_account_resource
        Gitlab::Kubernetes::ServiceAccount.new(
          service_account_name,
          service_account_namespace
        ).generate
      end

      def service_account_token_resource
        Gitlab::Kubernetes::ServiceAccountToken.new(
          token_name,
          service_account_name,
          service_account_namespace
        ).generate
      end

      def cluster_role_binding_resource
        subjects = [{ kind: 'ServiceAccount', name: service_account_name, namespace: service_account_namespace }]

        Gitlab::Kubernetes::ClusterRoleBinding.new(
          Clusters::Kubernetes::GITLAB_CLUSTER_ROLE_BINDING_NAME,
          Clusters::Kubernetes::GITLAB_CLUSTER_ROLE_NAME,
          subjects
        ).generate
      end

      def role_binding_resource
        Gitlab::Kubernetes::RoleBinding.new(
          name: role_binding_name,
          role_name: Clusters::Kubernetes::PROJECT_CLUSTER_ROLE_NAME,
          role_kind: :ClusterRole,
          namespace: service_account_namespace,
          service_account_name: service_account_name
        ).generate
      end

      def knative_serving_role_resource
        Gitlab::Kubernetes::Role.new(
          name: Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME,
          namespace: service_account_namespace,
          rules: [{
            apiGroups: %w(serving.knative.dev),
            resources: %w(configurations configurationgenerations routes revisions revisionuids autoscalers services),
            verbs: %w(get list create update delete patch watch)
          }]
        ).generate
      end

      def knative_serving_role_binding_resource
        Gitlab::Kubernetes::RoleBinding.new(
          name: Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME,
          role_name: Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME,
          role_kind: :Role,
          namespace: service_account_namespace,
          service_account_name: service_account_name
        ).generate
      end

      def crossplane_database_role_resource
        Gitlab::Kubernetes::Role.new(
          name: Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_NAME,
          namespace: service_account_namespace,
          rules: [{
            apiGroups: %w(database.crossplane.io),
            resources: %w(postgresqlinstances),
            verbs: %w(get list create watch)
          }]
        ).generate
      end

      def crossplane_database_role_binding_resource
        Gitlab::Kubernetes::RoleBinding.new(
          name: Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_BINDING_NAME,
          role_name: Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_NAME,
          role_kind: :Role,
          namespace: service_account_namespace,
          service_account_name: service_account_name
        ).generate
      end
    end
  end
end