ansible / django-ansible-base

Apache License 2.0
9 stars 39 forks source link

More API shortcut requests for object details #423

Open AlanCoding opened 1 month ago

AlanCoding commented 1 month ago

The intent of this issue is to describe some utilities we would like to have for quick access to roles in app APIs. The main focus is giving some replacements for what is now accomplished by the track_relationship utility, which see https://github.com/ansible/django-ansible-base/issues/159, is intended to be removed.

Links from objects to role-holding users

Visit http://127.0.0.1:8000/api/v1/teams/1/

That has related links to, for example, team admins:

{
    "id": 1,
    "url": "/api/v1/teams/1/",
    "related": {
        "admins": "/api/v1/teams/1/admins/",
        "created_by": "/api/v1/users/3/",
        "modified_by": "/api/v1/users/3/",

Without the relationship tracking, we don't have a direct alternative to http://127.0.0.1:8000/api/v1/teams/1/admins/, for example. My alternative proposal would be to add http://127.0.0.1:8000/api/v1/role_user_assignments/?object_id=1&content_type__model=team to the related links. This could be separated by role, but I would rather not do that.

Alternatively, we could filter the user list by the team roles. Right now I don't think this is possible with the query filters, because it requires 2 conditions on a subquery. So this could only be accomplished by exposing new things in the API.

Serializing role members

By default, test_app includes all fields, so TeamSerializer has "admins", for example, added.

            "encryptioner": null,
            "team_parents": [],
            "users": [
                3
            ],
            "admins": []

This requires prefetching those relationships, but assuming this is done, the serialization is performant.

The proposed replacement here is, drafted for teams:

"role_user_assignments": {
    "Team Admin": [],
    "Team Member": [
        3
    ],
}

This can be relatively performant, since it just involves fetching all ObjectRoles with the associated users prefetched. You could have an analog for team assignments (replacing former "team_parents"). It would still be preferred to limit this to the detail view.

AlanCoding commented 1 month ago

Alternative:

    "summary_fields": {
        "object_roles": [
            {
                "role_definition": 1,
                "name": "Team Admin",
                "managed": true,
                "users": []
            },
            {
                "role_definition": 2,
                "name": "Team Member",
                "managed": true,
                "users": [3]
            },
        ],
       "more": {},
    },

This is a bit of a doozy, where we have 2 lists involved in the nested (in addition to dumping it in summary_fields), but this is very accurately what we have in the database. There is not a related object_roles manager in the database, but it would be theoretically possible to add it. Downside: we never wanted to surface object roles in the API, so there's not an "id" but a reference to the role definition id.

AlanCoding commented 1 month ago

Disclosure - I am leaning away from all implementations proposed here.

There is a broader sentiment that we want DAB RBAC in the permission-provider mode to behave more like an external policy server. Even if a client is interacting with a single server, philosophically, we would like these annotations to be provided by a separate request.

This is very similar to the user capabilities issue https://github.com/ansible/django-ansible-base/issues/154, with only the very minor difference that that is concerned with evaluations and this is concerned with assignments. It is sensible that these are both handled by the same mechanisms.

So the suggestion here is that we might add new DAB RBAC endpoints that basically does a "bulk" display of either assignments of permissions. The use cases we are developing:

If we always have the resource/permission provider serve this information, that also helps answer an issue @john-westcott-iv brought up, which is that JWT syncing of role assignments will not be up-to-date in all circumstances we care about. This is going to be a little complicated, but imagine that we are serving a list of inventories from AWX coupled with a resource/permission server co-deployed. We should not, can not, have AWX provide either the assignments or permissions for objects in the list, because it is not the source-of-truth for that information.