Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add resource permission checks #1711

Merged
merged 68 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
9fe0d74
add resource permission checks
petrkalos Nov 21, 2024
7d30dde
force enable all modules
petrkalos Nov 21, 2024
634fd54
test_id
petrkalos Nov 21, 2024
f8a3346
DRY
petrkalos Nov 21, 2024
a6556e2
add more tests
petrkalos Nov 25, 2024
c404769
query.filter.all mock returns list
petrkalos Nov 26, 2024
e0fc769
assert called_once only without expecting to raise as some resolvers …
petrkalos Nov 26, 2024
b9b5710
filter out networks
petrkalos Nov 26, 2024
cd622ed
ignore reason
petrkalos Nov 26, 2024
e370c16
fix check order
petrkalos Nov 26, 2024
3a1052a
fix find_environment_by_uri invocation
petrkalos Nov 27, 2024
ee6f5b0
remove get_dataset check
petrkalos Nov 27, 2024
909968c
fix test client to allow errors
petrkalos Nov 27, 2024
1a54afd
fix test client
petrkalos Nov 28, 2024
3d6574f
fix datasetlist
petrkalos Nov 29, 2024
9346e85
fix dataset view
petrkalos Nov 29, 2024
2a7e1c8
add pipeline exceptions for checkov
petrkalos Nov 29, 2024
f1ce67c
fix tests
petrkalos Nov 29, 2024
1c5ba9a
fix folder ui
petrkalos Nov 29, 2024
73f130b
use explicit tenant perms
petrkalos Nov 29, 2024
b0e91f1
make use of testdata
petrkalos Nov 29, 2024
47e27b8
generalise resource/tenant tests
petrkalos Nov 29, 2024
6257101
add test
petrkalos Dec 2, 2024
cf73e82
add postinit
petrkalos Dec 2, 2024
158ab76
rename to tenat
petrkalos Dec 2, 2024
a78c030
appsupport
petrkalos Dec 2, 2024
9695a3c
improve IgnoreReason
petrkalos Dec 2, 2024
da30357
dispatch all
petrkalos Dec 2, 2024
ba7c6f5
explicit tests
petrkalos Dec 2, 2024
b2f711a
mock tenant
petrkalos Dec 2, 2024
a8571f0
indirect check support using TargetType
petrkalos Dec 2, 2024
9fa02d0
indirect check support using TargetType
petrkalos Dec 2, 2024
b5bf12b
add checks
petrkalos Dec 2, 2024
c20891e
add checks
petrkalos Dec 2, 2024
49ed977
add checks
petrkalos Dec 2, 2024
8dda36a
merge tests
petrkalos Dec 2, 2024
b126c41
mock aws calls for speed
petrkalos Dec 2, 2024
535ff9d
add deleteDataPipelineEnvironment perm
petrkalos Dec 2, 2024
42811ad
workaround inf loop
petrkalos Dec 2, 2024
db4a2dd
call get_organization
petrkalos Dec 3, 2024
cee23fc
introduce dataset_service.py::find_dataset
petrkalos Dec 3, 2024
fab49ab
split into 2 tests
petrkalos Dec 3, 2024
d3ed453
add unchecked test and parametrize based on type
petrkalos Dec 3, 2024
642247d
fix semgrep
petrkalos Dec 3, 2024
6ce0337
simplify
petrkalos Dec 3, 2024
cf6fa8a
add tenant_admin checks
petrkalos Dec 3, 2024
936ecf5
remove inf loop workaround
petrkalos Dec 3, 2024
456792e
add tenant check
petrkalos Dec 4, 2024
f8ebf6a
add more checks
petrkalos Dec 4, 2024
18e82b8
add more checks
petrkalos Dec 4, 2024
c0352d5
rebase, fix feed perms and catalog ignore reasons
petrkalos Dec 4, 2024
661135e
delete_omics_run and test specific setup solution
petrkalos Dec 4, 2024
6c04274
nosemgrep
petrkalos Dec 4, 2024
2a888cf
glossary owner checks
petrkalos Dec 5, 2024
0337bb3
fix delete_pipeline_environment
petrkalos Dec 5, 2024
3185284
split config and implemantation
petrkalos Dec 5, 2024
a4e12b6
mock get_session for speed
petrkalos Dec 5, 2024
14ff9a3
fix dashboards tenant check and perm configs
petrkalos Dec 5, 2024
5a088b9
change Dataset_tables resource_ignore reason
petrkalos Dec 5, 2024
0116f3a
add metadata fields owner checks
petrkalos Dec 5, 2024
5f27c88
change reasons
petrkalos Dec 5, 2024
110fdae
add redshift connections checks
petrkalos Dec 5, 2024
c14111c
fix getSharedDatasetTables
petrkalos Dec 5, 2024
60812c8
fix mf ignore reasons
petrkalos Dec 5, 2024
333c8c9
fix assert resolver != None order
petrkalos Dec 6, 2024
01a942d
make use of inspect.unwrap to get the resolver code
petrkalos Dec 6, 2024
ce71471
rebase main and handle Dashsboard.restricted and upVote
petrkalos Dec 6, 2024
65d625a
fix upvote mocking
petrkalos Dec 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .checkov.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,25 @@
}
]
},
{
"file": "/checkov_pipeline_synth.json",
"findings": [
{
"resource": "AWS::IAM::Role.PipelineRoleDCFDBB91",
"check_ids": [
"CKV_AWS_107",
"CKV_AWS_108",
"CKV_AWS_111"
]
},
{
"resource": "AWS::S3::Bucket.thistableartifactsbucketDB1C8C64",
"check_ids": [
"CKV_AWS_18"
]
}
]
},
{
"file": "/frontend/docker/prod/Dockerfile",
"findings": [
Expand Down
5 changes: 2 additions & 3 deletions backend/dataall/core/environment/api/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from dataall.core.organizations.api.resolvers import Context, exceptions, get_organization_simplified


log = logging.getLogger()


Expand Down Expand Up @@ -223,6 +222,7 @@ def generate_environment_access_token(context, source, environmentUri: str = Non
def get_environment_stack(context: Context, source: Environment, **kwargs):
return StackService.resolve_parent_obj_stack(
targetUri=source.environmentUri,
targetType='environment',
environmentUri=source.environmentUri,
)

Expand Down Expand Up @@ -275,8 +275,7 @@ def resolve_environment(context, source, **kwargs):
"""Resolves the environment for a environmental resource"""
if not source:
return None
with context.engine.scoped_session() as session:
return EnvironmentService.get_environment_by_uri(session, source.environmentUri)
return EnvironmentService.find_environment_by_uri(uri=source.environmentUri)


def resolve_parameters(context, source: Environment, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ def resolve_organization_by_env(uri):
context = get_context()
with context.db_engine.scoped_session() as session:
env = EnvironmentRepository.get_environment_by_uri(session, uri)
return OrganizationRepository.find_organization_by_uri(session, env.organizationUri)
return OrganizationService.get_organization(uri=env.organizationUri)

@staticmethod
@ResourcePolicyService.has_resource_permission(GET_ORGANIZATION)
Expand Down
9 changes: 8 additions & 1 deletion backend/dataall/core/stacks/services/stack_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,16 @@ def map_target_type_to_log_config_path(**kwargs):

class StackService:
@staticmethod
def resolve_parent_obj_stack(targetUri: str, environmentUri: str):
def resolve_parent_obj_stack(targetUri: str, targetType: str, environmentUri: str):
context = get_context()
with context.db_engine.scoped_session() as session:
ResourcePolicyService.check_user_resource_permission(
session=session,
username=context.username,
groups=context.groups,
resource_uri=targetUri,
permission_name=TargetType.get_resource_read_permission_name(targetType),
)
env: Environment = EnvironmentRepository.get_environment_by_uri(session, environmentUri)
stack: Stack = StackRepository.find_stack_by_target_uri(session, target_uri=targetUri)
if not stack:
Expand Down
24 changes: 22 additions & 2 deletions backend/dataall/core/vpc/services/vpc_service.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import logging

from dataall.base.context import get_context
from dataall.base.db import exceptions
from dataall.base.db.exceptions import ResourceUnauthorized
from dataall.core.permissions.services.group_policy_service import GroupPolicyService
from dataall.core.environment.db.environment_repositories import EnvironmentRepository
from dataall.core.activity.db.activity_models import Activity
from dataall.core.permissions.services.resource_policy_service import ResourcePolicyService
from dataall.core.permissions.services.tenant_policy_service import TenantPolicyService
from dataall.core.vpc.db.vpc_repositories import VpcRepository
from dataall.core.vpc.db.vpc_models import Vpc
from dataall.core.permissions.services.network_permissions import NETWORK_ALL, DELETE_NETWORK
from dataall.core.permissions.services.network_permissions import NETWORK_ALL, DELETE_NETWORK, GET_NETWORK
from dataall.core.permissions.services.environment_permissions import CREATE_NETWORK
from dataall.core.permissions.services.tenant_permissions import MANAGE_ENVIRONMENTS

log = logging.getLogger(__name__)


def _session():
return get_context().db_engine.scoped_session()
Expand Down Expand Up @@ -90,4 +95,19 @@ def delete_network(uri):
@staticmethod
def get_environment_networks(environment_uri):
with _session() as session:
return VpcRepository.get_environment_networks(session=session, environment_uri=environment_uri)
nets = []
all_nets = VpcRepository.get_environment_networks(session=session, environment_uri=environment_uri)
petrkalos marked this conversation as resolved.
Show resolved Hide resolved
for net in all_nets:
try:
ResourcePolicyService.check_user_resource_permission(
session=session,
username=get_context().username,
groups=get_context().groups,
resource_uri=net.vpcUri,
permission_name=GET_NETWORK,
)
except ResourceUnauthorized as exc:
log.info(exc)
else:
nets += net
return nets
40 changes: 21 additions & 19 deletions backend/dataall/modules/catalog/services/glossaries_service.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from functools import wraps
import logging
from functools import wraps

from dataall.base.context import get_context
from dataall.base.db import exceptions
from dataall.core.permissions.services.tenant_policy_service import TenantPolicyService

from dataall.modules.catalog.db.glossary_repositories import GlossaryRepository
from dataall.modules.catalog.db.glossary_models import GlossaryNode
from dataall.modules.catalog.services.glossaries_permissions import MANAGE_GLOSSARIES
from dataall.modules.catalog.db.glossary_repositories import GlossaryRepository
from dataall.modules.catalog.indexers.registry import GlossaryRegistry
from dataall.modules.catalog.services.glossaries_permissions import MANAGE_GLOSSARIES

logger = logging.getLogger(__name__)

Expand All @@ -26,26 +25,29 @@ def wrapper(*args, **kwargs):
uri = kwargs.get('uri')
if not uri:
raise KeyError(f"{f.__name__} doesn't have parameter uri.")
context = get_context()
with context.db_engine.scoped_session() as session:
node = GlossaryRepository.get_node(session=session, uri=uri)
MAX_GLOSSARY_DEPTH = 10
depth = 0
while node.nodeType != 'G' and depth <= MAX_GLOSSARY_DEPTH:
node = GlossaryRepository.get_node(session=session, uri=node.parentUri)
depth += 1
if node and (node.admin in context.groups):
return f(*args, **kwargs)
else:
raise exceptions.UnauthorizedOperation(
action='GLOSSARY MUTATION',
message=f'User {context.username} is not the admin of the glossary {node.label}.',
)
GlossariesResourceAccess.check_owner(uri)
return f(*args, **kwargs)

return wrapper

return decorator

@staticmethod
def check_owner(uri):
context = get_context()
with context.db_engine.scoped_session() as session:
node = GlossaryRepository.get_node(session=session, uri=uri)
MAX_GLOSSARY_DEPTH = 10
depth = 0
while node.nodeType != 'G' and depth <= MAX_GLOSSARY_DEPTH:
node = GlossaryRepository.get_node(session=session, uri=node.parentUri)
depth += 1
if not node or node.admin not in context.groups:
raise exceptions.UnauthorizedOperation(
action='GLOSSARY MUTATION',
message=f'User {context.username} is not the admin of the glossary {node.label}.',
)


class GlossariesService:
@staticmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@
from dataall.base.aws.parameter_store import ParameterStoreManager
from dataall.base.aws.sts import SessionHelper
from dataall.base.context import get_context
from dataall.core.environment.services.environment_service import EnvironmentService
from dataall.core.permissions.db.tenant.tenant_policy_repositories import TenantPolicyRepository
from dataall.base.db.exceptions import UnauthorizedOperation, TenantUnauthorized, AWSResourceNotFound
from dataall.core.permissions.services.tenant_permissions import TENANT_ALL
from dataall.base.utils import Parameter
from dataall.core.environment.services.environment_service import EnvironmentService
from dataall.core.permissions.services.resource_policy_service import ResourcePolicyService
from dataall.core.permissions.services.tenant_policy_service import TenantPolicyService
from dataall.modules.dashboards.db.dashboard_repositories import DashboardRepository
from dataall.modules.dashboards.db.dashboard_models import Dashboard
from dataall.core.permissions.services.tenant_permissions import TENANT_ALL
from dataall.core.permissions.services.tenant_policy_service import TenantPolicyService, TenantPolicyValidationService
from dataall.modules.dashboards.aws.dashboard_quicksight_client import DashboardQuicksightClient
from dataall.modules.dashboards.db.dashboard_models import Dashboard
from dataall.modules.dashboards.db.dashboard_repositories import DashboardRepository
from dataall.modules.dashboards.services.dashboard_permissions import GET_DASHBOARD, CREATE_DASHBOARD, MANAGE_DASHBOARDS
from dataall.base.utils import Parameter


class DashboardQuicksightService:
Expand Down Expand Up @@ -128,7 +127,7 @@ def get_quicksight_reader_session(cls, dashboard_uri):
@staticmethod
def _check_user_must_be_admin():
context = get_context()
admin = TenantPolicyRepository.is_tenant_admin(context.groups)
admin = TenantPolicyValidationService.is_tenant_admin(context.groups)

if not admin:
raise TenantUnauthorized(
Expand Down
1 change: 1 addition & 0 deletions backend/dataall/modules/datapipelines/api/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,6 @@ def resolve_stack(context, source: DataPipeline, **kwargs):
return None
return StackService.resolve_parent_obj_stack(
targetUri=source.DataPipelineUri,
targetType='pipeline',
environmentUri=source.environmentUri,
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@

from dataall.base.aws.sts import SessionHelper
from dataall.base.context import get_context
from dataall.core.permissions.services.group_policy_service import GroupPolicyService
from dataall.base.db import exceptions
from dataall.core.environment.services.environment_service import EnvironmentService
from dataall.core.permissions.services.group_policy_service import GroupPolicyService
from dataall.core.permissions.services.resource_policy_service import ResourcePolicyService
from dataall.core.permissions.services.tenant_policy_service import TenantPolicyService
from dataall.core.stacks.db.keyvaluetag_repositories import KeyValueTagRepository
from dataall.core.stacks.db.stack_repositories import StackRepository
from dataall.core.stacks.services.stack_service import StackService
from dataall.core.tasks.db.task_models import Task
from dataall.core.tasks.service_handlers import Worker
from dataall.base.db import exceptions
from dataall.modules.datapipelines.db.datapipelines_models import DataPipeline, DataPipelineEnvironment
from dataall.modules.datapipelines.db.datapipelines_repositories import DatapipelinesRepository
from dataall.modules.datapipelines.services.datapipelines_permissions import (
Expand All @@ -25,7 +25,6 @@
UPDATE_PIPELINE,
)


logger = logging.getLogger(__name__)


Expand All @@ -34,6 +33,10 @@ def _session():


class DataPipelineService:
@staticmethod
def _get_pipeline_uri_from_env_uri(session, envPipelineUri):
return DatapipelinesRepository.get_pipeline_environment_by_uri(session, envPipelineUri).pipelineUri

@staticmethod
@TenantPolicyService.has_tenant_permission(MANAGE_PIPELINES)
@ResourcePolicyService.has_resource_permission(CREATE_PIPELINE)
Expand Down Expand Up @@ -255,6 +258,9 @@ def _delete_repository(target_uri, accountid, cdk_role_arn, region, repo_name):

@staticmethod
@TenantPolicyService.has_tenant_permission(MANAGE_PIPELINES)
petrkalos marked this conversation as resolved.
Show resolved Hide resolved
@ResourcePolicyService.has_resource_permission(
UPDATE_PIPELINE, param_name='envPipelineUri', parent_resource=_get_pipeline_uri_from_env_uri
)
def delete_pipeline_environment(envPipelineUri: str):
with _session() as session:
DatapipelinesRepository.delete_pipeline_environment(session=session, envPipelineUri=envPipelineUri)
Expand Down
4 changes: 2 additions & 2 deletions backend/dataall/modules/datasets_base/api/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ def get_dataset_organization(context, source: DatasetBase, **kwargs):
def get_dataset_environment(context, source: DatasetBase, **kwargs):
if not source:
return None
with context.engine.scoped_session() as session:
return EnvironmentService.get_environment_by_uri(session, source.environmentUri)
return EnvironmentService.find_environment_by_uri(uri=source.environmentUri)


def get_dataset_owners_group(context, source: DatasetBase, **kwargs):
Expand All @@ -79,5 +78,6 @@ def resolve_dataset_stack(context: Context, source: DatasetBase, **kwargs):
return None
return StackService.resolve_parent_obj_stack(
targetUri=source.datasetUri,
targetType='dataset',
environmentUri=source.environmentUri,
)
1 change: 1 addition & 0 deletions backend/dataall/modules/mlstudio/api/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def resolve_sagemaker_studio_user_stack(context: Context, source: SagemakerStudi
return None
return StackService.resolve_parent_obj_stack(
targetUri=source.sagemakerStudioUserUri,
targetType='mlstudio',
environmentUri=source.environmentUri,
)

Expand Down
1 change: 1 addition & 0 deletions backend/dataall/modules/notebooks/api/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def resolve_notebook_stack(context: Context, source: SagemakerNotebook, **kwargs
return None
return StackService.resolve_parent_obj_stack(
targetUri=source.notebookUri,
targetType='notebook',
environmentUri=source.environmentUri,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ def resolve_dataset_environment(
): # TODO- duplicated with S3 datasets - follow-up PR
if not source:
return None
with context.engine.scoped_session() as session:
return EnvironmentService.get_environment_by_uri(session, source.environmentUri)
return EnvironmentService.find_environment_by_uri(uri=source.environmentUri)


def resolve_dataset_owners_group(
Expand Down
4 changes: 2 additions & 2 deletions backend/dataall/modules/s3_datasets/api/dataset/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ def get_dataset_organization(context, source: S3Dataset, **kwargs):
def get_dataset_environment(context, source: S3Dataset, **kwargs):
if not source:
return None
with context.engine.scoped_session() as session:
return EnvironmentService.get_environment_by_uri(session, source.environmentUri)
return EnvironmentService.find_environment_by_uri(uri=source.environmentUri)


def get_dataset_owners_group(context, source: S3Dataset, **kwargs):
Expand Down Expand Up @@ -133,6 +132,7 @@ def resolve_dataset_stack(context: Context, source: S3Dataset, **kwargs):
return None
return StackService.resolve_parent_obj_stack(
targetUri=source.datasetUri,
targetType='dataset',
environmentUri=source.environmentUri,
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from dataall.base.api.context import Context
from dataall.modules.catalog.db.glossary_repositories import GlossaryRepository
from dataall.base.db.exceptions import RequiredParameter
from dataall.base.feature_toggle_checker import is_feature_enabled
from dataall.modules.catalog.db.glossary_repositories import GlossaryRepository
from dataall.modules.s3_datasets.db.dataset_models import DatasetStorageLocation
from dataall.modules.s3_datasets.services.dataset_location_service import DatasetLocationService
from dataall.modules.s3_datasets.db.dataset_models import DatasetStorageLocation, S3Dataset
from dataall.modules.s3_datasets.services.dataset_service import DatasetService


def _validate_input(input: dict):
Expand Down Expand Up @@ -46,9 +47,7 @@ def remove_storage_location(context, source, locationUri: str = None):
def resolve_dataset(context, source: DatasetStorageLocation, **kwargs):
if not source:
return None
with context.engine.scoped_session() as session:
d = session.query(S3Dataset).get(source.datasetUri)
return d
return DatasetService.find_dataset(uri=source.datasetUri)


def resolve_glossary_terms(context: Context, source: DatasetStorageLocation, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
DATASET_ALL,
DATASET_READ,
IMPORT_DATASET,
GET_DATASET,
dlpzx marked this conversation as resolved.
Show resolved Hide resolved
DATASET_TABLE_ALL,
)
from dataall.modules.datasets_base.services.dataset_list_permissions import LIST_ENVIRONMENT_DATASETS
Expand Down Expand Up @@ -242,6 +243,11 @@ def get_dataset(uri):
dataset.userRoleForDataset = DatasetRole.Admin.value
return dataset

@classmethod
@ResourcePolicyService.has_resource_permission(GET_DATASET)
def find_dataset(cls, uri):
return DatasetService.get_dataset(uri)

@staticmethod
@TenantPolicyService.has_tenant_permission(MANAGE_DATASETS)
@ResourcePolicyService.has_resource_permission(CREDENTIALS_DATASET)
Expand Down
3 changes: 1 addition & 2 deletions backend/dataall/modules/s3_datasets_shares/api/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from dataall.base.feature_toggle_checker import is_feature_enabled
from dataall.modules.s3_datasets_shares.services.s3_share_service import S3ShareService


log = logging.getLogger(__name__)


Expand Down Expand Up @@ -41,7 +40,7 @@ def validate_dataset_share_selector_input(data):


def list_shared_tables_by_env_dataset(context: Context, source, datasetUri: str, envUri: str):
return S3ShareService.list_shared_tables_by_env_dataset(datasetUri, envUri)
return S3ShareService.list_shared_tables_by_env_dataset(uri=envUri, dataset_uri=datasetUri)


@is_feature_enabled('modules.s3_datasets.features.aws_actions')
Expand Down
Loading
Loading