import os from aws_cdk import Stack, Aws, triggers from aws_cdk.aws_iam import PolicyDocument, PolicyStatement, Effect, ManagedPolicy, Role, ServicePrincipal from constructs import Construct import aws_cdk.aws_lambda as lambda_ class IamSsmStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) sagemaker_role_arn = self.node.try_get_context("sagemaker_role") sagemaker_role = Role.from_role_arn(self, "sagemaker_role", role_arn=sagemaker_role_arn) user_role_arn = self.node.try_get_context("user_role") user_role = Role.from_role_arn(self, "user_role", role_arn=user_role_arn) # noinspection PyUnusedLocal ssh_client_policy = \ ManagedPolicy(self, "SSHSageMakerClientPolicy", managed_policy_name="SSHSageMakerClientPolicy", document=PolicyDocument(statements=[ PolicyStatement( effect=Effect.ALLOW, actions=[ "ssm:DescribeInstanceInformation", "ssm:ListTagsForResource", "ssm:GetCommandInvocation", ], resources=["*"] ), PolicyStatement( effect=Effect.ALLOW, actions=[ "ssm:DeregisterManagedInstance", ], resources=[f"arn:{Aws.PARTITION}:ssm:*:{Aws.ACCOUNT_ID}:managed-instance/mi-*"], conditions={ "StringLike": { "ssm:resourceTag/SSHOwner": "*" } } ), PolicyStatement( effect=Effect.ALLOW, actions=[ "ssm:StartSession", "ssm:SendCommand", ], resources=[f"arn:{Aws.PARTITION}:ssm:*:{Aws.ACCOUNT_ID}:managed-instance/mi-*"], conditions={ "StringEquals": { "ssm:resourceTag/SSHOwner": "${aws:userid}" } } ), PolicyStatement( effect=Effect.ALLOW, actions=[ "ssm:TerminateSession", ], resources=[f"arn:{Aws.PARTITION}:ssm:*:{Aws.ACCOUNT_ID}:session/*"], conditions={ "StringLike": { "ssm:resourceTag/aws:ssmmessages:session-id": "${aws:userid}" } } ), PolicyStatement( effect=Effect.ALLOW, actions=[ "ssm:StartSession", ], resources=[f"arn:{Aws.PARTITION}:ssm:*::document/AWS-StartSSHSession"] ), PolicyStatement( effect=Effect.ALLOW, actions=[ "ssm:SendCommand", ], resources=[f"arn:{Aws.PARTITION}:ssm:*::document/AWS-RunShellScript"] ), PolicyStatement( effect=Effect.ALLOW, actions=[ "logs:StartQuery", ], resources=[f"arn:{Aws.PARTITION}:logs:*:{Aws.ACCOUNT_ID}:log-group:/aws/sagemaker/*"] ), PolicyStatement( effect=Effect.ALLOW, actions=[ "logs:GetQueryResults", ], resources=["*"] ), ])) # noinspection PyUnusedLocal ssh_server_policy = \ ManagedPolicy(self, "SSHSageMakerServerPolicy", managed_policy_name="SSHSageMakerServerPolicy", document=PolicyDocument(statements=[ PolicyStatement( effect=Effect.ALLOW, actions=[ "iam:PassRole", ], resources=[sagemaker_role.role_arn], conditions={ "StringEquals": { "iam:PassedToService": "ssm.amazonaws.com" } } ), PolicyStatement( effect=Effect.ALLOW, actions=[ "ssm:AddTagsToResource", ], resources=[sagemaker_role.role_arn], ), PolicyStatement( effect=Effect.ALLOW, actions=[ "ssm:CreateActivation", "ssm:ListAssociations", "ssm:ListInstanceAssociations", "ec2messages:GetMessages", "ec2messages:AcknowledgeMessage", "ec2messages:SendReply", "ec2messages:DeleteMessage", "ssmmessages:CreateControlChannel", "ssmmessages:CreateDataChannel", "ssmmessages:OpenControlChannel", "ssmmessages:OpenDataChannel" ], resources=["*"] ), PolicyStatement( effect=Effect.ALLOW, actions=[ "ssm:UpdateInstanceInformation", ], resources=[f"arn:{Aws.PARTITION}:ssm:*:{Aws.ACCOUNT_ID}:managed-instance/mi-*"], conditions={ "StringLike": { "ssm:resourceTag/SSHOwner": "*" } } ), ])) ssh_server_policy.attach_to_role(sagemaker_role) ssh_client_policy.attach_to_role(user_role) with open(os.path.join(os.path.dirname(__file__), "trust_relationship_lambda.py")) as lambda_path: code = lambda_path.read() code = code.replace("<>", sagemaker_role.role_name) role = Role(self, "TrustRelationshipLambdaRole", assumed_by=ServicePrincipal("lambda.amazonaws.com"), inline_policies={ "TrustRelationshipLambdaPolicy": PolicyDocument(statements=[ PolicyStatement( effect=Effect.ALLOW, actions=["iam:UpdateAssumeRolePolicy"], resources=[sagemaker_role_arn] ) ])}) triggers.TriggerFunction(self, "TrustRelationshipLambdaTrigger", runtime=lambda_.Runtime.PYTHON_3_7, role=role, handler="index.handler", code=lambda_.Code.from_inline(code))