def CheckIamPermissions(project_id): """Check for needed IAM permissions and prompt to add if missing. Args: project_id: A string with the name of the project. """ project = projects_api.Get(project_id) service_account = 'serviceAccount:{0}@cloudbuild.gserviceaccount.com'.format( project.projectNumber) expected_permissions = { 'roles/compute.admin': service_account, 'roles/iam.serviceAccountActor': service_account } permissions = projects_api.GetIamPolicy(project_id) for binding in permissions.bindings: if expected_permissions.get(binding.role) in binding.members: del expected_permissions[binding.role] if expected_permissions: ep_table = [ '{0} {1}'.format(role, account) for role, account in expected_permissions.items() ] prompt_message = ( 'The following IAM permissions are needed for this operation:\n' '[{0}]\n'.format('\n'.join(ep_table))) console_io.PromptContinue( message=prompt_message, prompt_string='Would you like to add the permissions', throw_if_unattended=True, cancel_on_no=True) for role, account in expected_permissions.items(): log.info('Adding [{0}] to [{1}]'.format(account, role)) projects_api.AddIamPolicyBinding(project_id, account, role)
def _CheckIamPermissions(project_id, service_account_roles): """Check for needed IAM permissions and prompt to add if missing. Args: project_id: A string with the name of the project. service_account_roles: roles to be used by service account in addition to compute.admin. """ project = projects_api.Get(project_id) # If the user's project doesn't have cloudbuild enabled yet, then the service # account won't even exist. If so, then ask to enable it before continuing. # Also prompt them to enable Stackdriver Logging if they haven't yet. expected_services = ['cloudbuild.googleapis.com', 'logging.googleapis.com'] for service_name in expected_services: if not services_api.IsServiceEnabled(project.projectId, service_name): # TODO(b/112757283): Split this out into a separate library. prompt_message = ( 'The "{0}" service is not enabled for this project. ' 'It is required for this operation.\n').format(service_name) console_io.PromptContinue( prompt_message, 'Would you like to enable this service?', throw_if_unattended=True, cancel_on_no=True) operation = services_api.EnableServiceApiCall(project.projectId, service_name) # Wait for the operation to finish. services_util.ProcessOperationResult(operation, is_async=False) # Now that we're sure the service account exists, actually check permissions. service_account = 'serviceAccount:{0}@cloudbuild.gserviceaccount.com'.format( project.projectNumber) expected_permissions = {'roles/compute.admin': service_account} if service_account_roles: for role in service_account_roles: expected_permissions[role] = service_account permissions = projects_api.GetIamPolicy(project_id) for binding in permissions.bindings: if expected_permissions.get(binding.role) in binding.members: del expected_permissions[binding.role] if expected_permissions: ep_table = [ '{0} {1}'.format(role, account) for role, account in expected_permissions.items() ] prompt_message = ( 'The following IAM permissions are needed for this operation:\n' '[{0}]\n'.format('\n'.join(ep_table))) console_io.PromptContinue( message=prompt_message, prompt_string='Would you like to add the permissions', throw_if_unattended=True, cancel_on_no=True) for role, account in expected_permissions.items(): log.info('Adding [{0}] to [{1}]'.format(account, role)) projects_api.AddIamPolicyBinding(project_id, account, role)
def _CheckIamPermissions(project_id): """Check for needed IAM permissions and prompt to add if missing. Args: project_id: A string with the id of the project. """ project = projects_api.Get(project_id) # If the user's project doesn't have cloudbuild enabled yet, then the service # account won't even exist. If so, then ask to enable it before continuing. # Also prompt them to enable Stackdriver Logging if they haven't yet. expected_services = ['cloudbuild.googleapis.com', 'logging.googleapis.com'] for service_name in expected_services: if not services_api.IsServiceEnabled(project.projectId, service_name): # TODO(b/112757283): Split this out into a separate library. prompt_message = ( 'The "{0}" service is not enabled for this project. ' 'It is required for this operation.\n').format(service_name) console_io.PromptContinue( prompt_message, 'Would you like to enable this service?', throw_if_unattended=True, cancel_on_no=True) services_api.EnableService(project.projectId, service_name) # Now that we're sure the service account exists, actually check permissions. policy = projects_api.GetIamPolicy(project_id) build_account = 'serviceAccount:{0}@cloudbuild.gserviceaccount.com'.format( project.projectNumber) _VerifyRolesAndPromptIfMissing( project_id, build_account, _CurrentRolesForAccount(policy, build_account), { 'roles/compute.admin', 'roles/iam.serviceAccountUser', 'roles/iam.serviceAccountTokenCreator' }) # https://cloud.google.com/compute/docs/access/service-accounts#default_service_account compute_account = ( 'serviceAccount:{0}[email protected]'.format( project.projectNumber)) current_compute_account_roles = _CurrentRolesForAccount( policy, compute_account) # By default, the Compute Engine service account has the role `roles/editor` # applied to it, which is sufficient for import and export. If that's not # present, then request the minimal number of permissions. if 'roles/editor' not in current_compute_account_roles: try: _VerifyRolesAndPromptIfMissing( project_id, compute_account, current_compute_account_roles, {'roles/compute.storageAdmin', 'roles/storage.objectViewer'}) except apitools_exceptions.HttpForbiddenError: log.warning( 'Your account does not have permission to add roles to the ' 'default compute engine service account. If import fails, ' 'ensure "{0}" has the roles "{1}" and "{2}" before retrying.'.format( compute_account, 'roles/compute.storageAdmin', 'roles/storage.objectViewer'))
def CheckIamPermissions(project_id): """Check for needed IAM permissions and prompt to add if missing. Args: project_id: A string with the name of the project. """ project = projects_api.Get(project_id) # If the user's project doesn't have cloudbuild enabled yet, then the service # account won't even exist. If so, then ask to enable it before continuing. cloudbuild_service_name = 'cloudbuild.googleapis.com' if not services_api.IsServiceEnabled(project.projectId, cloudbuild_service_name): prompt_message = ('The Google Cloud Build service is not ' 'enabled for this project. It is required for this ' 'operation.\n') console_io.PromptContinue( prompt_message, 'Would you like to enable Container Builder?', throw_if_unattended=True, cancel_on_no=True) operation = services_api.EnableServiceApiCall(project.projectId, cloudbuild_service_name) # Wait for the operation to finish. services_util.ProcessOperationResult(operation, is_async=False) # Now that we're sure the service account exists, actually check permissions. service_account = 'serviceAccount:{0}@cloudbuild.gserviceaccount.com'.format( project.projectNumber) expected_permissions = { 'roles/compute.admin': service_account, 'roles/iam.serviceAccountActor': service_account } permissions = projects_api.GetIamPolicy(project_id) for binding in permissions.bindings: if expected_permissions.get(binding.role) in binding.members: del expected_permissions[binding.role] if expected_permissions: ep_table = [ '{0} {1}'.format(role, account) for role, account in expected_permissions.items() ] prompt_message = ( 'The following IAM permissions are needed for this operation:\n' '[{0}]\n'.format('\n'.join(ep_table))) console_io.PromptContinue( message=prompt_message, prompt_string='Would you like to add the permissions', throw_if_unattended=True, cancel_on_no=True) for role, account in expected_permissions.items(): log.info('Adding [{0}] to [{1}]'.format(account, role)) projects_api.AddIamPolicyBinding(project_id, account, role)
def _GetProjectRolesForServiceAccount(service_account_ref): """Returns the project roles the given service account is a member of.""" project_ref = projects_util.ParseProject(properties.VALUES.core.project.Get()) iam_policy = projects_api.GetIamPolicy(project_ref) roles = set() # iam_policy.bindings looks like: # list[<Binding # members=['serviceAccount:[email protected]',...] # role='roles/somerole'>...] for binding in iam_policy.bindings: if any( m.endswith(':' + service_account_ref.Name()) for m in binding.members): roles.add(binding.role) return roles
def GetIamPolicyWithAncestors(project_id): """Get IAM policy for given project and its ancestors. Args: project_id: project id Returns: IAM policy for given project and its ancestors """ iam_policies = [] ancestry = projects_api.GetAncestry(project_id) try: for resource in ancestry.ancestor: resource_type = resource.resourceId.type resource_id = resource.resourceId.id # this is the given project if resource_type == 'project': project_ref = ParseProject(project_id) iam_policies.append({ 'type': 'project', 'id': project_id, 'policy': projects_api.GetIamPolicy(project_ref) }) if resource_type == 'folder': iam_policies.append({ 'type': resource_type, 'id': resource_id, 'policy': folders.GetIamPolicy(resource_id) }) if resource_type == 'organization': iam_policies.append({ 'type': resource_type, 'id': resource_id, 'policy': organizations.Client().GetIamPolicy(resource_id), }) return iam_policies except HttpForbiddenError: raise exceptions.AncestorsIamPolicyAccessDeniedError( 'User is not permitted to access IAM policy for one or more of the' ' ancestors')
def Run(self, args): project_ref = command_lib_util.ParseProject(args.id) return projects_api.GetIamPolicy(project_ref)
def Run(self, args): client = apis.GetClientInstance('storagetransfer', 'v1') messages = apis.GetMessagesModule('storagetransfer', 'v1') if args.creds_file: expanded_file_path = os.path.abspath(os.path.expanduser(args.creds_file)) with files.FileReader(expanded_file_path) as file_reader: try: parsed_creds_file = json.load(file_reader) account_email = parsed_creds_file['client_email'] is_service_account = parsed_creds_file['type'] == 'service_account' except (ValueError, KeyError) as e: log.error(e) raise ValueError('Invalid creds file format.' ' Run command with "--help" flag for more details.') prefixed_account_email = _get_iam_prefixed_email( account_email, is_service_account) else: account_email = properties.VALUES.core.account.Get() is_service_account = creds.IsServiceAccountCredentials(creds_store.Load()) prefixed_account_email = _get_iam_prefixed_email(account_email, is_service_account) project_id = properties.VALUES.core.project.Get() parsed_project_id = projects_util.ParseProject(project_id) project_iam_policy = projects_api.GetIamPolicy(parsed_project_id) existing_user_roles = _get_existing_transfer_roles_for_account( project_iam_policy, prefixed_account_email, EXPECTED_USER_ROLES) log.status.Print('User {} has roles:\n{}'.format(account_email, list(existing_user_roles))) missing_user_roles = EXPECTED_USER_ROLES - existing_user_roles log.status.Print('Missing roles:\n{}'.format(list(missing_user_roles))) all_missing_role_tuples = [ (prefixed_account_email, role) for role in missing_user_roles ] log.status.Print('***') transfer_p4sa_email = client.googleServiceAccounts.Get( messages.StoragetransferGoogleServiceAccountsGetRequest( projectId=project_id)).accountEmail prefixed_transfer_p4sa_email = _get_iam_prefixed_email( transfer_p4sa_email, is_service_account=True) existing_p4sa_roles = _get_existing_transfer_roles_for_account( project_iam_policy, prefixed_transfer_p4sa_email, EXPECTED_P4SA_ROLES) log.status.Print('Google-managed transfer account {} has roles:\n{}'.format( transfer_p4sa_email, list(existing_p4sa_roles))) missing_p4sa_roles = EXPECTED_P4SA_ROLES - existing_p4sa_roles log.status.Print('Missing roles:\n{}'.format(list(missing_p4sa_roles))) all_missing_role_tuples += [ (prefixed_transfer_p4sa_email, role) for role in missing_p4sa_roles ] if args.add_missing or all_missing_role_tuples: log.status.Print('***') if args.add_missing: if all_missing_role_tuples: log.status.Print('Adding roles:\n{}'.format(all_missing_role_tuples)) projects_api.AddIamPolicyBindings(parsed_project_id, all_missing_role_tuples) log.status.Print('***') # Source: # https://cloud.google.com/iam/docs/granting-changing-revoking-access log.status.Print( 'Done. Permissions typically take seconds to propagate, but,' ' in some cases, it can take up to seven minutes.') else: log.status.Print('No missing roles to add.') else: log.status.Print('Rerun with --add-missing to add missing roles.')
def GetIamPolicyWithAncestors(project_id, include_deny, release_track): """Get IAM policy for given project and its ancestors. Args: project_id: project id include_deny: boolean that represents if we should show the deny policies in addition to the grants release_track: which release track, include deny is only supported for ALPHA or BETA Returns: IAM policy for given project and its ancestors """ iam_policies = [] ancestry = projects_api.GetAncestry(project_id) try: for resource in ancestry.ancestor: resource_type = resource.resourceId.type resource_id = resource.resourceId.id # this is the given project if resource_type == 'project': project_ref = ParseProject(project_id) iam_policies.append({ 'type': 'project', 'id': project_id, 'policy': projects_api.GetIamPolicy(project_ref) }) if include_deny: deny_policies = policies.ListDenyPolicies( project_id, 'project', release_track) for deny_policy in deny_policies: iam_policies.append({ 'type': 'project', 'id': project_id, 'policy': deny_policy }) if resource_type == 'folder': iam_policies.append({ 'type': resource_type, 'id': resource_id, 'policy': folders.GetIamPolicy(resource_id) }) if include_deny: deny_policies = policies.ListDenyPolicies( resource_id, 'folder', release_track) for deny_policy in deny_policies: iam_policies.append({ 'type': 'folder', 'id': resource_id, 'policy': deny_policy }) if resource_type == 'organization': iam_policies.append({ 'type': resource_type, 'id': resource_id, 'policy': organizations.Client().GetIamPolicy(resource_id), }) if include_deny: deny_policies = policies.ListDenyPolicies( resource_id, 'organization', release_track) for deny_policy in deny_policies: iam_policies.append({ 'type': 'organization', 'id': resource_id, 'policy': deny_policy }) return iam_policies except HttpForbiddenError: raise exceptions.AncestorsIamPolicyAccessDeniedError( 'User is not permitted to access IAM policy for one or more of the' ' ancestors')
def _CheckIamPermissions(project_id, cloudbuild_service_account_roles, compute_service_account_roles, custom_compute_service_account=''): """Check for needed IAM permissions and prompt to add if missing. Args: project_id: A string with the id of the project. cloudbuild_service_account_roles: A set of roles required for cloudbuild service account. compute_service_account_roles: A set of roles required for compute service account. custom_compute_service_account: Custom compute service account """ project = projects_api.Get(project_id) # If the user's project doesn't have cloudbuild enabled yet, then the service # account won't even exist. If so, then ask to enable it before continuing. # Also prompt them to enable Cloud Logging if they haven't yet. expected_services = ['cloudbuild.googleapis.com', 'logging.googleapis.com', 'compute.googleapis.com'] for service_name in expected_services: if not services_api.IsServiceEnabled(project.projectId, service_name): # TODO(b/112757283): Split this out into a separate library. prompt_message = ( 'The "{0}" service is not enabled for this project. ' 'It is required for this operation.\n').format(service_name) enable_service = console_io.PromptContinue( prompt_message, 'Would you like to enable this service?', throw_if_unattended=True) if enable_service: services_api.EnableService(project.projectId, service_name) else: log.warning( 'If import fails, manually enable {0} before retrying. For ' 'instructions on enabling services, see ' 'https://cloud.google.com/service-usage/docs/enable-disable.' .format(service_name)) build_account = 'serviceAccount:{0}@cloudbuild.gserviceaccount.com'.format( project.projectNumber) # https://cloud.google.com/compute/docs/access/service-accounts#default_service_account compute_account = ( 'serviceAccount:{0}[email protected]'.format( project.projectNumber)) if custom_compute_service_account: compute_account = 'serviceAccount:{0}'.format( custom_compute_service_account) # Now that we're sure the service account exists, actually check permissions. try: policy = projects_api.GetIamPolicy(project_id) except apitools_exceptions.HttpForbiddenError: log.warning( 'Your account does not have permission to check roles for the ' 'service account {0}. If import fails, ' 'ensure "{0}" has the roles "{1}" and "{2}" has the roles "{3}" before ' 'retrying.'.format(build_account, cloudbuild_service_account_roles, compute_account, compute_service_account_roles)) return _VerifyRolesAndPromptIfMissing(project_id, build_account, _CurrentRolesForAccount(policy, build_account), frozenset(cloudbuild_service_account_roles)) current_compute_account_roles = _CurrentRolesForAccount( policy, compute_account) # By default, the Compute Engine service account has the role `roles/editor` # applied to it, which is sufficient for import and export. If that's not # present, then request the minimal number of permissions. if ROLE_EDITOR not in current_compute_account_roles: _VerifyRolesAndPromptIfMissing( project_id, compute_account, current_compute_account_roles, compute_service_account_roles)