diff --git a/ee/lib/api/project_google_cloud_integration.rb b/ee/lib/api/project_google_cloud_integration.rb index 9a10ea28d2e0707e50eb4234d0d76642d3b65047..f5664cd186d3762ee10f6a41676f1398efb2cdbc 100644 --- a/ee/lib/api/project_google_cloud_integration.rb +++ b/ee/lib/api/project_google_cloud_integration.rb @@ -4,6 +4,8 @@ module API class ProjectGoogleCloudIntegration < ::API::Base feature_category :integrations + include GrapePathHelpers::NamedRouteMatcher + before { authorize_admin_project } before do unless ::Feature.enabled?(:google_cloud_integration_onboarding, user_project.root_namespace, type: :beta) @@ -11,14 +13,55 @@ class ProjectGoogleCloudIntegration < ::API::Base end end - desc 'Get shell script to create and configure Workload Identity Federation' do - detail 'This feature is experimental.' - end params do requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project' end resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do + namespace ':id/google_cloud/setup' do + desc 'Get shell script to setup an integration in Google Cloud' do + detail 'This feature is experimental.' + end + params do + optional :enable_google_cloud_artifact_registry, types: Boolean + optional :google_cloud_artifact_registry_project_id, types: String + at_least_one_of :enable_google_cloud_artifact_registry + end + get '/integrations.sh' do + env['api.format'] = :binary + content_type 'text/plain' + + wlif_integration = user_project.google_cloud_platform_workload_identity_federation_integration + unless user_project.google_cloud_workload_identity_federation_enabled? && wlif_integration&.activated? + render_api_error!('Workload Identity Federation is not configured', 400) + end + + template_path = File.join( + 'ee', 'lib', 'api', 'templates', 'google_cloud_integration_setup_integration.sh.erb') + template = ERB.new(File.read(template_path)) + + locals = { + google_cloud_artifact_registry_project_id: + declared_params[:google_cloud_artifact_registry_project_id], + identity_provider: wlif_integration.identity_pool_resource_name, + oidc_claim_grants: [ + { claim_name: 'guest_access', claim_value: 'true', iam_role: 'roles/artifactregistry.reader' }, + { claim_name: 'developer_access', claim_value: 'true', iam_role: 'roles/artifactregistry.writer' } + ], + api_integrations_url: + Gitlab::Utils.append_path( + Gitlab.config.gitlab.url, + api_v4_projects_integrations_path(id: params[:id]) + ) + } + + template.result_with_hash(locals) + end + end + namespace ':id/scripts/google_cloud/' do + desc 'Get shell script to create and configure Workload Identity Federation' do + detail 'This feature is experimental.' + end params do requires :google_cloud_project_id, types: String optional( diff --git a/ee/lib/api/templates/google_cloud_integration_setup_integration.sh.erb b/ee/lib/api/templates/google_cloud_integration_setup_integration.sh.erb new file mode 100644 index 0000000000000000000000000000000000000000..7837cc4a3bcc8c80427d2b52345c22eaeb220105 --- /dev/null +++ b/ee/lib/api/templates/google_cloud_integration_setup_integration.sh.erb @@ -0,0 +1,20 @@ +#!/bin/bash + +set -eu +set -o pipefail + +if [[ "${1:-}" == "--debug" ]]; then + set -x + shift +fi + +create_google_cloud_resources() { + <% oidc_claim_grants.each do |oidc_claim_grant| %> + PRINCIPAL="principalSet://<%= identity_provider %>/attribute.<%= oidc_claim_grant[:claim_name] %>/<%= oidc_claim_grant[:claim_value] %>" + + gcloud projects add-iam-policy-binding '<%= google_cloud_artifact_registry_project_id %>' \ + --member=$PRINCIPAL --role='<%= oidc_claim_grant[:iam_role] %>' + <% end %> +} + +create_google_cloud_resources diff --git a/ee/spec/requests/api/project_google_cloud_integration_spec.rb b/ee/spec/requests/api/project_google_cloud_integration_spec.rb index 61fa0cde88f6fc79c51eb5bce238405471ca3f32..7959a1c066e047020889ea2f9b3111e46d3cba05 100644 --- a/ee/spec/requests/api/project_google_cloud_integration_spec.rb +++ b/ee/spec/requests/api/project_google_cloud_integration_spec.rb @@ -19,7 +19,7 @@ expect(response).to have_gitlab_http_status(:ok) expect(response.content_type).to eql('text/plain') - expect(response.body).to include("gcloud config set project '#{google_cloud_project_id}'") + expect(response.body).to include("#!/bin/bash") end context 'when required param is missing' do @@ -80,4 +80,33 @@ it_behaves_like 'an endpoint generating a bash script for Google Cloud' end + + describe 'GET /projects/:id/google_cloud/setup/integrations.sh' do + let(:path) { "/projects/#{project.id}/google_cloud/setup/integrations.sh" } + let(:params) do + { enable_google_cloud_artifact_registry: true, + google_cloud_project_id: google_cloud_project_id } + end + + before do + stub_saas_features(google_cloud_support: true) + end + + context 'when Workload Identity Federation integration exists' do + before do + create(:google_cloud_platform_workload_identity_federation_integration, project: project) + end + + it_behaves_like 'an endpoint generating a bash script for Google Cloud' + end + + context 'when Workload Identity Federation integration does not exist' do + it 'returns error' do + get(api(path, owner), params: params) + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq('Workload Identity Federation is not configured') + end + end + end end