Пример #1
0
def service_account_has_external_access(service_account, google_project_id):
    """
    Checks if service account has external access or not.

    Args:
        service_account(str): service account
        google_project_id(str): google project id

    Returns:
        bool: whether or not the service account has external access
    """
    with GoogleCloudManager(google_project_id, use_default=False) as g_mgr:
        response = g_mgr.get_service_account_policy(service_account)
        if response.status_code != 200:
            logger.error(
                "Unable to get IAM policy for service account {}\n{}.".format(
                    service_account, response.json()
                )
            )
            # if there is an exception, assume it has external access
            return True

        json_obj = response.json()
        # In the case that a service account does not have any role, Google API
        # returns a json object without bindings key
        if "bindings" in json_obj:
            policy = GooglePolicy.from_json(json_obj)
            if policy.roles:
                return True
        if g_mgr.get_service_account_keys_info(service_account):
            return True
    return False
Пример #2
0
def is_valid_service_account_type(project_id, account_id):
    """
    Checks service account type against allowed service account types
    for service account registration

    Args:
        project_id(str): project identifier for project associated
            with service account
        account_id(str): account identifier to check valid type

    Returns:
        Bool: True if service acocunt type is allowed as defined
        in ALLOWED_SERVICE_ACCOUNT_TYPES
    """
    try:
        with GoogleCloudManager(project_id, use_default=False) as g_mgr:
            return (
                g_mgr.get_service_account_type(account_id)
                in ALLOWED_SERVICE_ACCOUNT_TYPES
            )
    except Exception as exc:
        logger.error(
            "validity of Google service account {} (google project: {}) type "
            "determined False due to error. Details: {}".format(
                account_id, project_id, exc
            )
        )
Пример #3
0
def create_google_logging_bucket(name, storage_class=None, google_project_id=None):
    cirrus_config.update(**config["CIRRUS_CFG"])

    # determine project where buckets are located if not provided, default
    # to configured project if checking creds doesn't work
    storage_creds_project_id = (
        google_project_id
        or _get_storage_project_id()
        or cirrus_config.GOOGLE_PROJECT_ID
    )

    manager = GoogleCloudManager(
        storage_creds_project_id, creds=cirrus_config.configs["GOOGLE_STORAGE_CREDS"]
    )
    with manager as g_mgr:
        g_mgr.create_or_update_bucket(
            name,
            storage_class=storage_class,
            public=False,
            requester_pays=False,
            for_logging=True,
        )

        logger.info(
            "Successfully created Google Bucket {} "
            "to store Access Logs.".format(name)
        )
Пример #4
0
    def delete(self, id_):
        """
        Delete a service account

        Args:
            id_ (str): Google service account email to delete
        """
        user_id = current_token["sub"]

        service_account_email = get_service_account_email(id_)
        registered_service_account = get_registered_service_account_from_email(
            service_account_email)
        if not registered_service_account:
            raise NotFound(
                "Could not find a registered service account from given email {}"
                .format(service_account_email))

        google_project_id = registered_service_account.google_project_id

        # check if user has permission to delete the service account
        with GoogleCloudManager(google_project_id) as gcm:
            authorized = is_user_member_of_google_project(user_id, gcm)

        if not authorized:
            return (
                'User "{}" does not have permission to delete the provided '
                'service account "{}".'.format(user_id, id_),
                403,
            )

        return self._delete(id_)
Пример #5
0
def _setup_google_bucket_access_group(
    db_session,
    google_bucket_name,
    bucket_db_id,
    google_project_id,
    storage_creds_project_id,
    privileges,
):

    access_group = _create_google_bucket_access_group(
        db_session, google_bucket_name, bucket_db_id, google_project_id, privileges
    )
    # use storage creds to update bucket iam
    storage_manager = GoogleCloudManager(
        storage_creds_project_id, creds=cirrus_config.configs["GOOGLE_STORAGE_CREDS"]
    )
    with storage_manager as g_mgr:
        g_mgr.give_group_access_to_bucket(
            access_group.email, google_bucket_name, access=privileges
        )

    logger.info(
        "Successfully set up Google Bucket Access Group {} "
        "for Google Bucket {}.".format(access_group.email, google_bucket_name)
    )

    return access_group
Пример #6
0
def delete_expired_service_accounts(DB):
    """
    Delete all expired service accounts.
    """
    cirrus_config.update(**config["CIRRUS_CFG"])

    driver = SQLAlchemyDriver(DB)
    with driver.session as session:
        current_time = int(time.time())
        records_to_delete = (
            session.query(ServiceAccountToGoogleBucketAccessGroup)
            .filter(ServiceAccountToGoogleBucketAccessGroup.expires < current_time)
            .all()
        )
        if len(records_to_delete):
            with GoogleCloudManager() as manager:
                for record in records_to_delete:
                    try:
                        manager.remove_member_from_group(
                            record.service_account.email, record.access_group.email
                        )
                        session.delete(record)
                        logger.info(
                            "Removed expired service account: {}".format(
                                record.service_account.email
                            )
                        )
                    except Exception as e:
                        logger.error(
                            "ERROR: Could not delete service account {}. Details: {}".format(
                                record.service_account.email, e
                            )
                        )

                session.commit()
Пример #7
0
def _remove_client_service_accounts(db_session, client):
    client_service_accounts = (
        db_session.query(GoogleServiceAccount)
        .filter(GoogleServiceAccount.client_id == client.client_id)
        .all()
    )

    if client_service_accounts:
        with GoogleCloudManager() as g_mgr:
            for service_account in client_service_accounts:
                logger.info(
                    "Deleting client {}'s service account: {}".format(
                        client.name, service_account.email
                    )
                )
                response = g_mgr.delete_service_account(service_account.email)
                if not response.get("error"):
                    db_session.delete(service_account)
                    db_session.commit()
                else:
                    logger.error("ERROR - from Google: {}".format(response))
                    logger.error(
                        "ERROR - Could not delete client service account: {}".format(
                            service_account.email
                        )
                    )
Пример #8
0
def _verify_google_group_member(session, access_group, member):
    """
    Delete if the member which is a google group is not in Fence.

    Args:
        session(Session): db session
        access_group(GoogleBucketAccessGroup): access group
        member(dict): group member info

    Returns:
        None

    """
    account_emails = [
        granted_group.proxy_group.email for granted_group in (
            session.query(GoogleProxyGroupToGoogleBucketAccessGroup).filter_by(
                access_group_id=access_group.id).all())
    ]

    if not any(
        [email for email in account_emails if email == member.get("email")]):
        try:
            with GoogleCloudManager() as manager:
                manager.remove_member_from_group(member.get("email"),
                                                 access_group.email)
        except Exception as e:
            print(
                "ERROR: Could not remove google group memeber {} from access group {}. Detail {}"
                .format(member.get("email"), access_group.email, e))
Пример #9
0
    def add_bucket_acl(self, bucket, username, access=None):
        """
        Tries to grant a user access to a bucket

        Args:
            bucket (str): Google Bucket Access Group email address. This should
                be the address of a Google Group that has read access on a
                single bucket. Access is controlled by adding members to this
                group.
            username (str): An email address of a member to add to the Google
                Bucket Access Group.
            access (str): IGNORED. For Google buckets, the Google Bucket Access
                Group is given access to the bucket through Google's
                IAM, so you cannot selectively choose permissions. Once you're
                added, you have the access that was set up for that group
                in Google IAM.
        """
        response = None
        with GoogleCloudManager(project_id=self.google_project_id) as g_mgr:
            try:
                response = g_mgr.add_member_to_group(
                    member_email=username, group_id=bucket
                )
            except Exception as exc:
                raise RequestError("Google API Error: {}".format(exc), code=400)

        return response
Пример #10
0
def _get_user_email_list_from_google_project_with_owner_role(project_id):
    """
    Get a list of emails associated to google project id

    Args:
        project_id(str): project id

    Returns:
        list(str): list of emails belong to the project

    """

    with GoogleCloudManager(project_id, use_default=False) as prj:
        members = prj.get_project_membership(project_id)
        users = [
            member
            for member in members
            if member.member_type == GooglePolicyMember.USER
        ]

        return list(
            {
                u.email_id
                for u in users
                for role in u.roles
                if role.name.upper() == "OWNER"
            }
        )
Пример #11
0
def is_user_member_of_all_google_projects(user_id,
                                          google_project_ids,
                                          db=None,
                                          membership=None):
    """
    Return whether or not the given user is a member of ALL of the provided
    Google project IDs.

    This will verify that either the user's email or their linked Google
    account email exists as a member in the projects.

    Args:
        user_id (int): User identifier
        google_project_ids (List(str)): List of unique google project ids
        db(str): db connection string
        membership (List(GooglePolicyMember) : pre-calculated list of members,
            Will make call to Google API if membership is None

    Returns:
        bool: whether or not the given user is a member of ALL of the provided
              Google project IDs
    """
    is_member = False
    for google_project_id in google_project_ids:
        with GoogleCloudManager(google_project_id) as google_cloud_manager:
            is_member = is_user_member_of_google_project(
                user_id, google_cloud_manager, db, membership)

            if not is_member:
                return False

    return is_member
Пример #12
0
def _create_proxy_group(user_id, username):
    """
    Create a proxy group for the given user

    Args:
        user_id (int): unique integer id for user
        username (str): unique name for user

    Return:
        userdatamodel.user.GoogleProxyGroup: the newly created proxy group
    """

    with GoogleCloudManager() as g_cloud:
        prefix = get_prefix_for_google_proxy_groups()
        new_proxy_group = g_cloud.create_proxy_group_for_user(user_id,
                                                              username,
                                                              prefix=prefix)

    proxy_group = GoogleProxyGroup(id=new_proxy_group["id"],
                                   email=new_proxy_group["email"])

    # link proxy group to user
    user = current_session.query(User).filter_by(id=user_id).first()
    user.google_proxy_group_id = proxy_group.id

    current_session.add(proxy_group)
    current_session.commit()

    logger.info("Created proxy group {} for user {} with id {}.".format(
        new_proxy_group["email"], username, user_id))

    return proxy_group
Пример #13
0
def _verify_google_service_account_member(session, access_group, member):
    """
    Delete if the member which is a service account is not in Fence.

    Args:
        session(session): db session
        access_group(GoogleBucketAccessGroup): access group
        members(dict): service account member info

    Returns:
        None

    """

    account_emails = [
        account.service_account.email for account in (
            session.query(ServiceAccountToGoogleBucketAccessGroup).filter_by(
                access_group_id=access_group.id).all())
    ]

    if not any(
        [email for email in account_emails if email == member.get("email")]):
        try:
            with GoogleCloudManager() as manager:
                manager.remove_member_from_group(member.get("email"),
                                                 access_group.email)
                print("Removed {} from {}, not found in fence but found "
                      "in Google Group.".format(member.get("email"),
                                                access_group.email))
        except Exception as e:
            print(
                "ERROR: Could not remove service account memeber {} from access group {}. Detail {}"
                .format(member.get("email"), access_group.email, e))
Пример #14
0
def _create_google_bucket_access_group(
    db_session, google_bucket_name, bucket_db_id, google_project_id, privileges
):
    access_group = None
    prefix = config.get("GOOGLE_GROUP_PREFIX", "")
    # use default creds for creating group and iam policies
    with GoogleCloudManager(google_project_id) as g_mgr:
        # create bucket access group
        result = g_mgr.create_group(
            name=prefix
            + "_"
            + google_bucket_name
            + "_"
            + "_".join(privileges)
            + "_gbag"
        )
        group_email = result["email"]

        # add bucket group to db
        access_group = (
            db_session.query(GoogleBucketAccessGroup)
            .filter_by(bucket_id=bucket_db_id, email=group_email)
            .first()
        )
        if not access_group:
            access_group = GoogleBucketAccessGroup(
                bucket_id=bucket_db_id, email=group_email, privileges=privileges
            )
            db_session.add(access_group)
            db_session.commit()

    return access_group
Пример #15
0
def is_user_member_of_all_google_projects(
    user_id, google_project_ids, db=None, membership=None
):
    """
    Return whether or not the given user is a member of ALL of the provided
    Google project IDs.

    This will verify that either the user's email or their linked Google
    account email exists as a member in the projects.

    Args:
        user_id (int): User identifier
        google_project_ids (List(str)): List of unique google project ids
        db(str): db connection string
        membership (List(GooglePolicyMember) : pre-calculated list of members,
            Will make call to Google API if membership is None

    Returns:
        bool: whether or not the given user is a member of ALL of the provided
              Google project IDs
    """
    session = get_db_session(db)
    user = session.query(User).filter_by(id=user_id).first()
    if not user:
        logger.error(
            "Could not determine if user (id: {}) is from projects:"
            " {} due to error. User does not exist...".format(
                user_id, google_project_ids
            )
        )
        return False

    linked_google_account = (
        session.query(UserGoogleAccount)
        .filter(UserGoogleAccount.user_id == user_id)
        .first()
    )

    try:
        for google_project_id in google_project_ids:
            with GoogleCloudManager(google_project_id, use_default=False) as g_mgr:
                members = membership or g_mgr.get_project_membership()
                member_emails = [member.email_id.lower() for member in members]
                # first check if user.email is in project, then linked account
                if not (user.email and user.email in member_emails):
                    if not (
                        linked_google_account
                        and linked_google_account.email in member_emails
                    ):
                        # no user email is in project
                        return False
    except Exception as exc:
        logger.error(
            "Could not determine if user (id: {}) is from projects:"
            " {} due to error. Details: {}".format(user_id, google_project_ids, exc)
        )
        return False

    return True
Пример #16
0
    def _unlink_google_account():
        user_id = current_token["sub"]

        g_account = (
            current_session.query(UserGoogleAccount)
            .filter(UserGoogleAccount.user_id == user_id)
            .first()
        )

        if not g_account:
            error_message = {
                "error": "g_acnt_link_error",
                "error_description": (
                    "Couldn't unlink account for user, no linked Google "
                    "account found."
                ),
            }
            _clear_google_link_info_from_session()
            return error_message, 404

        g_account_access = (
            current_session.query(UserGoogleAccountToProxyGroup)
            .filter(
                UserGoogleAccountToProxyGroup.user_google_account_id == g_account.id
            )
            .first()
        )

        if g_account_access:
            try:
                with GoogleCloudManager() as g_manager:
                    g_manager.remove_member_from_group(
                        member_email=g_account.email,
                        group_id=g_account_access.proxy_group_id,
                    )
            except Exception as exc:
                error_message = {
                    "error": "g_acnt_access_error",
                    "error_description": (
                        "Couldn't remove account from user's proxy group, "
                        "Google API failure. Exception: {}".format(exc)
                    ),
                }
                _clear_google_link_info_from_session()
                return error_message, 400

            current_session.delete(g_account_access)
            current_session.commit()

        current_session.delete(g_account)
        current_session.commit()

        # clear session and cookies so access token and session don't have
        # outdated linkage info
        flask.session.clear()
        response = flask.make_response("", 200)
        clear_cookies(response)

        return response
Пример #17
0
def get_test_cloud_manager():
    project_id = "test_project"
    manager = GoogleCloudManager(project_id)
    manager._authed_session = MagicMock()
    manager._admin_service = MagicMock()
    manager._storage_client = MagicMock()
    manager.credentials = MagicMock()
    return manager
Пример #18
0
def email_users_without_access(
    db, auth_ids, user_emails, check_linking, google_project_id
):

    """
    Build list of users without acess and send emails.

    Args:
        db (str): database instance
        auth_ids (list(str)): list of project auth_ids to check access against
        user_emails (list(str)): list of emails to check access for
        check_linking (bool): flag to check for linked google email
    Returns:
        None
    """
    users_without_access = _get_users_without_access(
        db, auth_ids, user_emails, check_linking
    )

    if len(users_without_access) == len(user_emails):
        logger.warning(
            "No user has proper access to provided projects. Contact project administrator. No emails will be sent"
        )
        return
    elif len(users_without_access) > 0:
        logger.info(
            "Some user(s) do not have proper access to provided projects. Email(s) will be sent to user(s)."
        )

        with GoogleCloudManager(google_project_id) as gcm:
            members = gcm.get_project_membership(google_project_id)
            users = []
            for member in members:
                if member.member_type == GooglePolicyMember.USER:
                    users.append(member.email_id)

        for user, projects in users_without_access.iteritems():
            logger.info(
                "{} does not have access to the following datasets: {}.".format(
                    user, ",".join(projects)
                )
            )
            if user in users:
                logger.info(
                    "{} is a member of google project: {}. User will be emailed.".format(
                        user, google_project_id
                    )
                )
                email_user_without_access(user, projects, google_project_id)
            else:
                logger.info(
                    "{} is NOT a member of google project: {}. User will NOT be emailed.".format(
                        user, google_project_id
                    )
                )
    else:
        logger.info("All users have proper access to provided projects.")
Пример #19
0
def delete_keypair(provider, access_key):
    """
    .. http:get: /<provider>/(string: access_key)
    Delete a keypair for user

    :param access_key: existing access key belongs to this user

    For Google:
        The access_key can be constructed from
        data in the response from creating the key.

        access_key should be a string:
        `projects/{PROJECT_ID}/serviceAccounts/{ACCOUNT}/keys/{KEY}`
        which can be constructed with the information from POST/PUT `credentials/google`
        Use `project_id` for {PROJECT_ID},
            `client_email` for {ACCOUNT},
            `private_key_id` for {KEY}

    :statuscode 201 Success
    :statuscode 403 Forbidden to delete access key
    :statuscode 404 Access key doesn't exist

    """
    if provider == 'cdis':
        jti = access_key
        with flask.current_app.db.session as session:
            api_key = (
                session
                .query(UserRefreshToken)
                .filter_by(jti=jti)
                .first()
            )
        if not api_key:
            flask.abort(400, 'token not found with JTI {}'.format(jti))
        blacklist_token(jti, api_key.expires)
    elif provider == 'google':
        with GoogleCloudManager() as g_cloud:
            service_account = _get_google_service_account_for_client(g_cloud)

            if service_account:
                keys_for_account = (
                    g_cloud.get_service_account_keys_info(service_account.google_unique_id)
                )

                # Only delete the requested key if is owned by current client's SA
                if access_key in [key['name'].split('/')[-1] for key in keys_for_account]:
                    g_cloud.delete_service_account_key(service_account.google_unique_id,
                                                       access_key)
                else:
                    flask.abort(400, 'Could not delete key ' + access_key + '. Not found for current user.')
            else:
                flask.abort(400, 'Could not find service account for current user.')
    else:
        flask.current_app.storage_manager.delete_keypair(provider, flask.g.user, access_key)

    return '', 204
Пример #20
0
def remove_expired_google_service_account_keys(db):
    import fence.settings

    cirrus_config.update(**fence.settings.CIRRUS_CFG)

    db = SQLAlchemyDriver(db)
    with db.session as current_session:
        client_service_accounts = current_session.query(
            GoogleServiceAccount,
            Client).filter(GoogleServiceAccount.client_id == Client.client_id)

        current_time = int(time.time())
        print("Current time: {}\n".format(current_time))

        expired_sa_keys_for_users = current_session.query(
            GoogleServiceAccountKey).filter(
                GoogleServiceAccountKey.expires <= current_time)

        # handle service accounts with default max expiration
        for service_account, client in client_service_accounts:
            with GoogleCloudManager() as g_mgr:
                g_mgr.handle_expired_service_account_keys(
                    service_account.google_unique_id)

            # handle service accounts with custom expiration
            for expired_user_key in expired_sa_keys_for_users:
                sa = (current_session.query(GoogleServiceAccount).filter(
                    GoogleServiceAccount.id ==
                    expired_user_key.service_account_id).first())
                response = g_mgr.delete_service_account_key(
                    account=sa.google_unique_id,
                    key_name=expired_user_key.key_id)
                response_error_code = response.get("error", {}).get("code")

                if not response_error_code:
                    current_session.delete(expired_user_key)
                    print(
                        "INFO: Removed expired service account key {} "
                        "for service account {} (owned by user with id {}).\n".
                        format(expired_user_key.key_id, sa.email, sa.user_id))
                elif response_error_code == 404:
                    print(
                        "INFO: Service account key {} for service account {} "
                        "(owned by user with id {}) does not exist in Google. "
                        "Removing from database...\n".format(
                            expired_user_key.key_id, sa.email, sa.user_id))
                    current_session.delete(expired_user_key)
                else:
                    print("ERROR: Google returned an error when attempting to "
                          "remove service account key {} "
                          "for service account {} (owned by user with id {}). "
                          "Error:\n{}\n".format(expired_user_key.key_id,
                                                sa.email, sa.user_id,
                                                response))
Пример #21
0
def _is_valid_service_account(sa_email, google_project_id):
    """
    Validate the given registered service account and remove if invalid.

    Args:
        sa_email(str): service account email
        google_project_id(str): google project id
    """
    with GoogleCloudManager(google_project_id) as gcm:
        google_project_number = get_google_project_number(google_project_id, gcm)

    has_access = bool(google_project_number)
    if not has_access:
        # if our monitor doesn't have access at this point, just don't return any
        # information. When the project check runs, it will catch the monitor missing
        # error and add it to the removal reasons
        raise Unauthorized(
            "Google Monitoring SA doesn't have access to Google Project: {}".format(
                google_project_id
            )
        )

    try:
        sa_validity = GoogleServiceAccountValidity(
            sa_email, google_project_id, google_project_number=google_project_number
        )

        if is_google_managed_service_account(sa_email):
            sa_validity.check_validity(
                early_return=True,
                check_type=True,
                check_policy_accessible=True,
                check_external_access=False,
            )
        else:
            sa_validity.check_validity(
                early_return=True,
                check_type=True,
                check_policy_accessible=True,
                check_external_access=True,
            )

    except Exception as exc:
        # any issues, assume invalid
        # TODO not sure if this is the right way to handle this...
        logger.warning(
            "Service Account {} determined invalid due to unhandled exception: {}. "
            "Assuming service account is invalid.".format(sa_email, str(exc))
        )
        traceback.print_exc()
        sa_validity = None

    return sa_validity
Пример #22
0
def remove_expired_google_accounts_from_proxy_groups(db):
    cirrus_config.update(**config["CIRRUS_CFG"])

    db = SQLAlchemyDriver(db)
    with db.session as current_session:
        current_time = int(time.time())
        logger.info("Current time: {}".format(current_time))

        expired_accounts = current_session.query(UserGoogleAccountToProxyGroup).filter(
            UserGoogleAccountToProxyGroup.expires <= current_time
        )

        with GoogleCloudManager() as g_mgr:
            for expired_account_access in expired_accounts:
                g_account = (
                    current_session.query(UserGoogleAccount)
                    .filter(
                        UserGoogleAccount.id
                        == expired_account_access.user_google_account_id
                    )
                    .first()
                )
                try:
                    response = g_mgr.remove_member_from_group(
                        member_email=g_account.email,
                        group_id=expired_account_access.proxy_group_id,
                    )
                    response_error_code = response.get("error", {}).get("code")

                    if not response_error_code:
                        current_session.delete(expired_account_access)
                        logger.info(
                            "INFO: Removed {} from proxy group with id {}.\n".format(
                                g_account.email, expired_account_access.proxy_group_id
                            )
                        )
                    else:
                        logger.error(
                            "ERROR: Google returned an error when attempting to "
                            "remove member {} from proxy group {}. Error:\n{}\n".format(
                                g_account.email,
                                expired_account_access.proxy_group_id,
                                response,
                            )
                        )
                except Exception as exc:
                    logger.error(
                        "ERROR: Google returned an error when attempting to "
                        "remove member {} from proxy group {}. Error:\n{}\n".format(
                            g_account.email, expired_account_access.proxy_group_id, exc
                        )
                    )
Пример #23
0
 def delete(self, bucket, file_id):
     try:
         with GoogleCloudManager(creds='a') as gcm:
             gcm.delete_data_file(bucket, file_id)
         return ("", 204)
     except Exception as e:
         logger.error(e)
         try:
             status_code = e.resp.status
         except Exception as exc:
             logger.error(exc)
             status_code = 500
         return ("Failed to delete data file.", status_code)
Пример #24
0
def add_user_service_account_to_google(
    session, to_add_project_ids, google_project_id, service_account
):
    """
    Add service account to Google access groups

    Args:
        session(current_session): db session
        to_add_project_ids (List(id)): list of project ids
        google_project_id (str): google project id
        service_account (UserServiceAccount): user service account

    """
    logger.debug(
        "attempting to add {} to groups for projects: {}".format(
            service_account, to_add_project_ids
        )
    )
    for project_id in to_add_project_ids:
        access_groups = _get_google_access_groups(session, project_id)
        logger.debug(
            "google group(s) for project {}: {}".format(project_id, access_groups)
        )
        for access_group in access_groups:
            try:
                # TODO: Need to remove try/catch after major refactor
                with GoogleCloudManager(
                    google_project_id, use_default=False
                ) as g_manager:
                    response = g_manager.add_member_to_group(
                        member_email=service_account.email, group_id=access_group.email
                    )
                    if response.get("email", None):
                        logger.debug(
                            "Successfully add member {} to Google group {}.".format(
                                service_account.email, access_group.email
                            )
                        )
                    else:
                        raise GoogleAPIError(
                            "Can not add {} to Google group {}".format(
                                service_account.email, access_group.email
                            )
                        )

            except Exception as exc:
                raise GoogleAPIError(
                    "Can not add {} to Google group {}. Detail {}".format(
                        service_account.email, access_group.email, exc
                    )
                )
Пример #25
0
 def delete(self, bucket, file_id):
     try:
         with GoogleCloudManager(
                 creds=config["CIRRUS_CFG"]["GOOGLE_STORAGE_CREDS"]) as gcm:
             gcm.delete_data_file(bucket, file_id)
         return ("", 204)
     except Exception as e:
         logger.error(e)
         try:
             status_code = e.resp.status
         except Exception as exc:
             logger.error(exc)
             status_code = 500
         return ("Failed to delete data file.", status_code)
Пример #26
0
def create_google_access_key(client_id, user_id, username, proxy_group_id):
    """
    Return an access key for current user and client.

    NOTE: This will create a service account for the client if one does
    not exist.

    Returns:

        JSON key in Google Credentials File format:

        .. code-block:: JavaScript

            {
                "type": "service_account",
                "project_id": "project-id",
                "private_key_id": "some_number",
                "private_key": "-----BEGIN PRIVATE KEY-----\n....
                =\n-----END PRIVATE KEY-----\n",
                "client_email": "<api-name>[email protected]",
                "client_id": "...",
                "auth_uri": "https://accounts.google.com/o/oauth2/auth",
                "token_uri": "https://accounts.google.com/o/oauth2/token",
                "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
                "client_x509_cert_url": "https://www.googleapis.com/...<api-name>api%40project-id.iam.gserviceaccount.com"
            }
    """
    key = {}
    service_account = get_or_create_service_account(
        client_id=client_id,
        user_id=user_id,
        username=username,
        proxy_group_id=proxy_group_id,
    )

    with GoogleCloudManager() as g_cloud:
        key = g_cloud.get_access_key(service_account.email)

    logger.info(
        "Created key with id {} for service account {} in user {}'s "
        "proxy group {} (user's id: {}).".format(
            key.get("private_key_id"),
            service_account.email,
            username,
            proxy_group_id,
            user_id,
        )
    )

    return key, service_account
Пример #27
0
def get_google_project_membership(project_id):
    """
    Returns GCM get_project_membership() result, which is a list of all
    members on the projects IAM

    Args:
        project_id(str): unique id for project

    Returns
        List(GooglePolicyMember): list of members on project's IAM
    """

    with GoogleCloudManager(project_id, use_default=False) as prj:
        return prj.get_project_membership(project_id)
Пример #28
0
    def get(self):
        """
        List access keys for user

        **Example:**
        .. code-block:: http

               POST /credentials/apis/ HTTP/1.1
               Content-Type: application/json
               Accept: application/json

        Info from Google API /serviceAccounts/<account>/keys endpoint
        TODO: In the future we should probably add in our expiration time, when
              we start monitoring and deleting after x amount of time

        .. code-block:: JavaScript

            {
                "access_keys":
                [
                    {
                        "keyAlgorithm": enum(ServiceAccountKeyAlgorithm),
                        "validBeforeTime": string,
                        "name": string,
                        "validAfterTime": string,
                    },
                    ...
                ]
            }

        """
        client_id = current_token.get("azp") or None
        user_id = current_token["sub"]
        username = current_token.get("context", {}).get("user", {}).get("name")

        with GoogleCloudManager() as g_cloud_manager:
            proxy_group_id = get_or_create_proxy_group_id()
            service_account = get_or_create_service_account(
                client_id=client_id,
                user_id=user_id,
                username=username,
                proxy_group_id=proxy_group_id,
            )

            keys = g_cloud_manager.get_service_account_keys_info(
                service_account.google_unique_id)
            result = {"access_keys": keys}

        return flask.jsonify(result)
Пример #29
0
def get_google_project_valid_users_and_service_accounts(project_id, membership=None):
    """
    Gets google project members of type
    USER or SERVICE_ACCOUNT and raises an error if it finds a member
    that isn't one of those types.

    Args:
        project_id (str): Google project ID
        membership (List(GooglePolicyMember): pre-calculated list of members,
            Will make call to Google API if membership is None

    Return:
        List[cirrus.google_cloud.iam.GooglePolicyMember]: Members on the
            google project

    Raises:
        NotSupported: Member is invalid type
    """
    try:
        with GoogleCloudManager(project_id, use_default=False) as prj:
            members = membership or prj.get_project_membership(project_id)
            for member in members:
                if not (
                    member.member_type == GooglePolicyMember.SERVICE_ACCOUNT
                    or member.member_type == GooglePolicyMember.USER
                ):
                    raise NotSupported(
                        "Member {} has invalid type: {}".format(
                            member.email_id, member.member_type
                        )
                    )
            users = [
                member
                for member in members
                if member.member_type == GooglePolicyMember.USER
            ]
            service_accounts = [
                member
                for member in members
                if member.member_type == GooglePolicyMember.SERVICE_ACCOUNT
            ]
            return users, service_accounts
    except Exception as exc:
        logger.error(
            "validity of Google Project (id: {}) members "
            "could not complete. Details: {}".format(project_id, exc)
        )

        raise
Пример #30
0
    def delete(self):
        """
        .. http:get: /google/
        Delete keypair(s) for user
        ?all=true must be specified

        True values are y, yes, t, true, on and 1; false values are n, no, f, false, off and 0

        :statuscode 204 Success
        :statuscode 403 Forbidden to delete access key
        :statuscode 405 Method Not Allowed if ?all=true is not included
        """
        user_id = current_token["sub"]

        try:
            all_arg = strtobool(flask.request.args.get("all", "false").lower())
        except ValueError:
            all_arg = False

        if not all_arg:
            flask.abort(
                405,
                "Please include ?all=true to confirm deletion of ALL Google Service account keys.",
            )

        with GoogleCloudManager() as g_cloud:
            client_id = current_token.get("azp") or None
            service_account = get_service_account(client_id, user_id)

            if service_account:
                keys_for_account = g_cloud.get_service_account_keys_info(
                    service_account.email)

                # Only delete the key if is owned by current client's SA
                all_client_keys = [
                    key["name"].split("/")[-1] for key in keys_for_account
                ]

                for key in all_client_keys:
                    _delete_service_account_key(g_cloud, service_account.email,
                                                key)
            else:
                flask.abort(
                    404, "Could not find service account for current user.")

        return "", 204