Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
c03d5b8f
Commit
c03d5b8f
authored
Jan 20, 2022
by
Sri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Grant permissions to generated Gcp service account
parent
a41810b5
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
103 additions
and
32 deletions
+103
-32
app/services/google_cloud/create_service_accounts_service.rb
app/services/google_cloud/create_service_accounts_service.rb
+3
-2
ee/spec/services/google_cloud/create_service_accounts_service_spec.rb
...ices/google_cloud/create_service_accounts_service_spec.rb
+12
-9
lib/google_api/cloud_platform/client.rb
lib/google_api/cloud_platform/client.rb
+25
-5
spec/lib/google_api/cloud_platform/client_spec.rb
spec/lib/google_api/cloud_platform/client_spec.rb
+48
-4
spec/requests/projects/google_cloud/service_accounts_controller_spec.rb
...projects/google_cloud/service_accounts_controller_spec.rb
+5
-6
spec/services/google_cloud/create_service_accounts_service_spec.rb
...ices/google_cloud/create_service_accounts_service_spec.rb
+10
-6
No files found.
app/services/google_cloud/create_service_accounts_service.rb
View file @
c03d5b8f
...
...
@@ -5,6 +5,7 @@ module GoogleCloud
def
execute
service_account
=
google_api_client
.
create_service_account
(
gcp_project_id
,
service_account_name
,
service_account_desc
)
service_account_key
=
google_api_client
.
create_service_account_key
(
gcp_project_id
,
service_account
.
unique_id
)
google_api_client
.
grant_service_account_roles
(
gcp_project_id
,
service_account
.
email
)
service_accounts_service
.
add_for_project
(
environment_name
,
...
...
@@ -35,7 +36,7 @@ module GoogleCloud
end
def
google_api_client
GoogleApi
::
CloudPlatform
::
Client
.
new
(
google_oauth2_token
,
nil
)
@google_api_client_instance
||=
GoogleApi
::
CloudPlatform
::
Client
.
new
(
google_oauth2_token
,
nil
)
end
def
service_accounts_service
...
...
@@ -50,7 +51,7 @@ module GoogleCloud
"GitLab generated service account for project '
#{
project
.
name
}
' and environment '
#{
environment_name
}
'"
end
# Overriden in EE
# Overrid
d
en in EE
def
environment_protected?
false
end
...
...
ee/spec/services/google_cloud/create_service_accounts_service_spec.rb
View file @
c03d5b8f
...
...
@@ -2,10 +2,6 @@
require
'spec_helper'
# Mock Types
MockGoogleOAuth2Credentials
=
Struct
.
new
(
:app_id
,
:app_secret
)
MockServiceAccount
=
Struct
.
new
(
:project_id
,
:unique_id
)
RSpec
.
describe
GoogleCloud
::
CreateServiceAccountsService
do
let
(
:google_oauth2_token
)
{
'mock-token'
}
let
(
:gcp_project_id
)
{
'mock-gcp-project-id'
}
...
...
@@ -14,19 +10,26 @@ RSpec.describe GoogleCloud::CreateServiceAccountsService do
before
do
stub_licensed_features
(
protected_environments:
true
)
mock_google_oauth2_creds
=
Struct
.
new
(
:app_id
,
:app_secret
)
.
new
(
'mock-app-id'
,
'mock-app-secret'
)
allow
(
Gitlab
::
Auth
::
OAuth
::
Provider
)
.
to
receive
(
:config_for
)
.
with
(
'google_oauth2'
)
.
and_return
(
MockGoogleOAuth2Credentials
.
new
(
'mock-app-id'
,
'mock-app-secret'
)
)
.
and_return
(
mock_google_oauth2_creds
)
allow_next_instance_of
(
GoogleApi
::
CloudPlatform
::
Client
)
do
|
client
|
allow
(
client
)
expect_next_instance_of
(
GoogleApi
::
CloudPlatform
::
Client
)
do
|
client
|
mock_service_account
=
Struct
.
new
(
:project_id
,
:unique_id
,
:email
)
.
new
(
'mock-project-id'
,
'mock-unique-id'
,
'mock-email'
)
expect
(
client
)
.
to
receive
(
:create_service_account
)
.
and_return
(
MockServiceAccount
.
new
(
'mock-project-id'
,
'mock-unique-id'
)
)
.
and_return
(
mock_service_account
)
allow
(
client
)
expect
(
client
)
.
to
receive
(
:create_service_account_key
)
.
and_return
(
'mock-key'
)
expect
(
client
)
.
to
receive
(
:grant_service_account_roles
)
end
end
...
...
lib/google_api/cloud_platform/client.rb
View file @
c03d5b8f
...
...
@@ -20,6 +20,7 @@ module GoogleApi
"https://www.googleapis.com/auth/logging.write"
,
"https://www.googleapis.com/auth/monitoring"
].
freeze
ROLES_LIST
=
%w[roles/iam.serviceAccountUser roles/artifactregistry.admin roles/cloudbuild.builds.builder roles/run.admin roles/storage.admin roles/cloudsql.admin roles/browser]
.
freeze
class
<<
self
def
session_key_for_token
...
...
@@ -88,11 +89,8 @@ module GoogleApi
def
list_projects
result
=
[]
service
=
Google
::
Apis
::
CloudresourcemanagerV1
::
CloudResourceManagerService
.
new
service
.
authorization
=
access_token
response
=
service
.
fetch_all
(
items: :projects
)
do
|
token
|
service
.
list_projects
response
=
cloud_resource_manager_service
.
fetch_all
(
items: :projects
)
do
|
token
|
cloud_resource_manager_service
.
list_projects
end
# Google API results are paged by default, so we need to iterate through
...
...
@@ -130,6 +128,11 @@ module GoogleApi
service
.
create_service_account_key
(
name
,
request_body
)
end
def
grant_service_account_roles
(
gcp_project_id
,
email
)
body
=
policy_request_body
(
gcp_project_id
,
email
)
cloud_resource_manager_service
.
set_project_iam_policy
(
gcp_project_id
,
body
)
end
private
def
make_cluster_options
(
cluster_name
,
cluster_size
,
machine_type
,
legacy_abac
,
enable_addons
)
...
...
@@ -173,6 +176,23 @@ module GoogleApi
options
.
header
=
{
'User-Agent'
:
"GitLab/
#{
Gitlab
::
VERSION
.
match
(
'(\d+\.\d+)'
).
captures
.
first
}
(GPN:GitLab;)"
}
end
end
def
policy_request_body
(
gcp_project_id
,
email
)
policy
=
cloud_resource_manager_service
.
get_project_iam_policy
(
gcp_project_id
)
policy
.
bindings
=
policy
.
bindings
+
additional_policy_bindings
(
"serviceAccount:
#{
email
}
"
)
Google
::
Apis
::
CloudresourcemanagerV1
::
SetIamPolicyRequest
.
new
(
policy:
policy
)
end
def
additional_policy_bindings
(
member
)
ROLES_LIST
.
map
do
|
role
|
Google
::
Apis
::
CloudresourcemanagerV1
::
Binding
.
new
(
role:
role
,
members:
[
member
])
end
end
def
cloud_resource_manager_service
@gpc_service
||=
Google
::
Apis
::
CloudresourcemanagerV1
::
CloudResourceManagerService
.
new
.
tap
{
|
s
|
s
.
authorization
=
access_token
}
end
end
end
end
spec/lib/google_api/cloud_platform/client_spec.rb
View file @
c03d5b8f
...
...
@@ -60,7 +60,7 @@ RSpec.describe GoogleApi::CloudPlatform::Client do
before
do
allow_any_instance_of
(
Google
::
Apis
::
ContainerV1
::
ContainerService
)
.
to
receive
(
:get_zone_cluster
).
with
(
any_args
,
options:
user_agent_options
)
.
and_return
(
gke_cluster
)
.
and_return
(
gke_cluster
)
end
it
{
is_expected
.
to
eq
(
gke_cluster
)
}
...
...
@@ -122,7 +122,7 @@ RSpec.describe GoogleApi::CloudPlatform::Client do
before
do
allow_any_instance_of
(
Google
::
Apis
::
ContainerV1beta1
::
ContainerService
)
.
to
receive
(
:create_cluster
).
with
(
any_args
)
.
and_return
(
operation
)
.
and_return
(
operation
)
end
it
'sets corresponded parameters'
do
...
...
@@ -172,7 +172,7 @@ RSpec.describe GoogleApi::CloudPlatform::Client do
before
do
allow_any_instance_of
(
Google
::
Apis
::
ContainerV1
::
ContainerService
)
.
to
receive
(
:get_zone_operation
).
with
(
any_args
,
options:
user_agent_options
)
.
and_return
(
operation
)
.
and_return
(
operation
)
end
it
{
is_expected
.
to
eq
(
operation
)
}
...
...
@@ -244,7 +244,7 @@ RSpec.describe GoogleApi::CloudPlatform::Client do
let
(
:operation
)
{
double
(
'Service Account Key'
)
}
it
'c
las
s Google Api IamService#create_service_account_key'
do
it
'c
all
s Google Api IamService#create_service_account_key'
do
expect_any_instance_of
(
Google
::
Apis
::
IamV1
::
IamService
)
.
to
receive
(
:create_service_account_key
)
.
with
(
any_args
)
...
...
@@ -252,4 +252,48 @@ RSpec.describe GoogleApi::CloudPlatform::Client do
is_expected
.
to
eq
(
operation
)
end
end
describe
'grant_service_account_roles'
do
subject
{
client
.
grant_service_account_roles
(
spy
,
spy
)
}
it
'calls Google Api CloudResourceManager#set_iam_policy'
do
mock_gcp_id
=
'mock-gcp-id'
mock_email
=
'mock@email.com'
mock_policy
=
Struct
.
new
(
:bindings
).
new
([])
mock_body
=
[]
expect
(
Google
::
Apis
::
CloudresourcemanagerV1
::
Binding
).
to
receive
(
:new
)
.
with
({
'role'
:
'roles/iam.serviceAccountUser'
,
'members'
:
[
"serviceAccount:
#{
mock_email
}
"
]
})
expect
(
Google
::
Apis
::
CloudresourcemanagerV1
::
Binding
).
to
receive
(
:new
)
.
with
({
'role'
:
'roles/artifactregistry.admin'
,
'members'
:
[
"serviceAccount:
#{
mock_email
}
"
]
})
expect
(
Google
::
Apis
::
CloudresourcemanagerV1
::
Binding
).
to
receive
(
:new
)
.
with
({
'role'
:
'roles/cloudbuild.builds.builder'
,
'members'
:
[
"serviceAccount:
#{
mock_email
}
"
]
})
expect
(
Google
::
Apis
::
CloudresourcemanagerV1
::
Binding
).
to
receive
(
:new
)
.
with
({
'role'
:
'roles/run.admin'
,
'members'
:
[
"serviceAccount:
#{
mock_email
}
"
]
})
expect
(
Google
::
Apis
::
CloudresourcemanagerV1
::
Binding
).
to
receive
(
:new
)
.
with
({
'role'
:
'roles/storage.admin'
,
'members'
:
[
"serviceAccount:
#{
mock_email
}
"
]
})
expect
(
Google
::
Apis
::
CloudresourcemanagerV1
::
Binding
).
to
receive
(
:new
)
.
with
({
'role'
:
'roles/cloudsql.admin'
,
'members'
:
[
"serviceAccount:
#{
mock_email
}
"
]
})
expect
(
Google
::
Apis
::
CloudresourcemanagerV1
::
Binding
).
to
receive
(
:new
)
.
with
({
'role'
:
'roles/browser'
,
'members'
:
[
"serviceAccount:
#{
mock_email
}
"
]
})
expect
(
Google
::
Apis
::
CloudresourcemanagerV1
::
SetIamPolicyRequest
).
to
receive
(
:new
).
and_return
([])
expect_next_instance_of
(
Google
::
Apis
::
CloudresourcemanagerV1
::
CloudResourceManagerService
)
do
|
instance
|
expect
(
instance
).
to
receive
(
:get_project_iam_policy
)
.
with
(
mock_gcp_id
)
.
and_return
(
mock_policy
)
expect
(
instance
).
to
receive
(
:set_project_iam_policy
)
.
with
(
mock_gcp_id
,
mock_body
)
end
client
.
grant_service_account_roles
(
mock_gcp_id
,
mock_email
)
end
end
end
spec/requests/projects/google_cloud/service_accounts_controller_spec.rb
View file @
c03d5b8f
...
...
@@ -2,10 +2,6 @@
require
'spec_helper'
# Mock Types
MockGoogleOAuth2Credentials
=
Struct
.
new
(
:app_id
,
:app_secret
)
MockServiceAccount
=
Struct
.
new
(
:project_id
,
:unique_id
)
RSpec
.
describe
Projects
::
GoogleCloud
::
ServiceAccountsController
do
let_it_be
(
:project
)
{
create
(
:project
,
:public
)
}
...
...
@@ -86,10 +82,12 @@ RSpec.describe Projects::GoogleCloud::ServiceAccountsController do
context
'and user has successfully completed the google oauth2 flow'
do
before
do
allow_next_instance_of
(
GoogleApi
::
CloudPlatform
::
Client
)
do
|
client
|
mock_service_account
=
Struct
.
new
(
:project_id
,
:unique_id
,
:email
).
new
(
123
,
456
,
'em@ai.l'
)
allow
(
client
).
to
receive
(
:validate_token
).
and_return
(
true
)
allow
(
client
).
to
receive
(
:list_projects
).
and_return
([{},
{},
{}])
allow
(
client
).
to
receive
(
:create_service_account
).
and_return
(
MockServiceAccount
.
new
(
123
,
456
)
)
allow
(
client
).
to
receive
(
:create_service_account
).
and_return
(
mock_service_account
)
allow
(
client
).
to
receive
(
:create_service_account_key
).
and_return
({})
allow
(
client
).
to
receive
(
:grant_service_account_roles
)
end
end
...
...
@@ -147,7 +145,8 @@ RSpec.describe Projects::GoogleCloud::ServiceAccountsController do
context
'but gitlab instance is not configured for google oauth2'
do
before
do
unconfigured_google_oauth2
=
MockGoogleOAuth2Credentials
.
new
(
''
,
''
)
unconfigured_google_oauth2
=
Struct
.
new
(
:app_id
,
:app_secret
)
.
new
(
''
,
''
)
allow
(
Gitlab
::
Auth
::
OAuth
::
Provider
).
to
receive
(
:config_for
)
.
with
(
'google_oauth2'
)
.
and_return
(
unconfigured_google_oauth2
)
...
...
spec/services/google_cloud/create_service_accounts_service_spec.rb
View file @
c03d5b8f
...
...
@@ -2,22 +2,26 @@
require
'spec_helper'
# Mock Types
MockGoogleOAuth2Credentials
=
Struct
.
new
(
:app_id
,
:app_secret
)
MockServiceAccount
=
Struct
.
new
(
:project_id
,
:unique_id
)
RSpec
.
describe
GoogleCloud
::
CreateServiceAccountsService
do
describe
'#execute'
do
before
do
mock_google_oauth2_creds
=
Struct
.
new
(
:app_id
,
:app_secret
)
.
new
(
'mock-app-id'
,
'mock-app-secret'
)
allow
(
Gitlab
::
Auth
::
OAuth
::
Provider
).
to
receive
(
:config_for
)
.
with
(
'google_oauth2'
)
.
and_return
(
MockGoogleOAuth2Credentials
.
new
(
'mock-app-id'
,
'mock-app-secret'
)
)
.
and_return
(
mock_google_oauth2_creds
)
allow_next_instance_of
(
GoogleApi
::
CloudPlatform
::
Client
)
do
|
client
|
mock_service_account
=
Struct
.
new
(
:project_id
,
:unique_id
,
:email
)
.
new
(
'mock-project-id'
,
'mock-unique-id'
,
'mock-email'
)
allow
(
client
).
to
receive
(
:create_service_account
)
.
and_return
(
MockServiceAccount
.
new
(
'mock-project-id'
,
'mock-unique-id'
))
.
and_return
(
mock_service_account
)
allow
(
client
).
to
receive
(
:create_service_account_key
)
.
and_return
(
'mock-key'
)
allow
(
client
)
.
to
receive
(
:grant_service_account_roles
)
end
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment