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

922 - Replace IAM inline policies by configurable Managed Policies for folder and bucket sharing #1068

Merged
merged 61 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
5d876ec
added 'create_managed_policy' method to base IAM class
Jan 30, 2024
43d0557
Merge branch 'mda-main' into 922-consumer-ima-role
Feb 8, 2024
d7145ff
generate empty policies, when the cosumption role is added
Feb 9, 2024
7ecb809
detach|delete|update managed policies for consumption roles
Feb 9, 2024
c33a547
add permissions to pivot role to create and attach managed policies
Feb 12, 2024
08df323
fatal typo. Corrected: uri -> env_uri
Feb 12, 2024
06a87d9
ensure always consumptionRoleName and not IAMRoleName is used
Feb 13, 2024
d44409d
lint
Feb 13, 2024
3db3664
compose managed policy arn by name and account_id
Feb 13, 2024
342fa83
detach pilicies from role by IAM role name, not by consumption_role_name
Feb 13, 2024
71b9445
lint
Feb 13, 2024
7ccd505
adjsut share_managers to work with managed policies instead of inline…
Feb 14, 2024
0c881b9
check if the required policies are attached to consumer role before s…
Feb 15, 2024
18c69c8
Flag dataallManaged for the consumptionRoles + migrations. Front-end …
Feb 15, 2024
49f3e05
frontend and test fix
Feb 15, 2024
d4875e0
Block share create if there are no policies attached to consumption role
Feb 15, 2024
4649b18
raise class Exception
Feb 15, 2024
6b6702f
add permissions to pivot role and more logging
Feb 16, 2024
a9fbc00
add permissions to pivot role for Add and Delete policy versions
Feb 16, 2024
93b6f3a
auto-aplly policies, if user checked this option. Display dataallMana…
Feb 16, 2024
b9f5ef4
field dataallManaged typo fix.
Feb 20, 2024
645ea5e
use just one share policy per consumption role
Feb 21, 2024
3ab0988
For Group-role the share policies are also attached
Feb 21, 2024
6a30a1a
lint fix
Feb 21, 2024
da1a3ee
Merge branch 'mda-main' into 922-consumer-ima-role
Feb 21, 2024
a633747
Revert Makefile as it was
Feb 21, 2024
8fa4cf9
Checkov baseline supression of 'CKV_AWS_110' for PivotRolepolicy3. ia…
Feb 22, 2024
73d44ad
disable 'Send request' button, if the policy is not attached
Feb 22, 2024
f202ddb
Merge branch 'mda-main' into 922-consumer-ima-role
Feb 23, 2024
9491131
Merge of alembic migrations
Feb 23, 2024
72c4e92
dataallManaged for ConsumptionRole is set to True by default
Feb 23, 2024
17f9cb8
Correct typo sharePolicyRolName -> sharePolicyRoleName
Feb 23, 2024
e771dd1
Remove ridiculous fields from ConsumptionRoleSearchResult
Feb 23, 2024
dfc9784
All share policy stuff for environment is now in separate service
Feb 23, 2024
cbe9d6d
Backwords compatibility
Feb 23, 2024
38feb93
If there were no inline share policies, we add no resources
Feb 23, 2024
d2b1657
resolver for ConsumptionRole properties
Feb 23, 2024
a31ec06
small changes
Feb 23, 2024
964b44c
Merge branch 'main' into 922-consumer-ima-role
dlpzx Feb 26, 2024
4bdab88
Merge remote-tracking branch 'sof/922-consumer-ima-role' into 922-con…
dlpzx Feb 26, 2024
73b9caa
ManagedPolicies to decouple SharePolicy service from core, backwards …
dlpzx Feb 27, 2024
a9c8a64
Fix alembic migration script
dlpzx Feb 27, 2024
92b98d3
Implementation with abstract classes instead. Added class to data sha…
dlpzx Feb 27, 2024
e7d5571
Uncoupled sharing policies from frontend
dlpzx Feb 27, 2024
77b9982
Added externally managed policies to environment stack to handle non-…
dlpzx Feb 27, 2024
abdeddd
Fix non-imported IAM roles and clear commented backwards compatibilit…
dlpzx Feb 28, 2024
c53dd9e
Divided policies for access points and buckets. Merge ShareManagerUti…
dlpzx Feb 28, 2024
785d002
Fix tests, added methods in remove group from environment and in crea…
dlpzx Feb 28, 2024
45278d9
Revert changes for environment creation
dlpzx Feb 29, 2024
2484ea2
Replace FAKE_S3_PLACEHOLDER by EMPTY_STATEMENT
dlpzx Feb 29, 2024
8fee408
Scope down permissions for pivot role
dlpzx Feb 29, 2024
a7ae29e
Merge branch 'main' into 922-consumer-ima-role
dlpzx Feb 29, 2024
181af2a
Adapt to merge changes
dlpzx Mar 1, 2024
65cf21a
Added exception handling, added and fixed tests
dlpzx Mar 1, 2024
11ae8e1
Fix test
dlpzx Mar 1, 2024
b896e1f
Fix credentials tests
dlpzx Mar 1, 2024
974949d
Small review enhancements
dlpzx Mar 4, 2024
a767146
Add edge cases support: delete policy versions, check policies before…
dlpzx Mar 4, 2024
3ae6892
Fixes backwards compatibility - remove backfilling from environment s…
dlpzx Mar 4, 2024
b96871c
Flaking
dlpzx Mar 4, 2024
3a10763
update checkov and small typo
noah-paige Mar 4, 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
3 changes: 2 additions & 1 deletion .checkov.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
{
"resource": "AWS::IAM::ManagedPolicy.PivotRolepolicy3",
"check_ids": [
"CKV_AWS_109"
"CKV_AWS_109",
noah-paige marked this conversation as resolved.
Show resolved Hide resolved
"CKV_AWS_110"
]
}
]
Expand Down
165 changes: 154 additions & 11 deletions backend/dataall/base/aws/iam.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from .sts import SessionHelper


log = logging.getLogger(__name__)


Expand Down Expand Up @@ -47,10 +46,10 @@ def get_role_arn_by_name(account_id: str, role_name: str, role=None):

@staticmethod
def update_role_policy(
account_id: str,
role_name: str,
policy_name: str,
policy: str,
account_id: str,
role_name: str,
policy_name: str,
policy: str,
):
try:
iamcli = IAM.client(account_id)
Expand All @@ -67,9 +66,9 @@ def update_role_policy(

@staticmethod
def get_role_policy(
account_id: str,
role_name: str,
policy_name: str,
account_id: str,
role_name: str,
policy_name: str,
):
try:
iamcli = IAM.client(account_id)
Expand All @@ -87,9 +86,9 @@ def get_role_policy(

@staticmethod
def delete_role_policy(
account_id: str,
role_name: str,
policy_name: str,
account_id: str,
role_name: str,
policy_name: str,
):
try:
iamcli = IAM.client(account_id)
Expand All @@ -101,3 +100,147 @@ def delete_role_policy(
log.error(
f'Failed to delete policy {policy_name} of role {role_name} : {e}'
)

@staticmethod
def create_managed_policy(
account_id: str,
policy_name: str,
policy: str
):
try:
iamcli = IAM.client(account_id)
response = iamcli.create_policy(
PolicyName=policy_name,
PolicyDocument=policy,
)
arn = response['Policy']['Arn']
log.info(
f'Created managed policy {arn}'
)
return arn
except Exception as e:
log.error(
f'Failed to create managed policy {policy_name} : {e}'
)
return None

@staticmethod
def delete_managed_policy_by_name(
account_id: str,
policy_name):
try:
arn = f'arn:aws:iam::{account_id}:policy/{policy_name}'
iamcli = IAM.client(account_id)
iamcli.delete_policy(
PolicyArn=arn
)
except Exception as e:
log.error(
f'Failed to delete managed policy {policy_name} : {e}'
)

@staticmethod
def get_managed_policy_default_version(
account_id: str,
policy_name: str):
try:
arn = f'arn:aws:iam::{account_id}:policy/{policy_name}'
iamcli = IAM.client(account_id)
response = iamcli.get_policy(PolicyArn=arn)
versionId = response['Policy']['DefaultVersionId']
policyVersion = iamcli.get_policy_version(PolicyArn=arn, VersionId=versionId)
policyDocument = policyVersion['PolicyVersion']['Document']
return versionId, policyDocument
except Exception as e:
log.error(
f'Failed to get policy {policy_name} : {e}'
)
return None
dlpzx marked this conversation as resolved.
Show resolved Hide resolved

@staticmethod
def update_managed_policy_default_version(
account_id: str,
policy_name: str,
old_version_id: str,
policy_document: str):
try:
arn = f'arn:aws:iam::{account_id}:policy/{policy_name}'
iamcli = IAM.client(account_id)
iamcli.create_policy_version(
PolicyArn=arn,
PolicyDocument=policy_document,
SetAsDefault=True
)

iamcli.delete_policy_version(PolicyArn=arn, VersionId=old_version_id)
except Exception as e:
log.error(
f'Failed to update policy {policy_name} : {e}'
)

@staticmethod
def detach_policy_from_role(
account_id: str,
role_name: str,
policy_name: str):

try:
arn = f'arn:aws:iam::{account_id}:policy/{policy_name}'
iamcli = IAM.client(account_id)
iamcli.detach_role_policy(
RoleName=role_name,
PolicyArn=arn
)
except Exception as e:
log.error(
f'Failed to detach policy {policy_name} from role {role_name} : {e}'
)

@staticmethod
def get_policy_by_name(
account_id: str,
policy_name: str
):
try:
arn = f'arn:aws:iam::{account_id}:policy/{policy_name}'
iamcli = IAM.client(account_id)
response = iamcli.get_policy(PolicyArn=arn)
return response['Policy']
except Exception as e:
log.error(
f'Failed to get policy {policy_name} : {e}'
)
return None

@staticmethod
def is_policy_attached(
account_id: str,
policy_name: str,
role_name: str
):
try:
iamcli = IAM.client(account_id)
response = iamcli.list_attached_role_policies(RoleName=role_name)
return policy_name in [p['PolicyName'] for p in response['AttachedPolicies']]
except Exception as e:
log.error(
f'Failed to get the list of attached policies to the role {role_name}: {e}'
)
return False

@staticmethod
def attach_role_policy(
account_id,
role_name,
policy_arn
):
try:
iamcli = IAM.client(account_id)
response = iamcli.attach_role_policy(
RoleName=role_name,
PolicyArn=policy_arn
)
except Exception as e:
log.error(
f'Failed to attach policy {policy_arn} to the role {role_name}: {e}'
)
3 changes: 2 additions & 1 deletion backend/dataall/base/utils/naming_convention.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
class NamingConventionPattern(Enum):

S3 = {'regex': '[^a-zA-Z0-9-]', 'separator': '-', 'max_length': 63}
IAM = {'regex': '[^a-zA-Z0-9-_]', 'separator': '-', 'max_length': 63}
IAM = {'regex': '[^a-zA-Z0-9-_]', 'separator': '-', 'max_length': 63} # Role names up to 64 chars
IAM_POLICY = {'regex': '[^a-zA-Z0-9-_]', 'separator': '-', 'max_length': 128} # Policy names up to 128 chars
GLUE = {'regex': '[^a-zA-Z0-9_]', 'separator': '_', 'max_length': 240} # Limit 255 - 15 extra chars buffer
GLUE_ETL = {'regex': '[^a-zA-Z0-9-]', 'separator': '-', 'max_length': 52}
NOTEBOOK = {'regex': '[^a-zA-Z0-9-]', 'separator': '-', 'max_length': 63}
Expand Down
2 changes: 2 additions & 0 deletions backend/dataall/core/environment/api/input_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ class EnvironmentSortField(GraphQLEnumMapper):
gql.Argument('groupUri', gql.NonNullableType(gql.String)),
gql.Argument('IAMRoleArn', gql.NonNullableType(gql.String)),
gql.Argument('environmentUri', gql.NonNullableType(gql.String)),
gql.Argument('dataallManaged', gql.NonNullableType(gql.Boolean)),

],
)

Expand Down
53 changes: 33 additions & 20 deletions backend/dataall/core/environment/api/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from dataall.base.aws.sts import SessionHelper
from dataall.base.utils import Parameter
from dataall.core.environment.db.environment_models import Environment, EnvironmentGroup
from dataall.core.environment.services.managed_iam_policies import PolicyManager
from dataall.core.environment.services.environment_resource_manager import EnvironmentResourceManager
from dataall.core.environment.services.environment_service import EnvironmentService
from dataall.core.environment.api.enums import EnvironmentPermission
Expand Down Expand Up @@ -39,7 +40,8 @@ def get_trust_account(context: Context, source, **kwargs):


def get_pivot_role_as_part_of_environment(context: Context, source, **kwargs):
ssm_param = ParameterStoreManager.get_parameter_value(region=os.getenv('AWS_REGION', 'eu-west-1'), parameter_path=f"/dataall/{os.getenv('envname', 'local')}/pivotRole/enablePivotRoleAutoCreate")
ssm_param = ParameterStoreManager.get_parameter_value(region=os.getenv('AWS_REGION', 'eu-west-1'),
parameter_path=f"/dataall/{os.getenv('envname', 'local')}/pivotRole/enablePivotRoleAutoCreate")
return True if ssm_param == "True" else False


Expand Down Expand Up @@ -122,7 +124,7 @@ def create_environment(context: Context, source, input={}):


def update_environment(
context: Context, source, environmentUri: str = None, input: dict = None
context: Context, source, environmentUri: str = None, input: dict = None
):
if input.get('SamlGroupName') and input.get('SamlGroupName') not in context.groups:
raise exceptions.UnauthorizedOperation(
Expand Down Expand Up @@ -233,7 +235,7 @@ def update_consumption_role(context: Context, source, environmentUri=None, consu


def list_environment_invited_groups(
context: Context, source, environmentUri=None, filter=None
context: Context, source, environmentUri=None, filter=None
):
if filter is None:
filter = {}
Expand All @@ -257,7 +259,7 @@ def list_environment_groups(context: Context, source, environmentUri=None, filte


def list_all_environment_groups(
context: Context, source, environmentUri=None, filter=None
context: Context, source, environmentUri=None, filter=None
):
if filter is None:
filter = {}
Expand All @@ -270,7 +272,7 @@ def list_all_environment_groups(


def list_environment_consumption_roles(
context: Context, source, environmentUri=None, filter=None
context: Context, source, environmentUri=None, filter=None
):
if filter is None:
filter = {}
Expand All @@ -283,7 +285,7 @@ def list_environment_consumption_roles(


def list_all_environment_consumption_roles(
context: Context, source, environmentUri=None, filter=None
context: Context, source, environmentUri=None, filter=None
):
if filter is None:
filter = {}
Expand All @@ -296,9 +298,9 @@ def list_all_environment_consumption_roles(


def list_environment_group_invitation_permissions(
context: Context,
source,
environmentUri=None,
context: Context,
source,
environmentUri=None,
):
with context.engine.scoped_session() as session:
return EnvironmentService.list_group_invitation_permissions(
Expand Down Expand Up @@ -331,7 +333,7 @@ def list_groups(context: Context, source, filter=None):


def list_consumption_roles(
context: Context, source, environmentUri=None, filter=None
context: Context, source, environmentUri=None, filter=None
):
if filter is None:
filter = {}
Expand All @@ -343,7 +345,7 @@ def list_consumption_roles(


def list_environment_networks(
context: Context, source, environmentUri=None, filter=None
context: Context, source, environmentUri=None, filter=None
):
if filter is None:
filter = {}
Expand All @@ -360,6 +362,17 @@ def get_parent_organization(context: Context, source, **kwargs):
return org


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One note out of the scope of this PR: core is not following the standard we have set for the modules, there is no a clear separation between the api, services and db layer. Balint refactored organizations and I refactored vpc we still need to refactor environments, groups, permissions, stacks

def get_policies(context: Context, source, **kwargs):
with context.engine.scoped_session() as session:
environment = EnvironmentService.get_environment_by_uri(session, source.environmentUri)
return PolicyManager(
role_name=source.IAMRoleName,
environmentUri=environment.environmentUri,
account=environment.AwsAccountId,
resource_prefix=environment.resourcePrefix
).get_all_policies()


def resolve_environment_networks(context: Context, source, **kwargs):
return VpcService.get_environment_networks(environment_uri=source.environmentUri)

Expand Down Expand Up @@ -392,7 +405,7 @@ def resolve_user_role(context: Context, source: Environment):


def list_environment_group_permissions(
context, source, environmentUri: str = None, groupUri: str = None
context, source, environmentUri: str = None, groupUri: str = None
):
with context.engine.scoped_session() as session:
return EnvironmentService.list_group_permissions(
Expand All @@ -404,7 +417,7 @@ def list_environment_group_permissions(

@is_feature_enabled('core.features.env_aws_actions')
def _get_environment_group_aws_session(
session, username, groups, environment, groupUri=None
session, username, groups, environment, groupUri=None
):
if groupUri and groupUri not in groups:
raise exceptions.UnauthorizedOperation(
Expand Down Expand Up @@ -452,10 +465,10 @@ def _get_environment_group_aws_session(

@is_feature_enabled('core.features.env_aws_actions')
def get_environment_assume_role_url(
context: Context,
source,
environmentUri: str = None,
groupUri: str = None,
context: Context,
source,
environmentUri: str = None,
groupUri: str = None,
):
with context.engine.scoped_session() as session:
ResourcePolicy.check_user_resource_permission(
Expand All @@ -481,7 +494,7 @@ def get_environment_assume_role_url(

@is_feature_enabled('core.features.env_aws_actions')
def generate_environment_access_token(
context, source, environmentUri: str = None, groupUri: str = None
context, source, environmentUri: str = None, groupUri: str = None
):
with context.engine.scoped_session() as session:
ResourcePolicy.check_user_resource_permission(
Expand Down Expand Up @@ -515,7 +528,7 @@ def get_environment_stack(context: Context, source: Environment, **kwargs):


def delete_environment(
context: Context, source, environmentUri: str = None, deleteFromAWS: bool = False
context: Context, source, environmentUri: str = None, deleteFromAWS: bool = False
):
with context.engine.scoped_session() as session:
environment = EnvironmentService.get_environment_by_uri(session, environmentUri)
Expand All @@ -537,7 +550,7 @@ def delete_environment(


def enable_subscriptions(
context: Context, source, environmentUri: str = None, input: dict = None
context: Context, source, environmentUri: str = None, input: dict = None
):
with context.engine.scoped_session() as session:
ResourcePolicy.check_user_resource_permission(
Expand Down
Loading
Loading