Cleaned up object perms
This commit is contained in:
19
TODO.md
19
TODO.md
@@ -16,3 +16,22 @@ Revocation:
|
|||||||
- Keywarden removes key / cert from target server, or invalidates on Keywarden's side
|
- Keywarden removes key / cert from target server, or invalidates on Keywarden's side
|
||||||
- Keywarden removes object permissions
|
- Keywarden removes object permissions
|
||||||
- User cannot access server anymore
|
- User cannot access server anymore
|
||||||
|
|
||||||
|
|
||||||
|
Permissions:
|
||||||
|
|
||||||
|
Administrator:
|
||||||
|
- Everything
|
||||||
|
|
||||||
|
Auditor:
|
||||||
|
- Can exclusively view audit logs of servers they have access to via request.
|
||||||
|
|
||||||
|
User:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Access Requests:
|
||||||
|
|
||||||
|
- Can use Shell?
|
||||||
|
- Can view logs?
|
||||||
|
- Can have user account?
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ class AccessRequestAdmin(GuardedModelAdmin):
|
|||||||
"requester",
|
"requester",
|
||||||
"server",
|
"server",
|
||||||
"status",
|
"status",
|
||||||
|
"request_shell",
|
||||||
|
"request_logs",
|
||||||
|
"request_users",
|
||||||
"requested_at",
|
"requested_at",
|
||||||
"expires_at",
|
"expires_at",
|
||||||
"decided_by",
|
"decided_by",
|
||||||
@@ -50,6 +53,9 @@ class AccessRequestAdmin(GuardedModelAdmin):
|
|||||||
"server",
|
"server",
|
||||||
"status",
|
"status",
|
||||||
"reason",
|
"reason",
|
||||||
|
"request_shell",
|
||||||
|
"request_logs",
|
||||||
|
"request_users",
|
||||||
"expires_at",
|
"expires_at",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -64,6 +70,9 @@ class AccessRequestAdmin(GuardedModelAdmin):
|
|||||||
"server",
|
"server",
|
||||||
"status",
|
"status",
|
||||||
"reason",
|
"reason",
|
||||||
|
"request_shell",
|
||||||
|
"request_logs",
|
||||||
|
"request_users",
|
||||||
"expires_at",
|
"expires_at",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
37
app/apps/access/migrations/0002_remove_delete_permission.py
Normal file
37
app/apps/access/migrations/0002_remove_delete_permission.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
def remove_delete_accessrequest_perm(apps, schema_editor):
|
||||||
|
Permission = apps.get_model("auth", "Permission")
|
||||||
|
ContentType = apps.get_model("contenttypes", "ContentType")
|
||||||
|
try:
|
||||||
|
content_type = ContentType.objects.get(app_label="access", model="accessrequest")
|
||||||
|
except ContentType.DoesNotExist:
|
||||||
|
return
|
||||||
|
Permission.objects.filter(content_type=content_type, codename="delete_accessrequest").delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("access", "0001_initial"),
|
||||||
|
("auth", "__latest__"),
|
||||||
|
("contenttypes", "__latest__"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(remove_delete_accessrequest_perm, migrations.RunPython.noop),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name="accessrequest",
|
||||||
|
options={
|
||||||
|
"verbose_name": "Access request",
|
||||||
|
"verbose_name_plural": "Access requests",
|
||||||
|
"default_permissions": ("add", "view", "change"),
|
||||||
|
"indexes": [
|
||||||
|
models.Index(fields=["status", "requested_at"], name="acc_req_status_req_idx"),
|
||||||
|
models.Index(fields=["server", "status"], name="acc_req_server_status_idx"),
|
||||||
|
],
|
||||||
|
"ordering": ["-requested_at"],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
26
app/apps/access/migrations/0003_access_request_options.py
Normal file
26
app/apps/access/migrations/0003_access_request_options.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("access", "0002_remove_delete_permission"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="accessrequest",
|
||||||
|
name="request_shell",
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="accessrequest",
|
||||||
|
name="request_logs",
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="accessrequest",
|
||||||
|
name="request_users",
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -28,6 +28,9 @@ class AccessRequest(models.Model):
|
|||||||
max_length=16, choices=Status.choices, default=Status.PENDING, db_index=True
|
max_length=16, choices=Status.choices, default=Status.PENDING, db_index=True
|
||||||
)
|
)
|
||||||
reason = models.TextField(blank=True)
|
reason = models.TextField(blank=True)
|
||||||
|
request_shell = models.BooleanField(default=False)
|
||||||
|
request_logs = models.BooleanField(default=False)
|
||||||
|
request_users = models.BooleanField(default=False)
|
||||||
requested_at = models.DateTimeField(default=timezone.now, editable=False)
|
requested_at = models.DateTimeField(default=timezone.now, editable=False)
|
||||||
decided_at = models.DateTimeField(null=True, blank=True)
|
decided_at = models.DateTimeField(null=True, blank=True)
|
||||||
expires_at = models.DateTimeField(null=True, blank=True)
|
expires_at = models.DateTimeField(null=True, blank=True)
|
||||||
@@ -42,6 +45,7 @@ class AccessRequest(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Access request"
|
verbose_name = "Access request"
|
||||||
verbose_name_plural = "Access requests"
|
verbose_name_plural = "Access requests"
|
||||||
|
default_permissions = ("add", "view", "change")
|
||||||
indexes = [
|
indexes = [
|
||||||
models.Index(fields=["status", "requested_at"], name="acc_req_status_req_idx"),
|
models.Index(fields=["status", "requested_at"], name="acc_req_status_req_idx"),
|
||||||
models.Index(fields=["server", "status"], name="acc_req_server_status_idx"),
|
models.Index(fields=["server", "status"], name="acc_req_server_status_idx"),
|
||||||
|
|||||||
@@ -16,11 +16,7 @@ def assign_access_request_perms(sender, instance: AccessRequest, created: bool,
|
|||||||
return
|
return
|
||||||
if instance.requester_id:
|
if instance.requester_id:
|
||||||
user = instance.requester
|
user = instance.requester
|
||||||
for perm in (
|
for perm in ("access.view_accessrequest", "access.change_accessrequest"):
|
||||||
"access.view_accessrequest",
|
|
||||||
"access.change_accessrequest",
|
|
||||||
"access.delete_accessrequest",
|
|
||||||
):
|
|
||||||
assign_perm(perm, user, instance)
|
assign_perm(perm, user, instance)
|
||||||
assign_default_object_permissions(instance)
|
assign_default_object_permissions(instance)
|
||||||
sync_server_view_perm(instance)
|
sync_server_view_perm(instance)
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ class Command(BaseCommand):
|
|||||||
for perm in (
|
for perm in (
|
||||||
"access.view_accessrequest",
|
"access.view_accessrequest",
|
||||||
"access.change_accessrequest",
|
"access.change_accessrequest",
|
||||||
"access.delete_accessrequest",
|
|
||||||
):
|
):
|
||||||
assign_perm(perm, access_request.requester, access_request)
|
assign_perm(perm, access_request.requester, access_request)
|
||||||
assign_default_object_permissions(access_request)
|
assign_default_object_permissions(access_request)
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ from guardian.shortcuts import assign_perm
|
|||||||
from ninja.errors import HttpError
|
from ninja.errors import HttpError
|
||||||
|
|
||||||
ROLE_ADMIN = "administrator"
|
ROLE_ADMIN = "administrator"
|
||||||
ROLE_OPERATOR = "operator"
|
|
||||||
ROLE_AUDITOR = "auditor"
|
|
||||||
ROLE_USER = "user"
|
ROLE_USER = "user"
|
||||||
|
|
||||||
ROLE_ORDER = (ROLE_ADMIN, ROLE_OPERATOR, ROLE_AUDITOR, ROLE_USER)
|
ROLE_ORDER = (ROLE_ADMIN, ROLE_USER)
|
||||||
ROLE_ALL = ROLE_ORDER
|
ROLE_ALL = ROLE_ORDER
|
||||||
ROLE_ALIASES = {"admin": ROLE_ADMIN}
|
ROLE_ALIASES = {"admin": ROLE_ADMIN}
|
||||||
ROLE_INPUTS = tuple(sorted(set(ROLE_ORDER) | set(ROLE_ALIASES.keys())))
|
ROLE_INPUTS = tuple(sorted(set(ROLE_ORDER) | set(ROLE_ALIASES.keys())))
|
||||||
@@ -20,21 +18,7 @@ def _model_perms(app_label: str, model: str, actions: list[str]) -> list[str]:
|
|||||||
|
|
||||||
ROLE_PERMISSIONS = {
|
ROLE_PERMISSIONS = {
|
||||||
ROLE_ADMIN: [],
|
ROLE_ADMIN: [],
|
||||||
ROLE_OPERATOR: [
|
|
||||||
*_model_perms("servers", "server", ["view"]),
|
|
||||||
*_model_perms("access", "accessrequest", ["add", "view", "change", "delete"]),
|
|
||||||
*_model_perms("keys", "sshkey", ["add", "view", "change", "delete"]),
|
|
||||||
*_model_perms("telemetry", "telemetryevent", ["add", "view"]),
|
|
||||||
*_model_perms("audit", "auditlog", ["view"]),
|
|
||||||
*_model_perms("audit", "auditeventtype", ["view"]),
|
|
||||||
*_model_perms("auth", "user", ["add", "view"]),
|
|
||||||
],
|
|
||||||
ROLE_AUDITOR: [
|
|
||||||
*_model_perms("audit", "auditlog", ["view"]),
|
|
||||||
*_model_perms("audit", "auditeventtype", ["view"]),
|
|
||||||
],
|
|
||||||
ROLE_USER: [
|
ROLE_USER: [
|
||||||
*_model_perms("servers", "server", ["view"]),
|
|
||||||
*_model_perms("access", "accessrequest", ["add"]),
|
*_model_perms("access", "accessrequest", ["add"]),
|
||||||
*_model_perms("keys", "sshkey", ["add"]),
|
*_model_perms("keys", "sshkey", ["add"]),
|
||||||
],
|
],
|
||||||
@@ -132,9 +116,6 @@ def set_user_role(user, role: str) -> str:
|
|||||||
if canonical == ROLE_ADMIN:
|
if canonical == ROLE_ADMIN:
|
||||||
user.is_staff = True
|
user.is_staff = True
|
||||||
user.is_superuser = True
|
user.is_superuser = True
|
||||||
elif canonical in {ROLE_OPERATOR, ROLE_AUDITOR}:
|
|
||||||
user.is_staff = True
|
|
||||||
user.is_superuser = False
|
|
||||||
else:
|
else:
|
||||||
user.is_staff = False
|
user.is_staff = False
|
||||||
user.is_superuser = False
|
user.is_superuser = False
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ from apps.access.permissions import sync_server_view_perm
|
|||||||
class AccessRequestCreateIn(Schema):
|
class AccessRequestCreateIn(Schema):
|
||||||
server_id: int
|
server_id: int
|
||||||
reason: Optional[str] = None
|
reason: Optional[str] = None
|
||||||
|
request_shell: bool = False
|
||||||
|
request_logs: bool = False
|
||||||
|
request_users: bool = False
|
||||||
expires_at: Optional[datetime] = None
|
expires_at: Optional[datetime] = None
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +36,9 @@ class AccessRequestOut(Schema):
|
|||||||
server_id: int
|
server_id: int
|
||||||
status: str
|
status: str
|
||||||
reason: str
|
reason: str
|
||||||
|
request_shell: bool
|
||||||
|
request_logs: bool
|
||||||
|
request_users: bool
|
||||||
requested_at: str
|
requested_at: str
|
||||||
decided_at: Optional[str] = None
|
decided_at: Optional[str] = None
|
||||||
expires_at: Optional[str] = None
|
expires_at: Optional[str] = None
|
||||||
@@ -54,6 +60,9 @@ def _request_to_out(access_request: AccessRequest) -> AccessRequestOut:
|
|||||||
server_id=access_request.server_id,
|
server_id=access_request.server_id,
|
||||||
status=access_request.status,
|
status=access_request.status,
|
||||||
reason=access_request.reason or "",
|
reason=access_request.reason or "",
|
||||||
|
request_shell=access_request.request_shell,
|
||||||
|
request_logs=access_request.request_logs,
|
||||||
|
request_users=access_request.request_users,
|
||||||
requested_at=access_request.requested_at.isoformat(),
|
requested_at=access_request.requested_at.isoformat(),
|
||||||
decided_at=access_request.decided_at.isoformat() if access_request.decided_at else None,
|
decided_at=access_request.decided_at.isoformat() if access_request.decided_at else None,
|
||||||
expires_at=access_request.expires_at.isoformat() if access_request.expires_at else None,
|
expires_at=access_request.expires_at.isoformat() if access_request.expires_at else None,
|
||||||
@@ -123,6 +132,9 @@ def build_router() -> Router:
|
|||||||
requester=request.user,
|
requester=request.user,
|
||||||
server=server,
|
server=server,
|
||||||
reason=(payload.reason or "").strip(),
|
reason=(payload.reason or "").strip(),
|
||||||
|
request_shell=payload.request_shell,
|
||||||
|
request_logs=payload.request_logs,
|
||||||
|
request_users=payload.request_users,
|
||||||
)
|
)
|
||||||
if payload.expires_at:
|
if payload.expires_at:
|
||||||
access_request.expires_at = payload.expires_at
|
access_request.expires_at = payload.expires_at
|
||||||
|
|||||||
Reference in New Issue
Block a user