Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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'))
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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')
Ejemplo n.º 7
0
 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.')
Ejemplo n.º 9
0
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')
Ejemplo n.º 10
0
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)