def autoscaler_role(self, policy: iam.Policy) -> iam.Role: oidc_arn = cdk.CfnJson( self, "oidc-provider", value=self.cluster.open_id_connect_provider. open_id_connect_provider_arn, ) oidc_arn_condition = cdk.CfnJson( self, "oidc-provider-condition", value={ f"{self.cluster.open_id_connect_provider.open_id_connect_provider_issuer}:sub": "system:serviceaccount:kube-system:cluster-autoscaler" }, ) role = iam.Role( self, "ClusterAutoscalerRole", assumed_by=iam.FederatedPrincipal( oidc_arn.value.to_string(), {"StringEquals": oidc_arn_condition}, "sts:AssumeRoleWithWebIdentity", ), ) role.attach_inline_policy(policy) return role
def create_job_execution_role(self, role_name: str, namespace: str) -> None: job_role = iam.Role( self, "EMR_EKS_Job_Role", assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"), managed_policies=[ iam.ManagedPolicy.from_aws_managed_policy_name( "AmazonS3FullAccess"), # Yes, yes...I know. :) iam.ManagedPolicy.from_aws_managed_policy_name( "AmazonEC2FullAccess"), iam.ManagedPolicy.from_aws_managed_policy_name( "AWSGlueConsoleFullAccess"), iam.ManagedPolicy.from_aws_managed_policy_name( "CloudWatchFullAccess"), ], role_name=role_name, ) cdk.CfnOutput(self, "JobRoleArn", value=job_role.role_arn) # Modify trust policy string_like = cdk.CfnJson( self, "ConditionJson", value={ f"{self.eks_cluster.cluster_open_id_connect_issuer}:sub": f"system:serviceaccount:{namespace}:emr-containers-sa-*-*-{cdk.Aws.ACCOUNT_ID}-*" }, ) job_role.assume_role_policy.add_statements( iam.PolicyStatement( effect=iam.Effect.ALLOW, actions=["sts:AssumeRoleWithWebIdentity"], principals=[ iam.OpenIdConnectPrincipal( self.eks_cluster.open_id_connect_provider, conditions={"StringLike": string_like}, ) ], )) string_aud = cdk.CfnJson( self, "ConditionJsonAud", value={ f"{self.eks_cluster.cluster_open_id_connect_issuer}:aud": "sts.amazon.com" }, ) job_role.assume_role_policy.add_statements( iam.PolicyStatement( effect=iam.Effect.ALLOW, actions=["sts:AssumeRoleWithWebIdentity"], principals=[ iam.OpenIdConnectPrincipal( self.eks_cluster.open_id_connect_provider, conditions={"StringEquals": string_aud}, ) ], ))
def add_service_account(self, cluster, name, namespace): """ workaround to add helm role to service account """ # create role conditions = core.CfnJson( self, 'ConditionJson', value={ "%s:aud" % cluster.cluster_open_id_connect_issuer: "sts.amazonaws.com", "%s:sub" % cluster.cluster_open_id_connect_issuer: "system:serviceaccount:%s:%s" % (namespace, name), }, ) principal = iam.OpenIdConnectPrincipal( cluster.open_id_connect_provider).with_conditions({ "StringEquals": conditions, }) role = iam.Role(self, 'ServiceAccountRole', assumed_by=principal) # create policy for the service account statements = [] with open('backend/iam_policy.json') as f: data = json.load(f) for s in data["Statement"]: statements.append(iam.PolicyStatement.from_json(s)) policy = iam.Policy(self, "LBControllerPolicy", statements=statements) policy.attach_to_role(role) return eks.KubernetesManifest( self, "ServiceAccount", cluster=cluster, manifest=[{ "apiVersion": "v1", "kind": "ServiceAccount", "metadata": { "name": name, "namespace": namespace, "labels": { "app.kubernetes.io/name": name, "app.kubernetes.io/managed-by": "Helm", }, "annotations": { "eks.amazonaws.com/role-arn": role.role_arn, "meta.helm.sh/release-name": name, "meta.helm.sh/release-namespace": namespace, }, }, }], )
def create_athena_resources(self) -> None: self.athena_workgroup = aws_athena.CfnWorkGroup( self, 'SlsBlogAthenaWorkgroup', name='sls-blog-athena-workgroup', description='Serverless Website demo project (by Dashbird)', recursive_delete_option=True, state='ENABLED', work_group_configuration_updates=core.CfnJson( self, 'sls-blog-workgroup-config-updates', value={ 'EnforceWorkGroupConfiguration': True, 'BytesScannedCutoffPerQuery': DataSize.gigabytes(1), 'PublishCloudWatchMetricsEnabled': True, 'ResultConfigurationUpdates': { 'OutputLocation': f's3://{self.bucket_queries.bucket_name}/', }, }, ), )
def __init__(self, scope: core.Construct, construct_id: str, subnets: List[str], vpc: ec2.IVpc, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) self.env_name = "MwaaForEmrOnEks" self.prefix_list_id = self.node.try_get_context("prefix") # Create S3 bucket for MWAA bucket = s3.Bucket(self, "MwaaBucket", encryption=s3.BucketEncryption.S3_MANAGED, block_public_access=s3.BlockPublicAccess.BLOCK_ALL, versioned=True) core.CfnOutput(self, "BucketName", value=bucket.bucket_name) # Create MWAA role role = iam.Role( self, "MwaaRole", assumed_by=iam.ServicePrincipal("airflow-env.amazonaws.com")) role.add_to_policy( iam.PolicyStatement(resources=[ f"arn:aws:airflow:{self.region}:{self.account}:environment/{self.env_name}" ], actions=["airflow:PublishMetrics"], effect=iam.Effect.ALLOW)) role.add_to_policy( iam.PolicyStatement(resources=[ f"arn:aws:s3:::{bucket.bucket_name}", f"arn:aws:s3:::{bucket.bucket_name}/*" ], actions=["s3:ListAllMyBuckets"], effect=iam.Effect.DENY)) role.add_to_policy( iam.PolicyStatement( resources=[ f"arn:aws:s3:::{bucket.bucket_name}", f"arn:aws:s3:::{bucket.bucket_name}/*" ], actions=["s3:GetObject*", "s3:GetBucket*", "s3:List*"], effect=iam.Effect.ALLOW)) role.add_to_policy( iam.PolicyStatement(resources=[ f"arn:aws:logs:{self.region}:{self.account}:log-group:airflow-{self.env_name}-*" ], actions=[ "logs:CreateLogStream", "logs:CreateLogGroup", "logs:PutLogEvents", "logs:GetLogEvents", "logs:GetLogRecord", "logs:GetLogGroupFields", "logs:GetQueryResults", "logs:DescribeLogGroups" ], effect=iam.Effect.ALLOW)) role.add_to_policy( iam.PolicyStatement(resources=["*"], actions=["cloudwatch:PutMetricData"], effect=iam.Effect.ALLOW)) role.add_to_policy( iam.PolicyStatement(resources=["*"], actions=[ "emr-containers:StartJobRun", "emr-containers:ListJobRuns", "emr-containers:DescribeJobRun", "emr-containers:CancelJobRun" ], effect=iam.Effect.ALLOW)) role.add_to_policy( iam.PolicyStatement( resources=[f"arn:aws:sqs:{self.region}:*:airflow-celery-*"], actions=[ "sqs:ChangeMessageVisibility", "sqs:DeleteMessage", "sqs:GetQueueAttributes", "sqs:GetQueueUrl", "sqs:ReceiveMessage", "sqs:SendMessage" ], effect=iam.Effect.ALLOW)) string_like = core.CfnJson( self, "ConditionJson", value={f"kms:ViaService": f"sqs.{self.region}.amazonaws.com"}) role.add_to_policy( iam.PolicyStatement( not_resources=[f"arn:aws:kms:*:{self.account}:key/*"], actions=[ "kms:Decrypt", "kms:DescribeKey", "kms:GenerateDataKey*", "kms:Encrypt" ], effect=iam.Effect.ALLOW, conditions={"StringLike": string_like})) # Upload MWAA pre-reqs s3deploy.BucketDeployment( self, "DeployPlugin", sources=[ s3deploy.Source.asset( "./emr_eks_cdk/mwaa_plugins", exclude=['**', '!emr_containers_airflow_plugin.zip']) ], destination_bucket=bucket, destination_key_prefix="plug-ins") s3req = s3deploy.BucketDeployment( self, "DeployReq", sources=[ s3deploy.Source.asset("./emr_eks_cdk/mwaa_plugins", exclude=['**', '!requirements.txt']) ], destination_bucket=bucket, destination_key_prefix="Requirements") s3deploy.BucketDeployment(self, "DeployDag", sources=[ s3deploy.Source.asset( "./emr_eks_cdk/mwaa_plugins", exclude=['**', '!emr_eks.py']) ], destination_bucket=bucket, destination_key_prefix="DAG") # Get object versions req_obj_version = custom.AwsCustomResource( self, "GetReqV", on_update={ "service": "S3", "action": "headObject", "parameters": { "Bucket": bucket.bucket_name, "Key": "Requirements/requirements.txt" }, "physical_resource_id": custom.PhysicalResourceId.from_response("VersionId") }, policy=custom.AwsCustomResourcePolicy.from_sdk_calls( resources=custom.AwsCustomResourcePolicy.ANY_RESOURCE), role=iam.Role( scope=self, id=f'{construct_id}-LambdaRole', assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'), managed_policies=[ iam.ManagedPolicy.from_aws_managed_policy_name( "service-role/AWSLambdaBasicExecutionRole"), iam.ManagedPolicy.from_aws_managed_policy_name( "AmazonS3FullAccess") ])) core.CfnOutput(self, "ReqObjVersion", value=req_obj_version.get_response_field("VersionId")) plugin_obj_version = custom.AwsCustomResource( self, "GetPluginV", on_update={ "service": "S3", "action": "headObject", "parameters": { "Bucket": bucket.bucket_name, "Key": "plug-ins/emr_containers_airflow_plugin.zip" }, "physical_resource_id": custom.PhysicalResourceId.from_response("VersionId") }, policy=custom.AwsCustomResourcePolicy.from_sdk_calls( resources=custom.AwsCustomResourcePolicy.ANY_RESOURCE), role=iam.Role( scope=self, id=f'{construct_id}-LambdaRole-2', assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'), managed_policies=[ iam.ManagedPolicy.from_aws_managed_policy_name( "service-role/AWSLambdaBasicExecutionRole"), iam.ManagedPolicy.from_aws_managed_policy_name( "AmazonS3FullAccess") ])) core.CfnOutput( self, "PluginObjVersion", value=plugin_obj_version.get_response_field("VersionId")) # Create security group mwaa_sg = ec2.SecurityGroup(self, "SecurityGroup", vpc=vpc, description="Allow inbound access to MWAA", allow_all_outbound=True) mwaa_sg.add_ingress_rule(ec2.Peer.prefix_list(self.prefix_list_id), ec2.Port.all_tcp(), "allow inbound access from the prefix list") mwaa_sg.add_ingress_rule(mwaa_sg, ec2.Port.all_traffic(), "allow inbound access from the SG") mwaa_env = mwaa.CfnEnvironment( self, "MWAAEnv", name=self.env_name, dag_s3_path="DAG", environment_class="mw1.small", execution_role_arn=role.role_arn, logging_configuration=mwaa.CfnEnvironment. LoggingConfigurationProperty( dag_processing_logs=mwaa.CfnEnvironment. ModuleLoggingConfigurationProperty(enabled=True, log_level='INFO'), scheduler_logs=mwaa.CfnEnvironment. ModuleLoggingConfigurationProperty(enabled=True, log_level='INFO'), task_logs=mwaa.CfnEnvironment. ModuleLoggingConfigurationProperty(enabled=True, log_level='INFO'), webserver_logs=mwaa.CfnEnvironment. ModuleLoggingConfigurationProperty(enabled=True, log_level='INFO'), worker_logs=mwaa.CfnEnvironment. ModuleLoggingConfigurationProperty(enabled=True, log_level='INFO')), network_configuration=mwaa.CfnEnvironment. NetworkConfigurationProperty( security_group_ids=[mwaa_sg.security_group_id], subnet_ids=subnets), plugins_s3_path="plug-ins/emr_containers_airflow_plugin.zip", plugins_s3_object_version=plugin_obj_version.get_response_field( "VersionId"), requirements_s3_path="Requirements/requirements.txt", requirements_s3_object_version=req_obj_version.get_response_field( "VersionId"), source_bucket_arn=bucket.bucket_arn, webserver_access_mode='PUBLIC_ONLY') core.CfnOutput(self, "MWAA_NAME", value=self.env_name)
def __init__(self, scope: core.Construct, id: str, vpc: VpcStack, s3: S3Stack, **kwargs) -> None: super().__init__(scope, id, **kwargs) mwaa_env_name = "mwaa_codeartifact_env" airflow_version = os.environ.get("AIRFLOW_VERSION", "2.0.2") # Create MWAA role mwaa_role = iam.Role( self, "MWAARole", assumed_by=iam.ServicePrincipal("airflow-env.amazonaws.com"), ) mwaa_role.add_to_policy( iam.PolicyStatement( resources=[(f"arn:aws:airflow:{self.region}:" f"{self.account}:environment/{mwaa_env_name}")], actions=["airflow:PublishMetrics"], effect=iam.Effect.ALLOW, )) mwaa_role.add_to_policy( iam.PolicyStatement( resources=[ f"arn:aws:s3:::{s3.instance.bucket_name}", f"arn:aws:s3:::{s3.instance.bucket_name}/*", ], actions=["s3:ListAllMyBuckets"], effect=iam.Effect.DENY, )) mwaa_role.add_to_policy( iam.PolicyStatement( resources=[ f"arn:aws:s3:::{s3.instance.bucket_name}", f"arn:aws:s3:::{s3.instance.bucket_name}/*", ], actions=["s3:*"], effect=iam.Effect.ALLOW, )) mwaa_role.add_to_policy( iam.PolicyStatement( resources=[(f"arn:aws:logs:{self.region}:{self.account}:" f"log-group:airflow-{mwaa_env_name}-*")], actions=[ "logs:CreateLogStream", "logs:CreateLogGroup", "logs:PutLogEvents", "logs:GetLogEvents", "logs:GetLogRecord", "logs:GetLogGroupFields", "logs:GetQueryResults", "logs:DescribeLogGroups", ], effect=iam.Effect.ALLOW, )) mwaa_role.add_to_policy( iam.PolicyStatement( resources=["*"], actions=["cloudwatch:PutMetricData"], effect=iam.Effect.ALLOW, )) mwaa_role.add_to_policy( iam.PolicyStatement( resources=[f"arn:aws:sqs:{self.region}:*:airflow-celery-*"], actions=[ "sqs:ChangeMessageVisibility", "sqs:DeleteMessage", "sqs:GetQueueAttributes", "sqs:GetQueueUrl", "sqs:ReceiveMessage", "sqs:SendMessage", ], effect=iam.Effect.ALLOW, )) string_like = core.CfnJson( self, "ConditionJson", value={f"kms:ViaService": f"sqs.{self.region}.amazonaws.com"}, ) mwaa_role.add_to_policy( iam.PolicyStatement( not_resources=[f"arn:aws:kms:*:{self.account}:key/*"], actions=[ "kms:Decrypt", "kms:DescribeKey", "kms:GenerateDataKey*", "kms:Encrypt", ], effect=iam.Effect.ALLOW, conditions={"StringLike": string_like}, )) # Define MWAA configuration security_group_ids = mwaa.CfnEnvironment.NetworkConfigurationProperty( security_group_ids=[vpc.mwaa_sg.security_group_id], subnet_ids=vpc.get_vpc_private_subnet_ids, ) logs_conf = mwaa.CfnEnvironment.ModuleLoggingConfigurationProperty( enabled=True, log_level="INFO") logging_configuration = mwaa.CfnEnvironment.LoggingConfigurationProperty( scheduler_logs=logs_conf, webserver_logs=logs_conf, dag_processing_logs=logs_conf, ) # Create MWAA environment mwaa_ca_env = mwaa.CfnEnvironment( self, "mwaa_ca_env", name=mwaa_env_name, environment_class="mw1.small", airflow_version=airflow_version, execution_role_arn=mwaa_role.role_arn, source_bucket_arn=s3.instance.bucket_arn, dag_s3_path="dags", requirements_s3_path="requirements.txt", max_workers=2, webserver_access_mode="PUBLIC_ONLY", network_configuration=security_group_ids, logging_configuration=logging_configuration, ) mwaa_ca_env.node.add_dependency(mwaa_role)
def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) self.emr_namespace = "sparkns" self.emr_namespace_fg = "sparkfg" self.emrsvcrolearn = f"arn:aws:iam::{self.account}:role/AWSServiceRoleForAmazonEMRContainers" self.instance_type = self.node.try_get_context("instance") # VPC self.vpc = ec2.Vpc(self, "EMR-EKS-VPC", max_azs=3) core.Tags.of(self.vpc).add("for-use-with-amazon-emr-managed-policies", "true") # EKS cluster self.cluster = eks.Cluster( self, "EksForSpark", version=eks.KubernetesVersion.V1_18, default_capacity=0, endpoint_access=eks.EndpointAccess.PUBLIC_AND_PRIVATE, vpc=self.vpc, vpc_subnets=[ ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE) ]) # Default node group self.ng = self.cluster.add_nodegroup_capacity( "base-node-group", instance_types=[ec2.InstanceType(self.instance_type)], min_size=3, max_size=10, disk_size=50) # Create namespaces for EMR to use namespace = self.cluster.add_manifest( self.emr_namespace, { "apiVersion": "v1", "kind": "Namespace", "metadata": { "name": self.emr_namespace }, }) namespace_fg = self.cluster.add_manifest( self.emr_namespace_fg, { "apiVersion": "v1", "kind": "Namespace", "metadata": { "name": self.emr_namespace_fg }, }) # Fargate profile fgprofile = eks.FargateProfile(self, "SparkFargateProfile", cluster=self.cluster, selectors=[{ "namespace": self.emr_namespace_fg }]) # Create k8s cluster role for EMR emrrole = self.cluster.add_manifest( "emrrole", { "apiVersion": "rbac.authorization.k8s.io/v1", "kind": "Role", "metadata": { "name": "emr-containers", "namespace": self.emr_namespace }, "rules": [{ "apiGroups": [""], "resources": ["namespaces"], "verbs": ["get"] }, { "apiGroups": [""], "resources": [ "serviceaccounts", "services", "configmaps", "events", "pods", "pods/log" ], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "deletecollection", "annotate", "patch", "label" ] }, { "apiGroups": [""], "resources": ["secrets"], "verbs": ["create", "patch", "delete", "watch"] }, { "apiGroups": ["apps"], "resources": ["statefulsets", "deployments"], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "annotate", "patch", "label" ] }, { "apiGroups": ["batch"], "resources": ["jobs"], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "annotate", "patch", "label" ] }, { "apiGroups": ["extensions"], "resources": ["ingresses"], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "annotate", "patch", "label" ] }, { "apiGroups": ["rbac.authorization.k8s.io"], "resources": ["roles", "rolebindings"], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "deletecollection", "annotate", "patch", "label" ] }] }) emrrole.node.add_dependency(namespace) emrrole_fg = self.cluster.add_manifest( "emrrole_fg", { "apiVersion": "rbac.authorization.k8s.io/v1", "kind": "Role", "metadata": { "name": "emr-containers", "namespace": self.emr_namespace_fg }, "rules": [{ "apiGroups": [""], "resources": ["namespaces"], "verbs": ["get"] }, { "apiGroups": [""], "resources": [ "serviceaccounts", "services", "configmaps", "events", "pods", "pods/log" ], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "deletecollection", "annotate", "patch", "label" ] }, { "apiGroups": [""], "resources": ["secrets"], "verbs": ["create", "patch", "delete", "watch"] }, { "apiGroups": ["apps"], "resources": ["statefulsets", "deployments"], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "annotate", "patch", "label" ] }, { "apiGroups": ["batch"], "resources": ["jobs"], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "annotate", "patch", "label" ] }, { "apiGroups": ["extensions"], "resources": ["ingresses"], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "annotate", "patch", "label" ] }, { "apiGroups": ["rbac.authorization.k8s.io"], "resources": ["roles", "rolebindings"], "verbs": [ "get", "list", "watch", "describe", "create", "edit", "delete", "deletecollection", "annotate", "patch", "label" ] }] }) emrrole_fg.node.add_dependency(namespace_fg) # Bind cluster role to user emrrolebind = self.cluster.add_manifest( "emrrolebind", { "apiVersion": "rbac.authorization.k8s.io/v1", "kind": "RoleBinding", "metadata": { "name": "emr-containers", "namespace": self.emr_namespace }, "subjects": [{ "kind": "User", "name": "emr-containers", "apiGroup": "rbac.authorization.k8s.io" }], "roleRef": { "kind": "Role", "name": "emr-containers", "apiGroup": "rbac.authorization.k8s.io" } }) emrrolebind.node.add_dependency(emrrole) emrrolebind_fg = self.cluster.add_manifest( "emrrolebind_fg", { "apiVersion": "rbac.authorization.k8s.io/v1", "kind": "RoleBinding", "metadata": { "name": "emr-containers", "namespace": self.emr_namespace_fg }, "subjects": [{ "kind": "User", "name": "emr-containers", "apiGroup": "rbac.authorization.k8s.io" }], "roleRef": { "kind": "Role", "name": "emr-containers", "apiGroup": "rbac.authorization.k8s.io" } }) emrrolebind_fg.node.add_dependency(emrrole_fg) # Map user to IAM role emrsvcrole = iam.Role.from_role_arn(self, "EmrSvcRole", self.emrsvcrolearn, mutable=False) self.cluster.aws_auth.add_role_mapping(emrsvcrole, groups=[], username="******") # Job execution role self.job_role = iam.Role( self, "EMR_EKS_Job_Role", assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"), managed_policies=[ iam.ManagedPolicy.from_aws_managed_policy_name( "AmazonS3FullAccess"), iam.ManagedPolicy.from_aws_managed_policy_name( "AmazonEC2FullAccess"), iam.ManagedPolicy.from_aws_managed_policy_name( "AWSGlueConsoleFullAccess"), iam.ManagedPolicy.from_aws_managed_policy_name( "CloudWatchFullAccess") ]) core.CfnOutput(self, "JobRoleArn", value=self.job_role.role_arn) # Modify trust policy string_like = core.CfnJson( self, "ConditionJson", value={ f"{self.cluster.cluster_open_id_connect_issuer}:sub": f"system:serviceaccount:emr:emr-containers-sa-*-*-{self.account}-*" }) self.job_role.assume_role_policy.add_statements( iam.PolicyStatement(effect=iam.Effect.ALLOW, actions=["sts:AssumeRoleWithWebIdentity"], principals=[ iam.OpenIdConnectPrincipal( self.cluster.open_id_connect_provider, conditions={"StringLike": string_like}) ])) string_aud = core.CfnJson( self, "ConditionJsonAud", value={ f"{self.cluster.cluster_open_id_connect_issuer}:aud": "sts.amazon.com" }) self.job_role.assume_role_policy.add_statements( iam.PolicyStatement( effect=iam.Effect.ALLOW, actions=["sts:AssumeRoleWithWebIdentity"], principals=[ iam.OpenIdConnectPrincipal( self.cluster.open_id_connect_provider, conditions={"StringEquals": string_aud}) ])) # EMR virtual cluster self.emr_vc = emrc.CfnVirtualCluster( scope=self, id="EMRCluster", container_provider=emrc.CfnVirtualCluster. ContainerProviderProperty( id=self.cluster.cluster_name, info=emrc.CfnVirtualCluster.ContainerInfoProperty( eks_info=emrc.CfnVirtualCluster.EksInfoProperty( namespace=self.emr_namespace)), type="EKS"), name="EMRCluster") self.emr_vc.node.add_dependency(namespace) self.emr_vc.node.add_dependency(emrrolebind) emr_vc_fg = emrc.CfnVirtualCluster( scope=self, id="EMRClusterFG", container_provider=emrc.CfnVirtualCluster. ContainerProviderProperty( id=self.cluster.cluster_name, info=emrc.CfnVirtualCluster.ContainerInfoProperty( eks_info=emrc.CfnVirtualCluster.EksInfoProperty( namespace=self.emr_namespace_fg)), type="EKS"), name="EMRClusterFG") emr_vc_fg.node.add_dependency(namespace_fg) emr_vc_fg.node.add_dependency(emrrolebind_fg) core.CfnOutput(self, "VirtualClusterId", value=self.emr_vc.attr_id) core.CfnOutput(self, "FgVirtualClusterId", value=emr_vc_fg.attr_id) # Create log group log_group = logs.LogGroup(self, "LogGroup") core.CfnOutput(self, "LogGroupName", value=log_group.log_group_name) # LB Controller role self.policy_document = { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "iam:CreateServiceLinkedRole", "ec2:DescribeAccountAttributes", "ec2:DescribeAddresses", "ec2:DescribeAvailabilityZones", "ec2:DescribeInternetGateways", "ec2:DescribeVpcs", "ec2:DescribeSubnets", "ec2:DescribeSecurityGroups", "ec2:DescribeInstances", "ec2:DescribeNetworkInterfaces", "ec2:DescribeTags", "ec2:GetCoipPoolUsage", "ec2:DescribeCoipPools", "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeLoadBalancerAttributes", "elasticloadbalancing:DescribeListeners", "elasticloadbalancing:DescribeListenerCertificates", "elasticloadbalancing:DescribeSSLPolicies", "elasticloadbalancing:DescribeRules", "elasticloadbalancing:DescribeTargetGroups", "elasticloadbalancing:DescribeTargetGroupAttributes", "elasticloadbalancing:DescribeTargetHealth", "elasticloadbalancing:DescribeTags" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "cognito-idp:DescribeUserPoolClient", "acm:ListCertificates", "acm:DescribeCertificate", "iam:ListServerCertificates", "iam:GetServerCertificate", "waf-regional:GetWebACL", "waf-regional:GetWebACLForResource", "waf-regional:AssociateWebACL", "waf-regional:DisassociateWebACL", "wafv2:GetWebACL", "wafv2:GetWebACLForResource", "wafv2:AssociateWebACL", "wafv2:DisassociateWebACL", "shield:GetSubscriptionState", "shield:DescribeProtection", "shield:CreateProtection", "shield:DeleteProtection" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:AuthorizeSecurityGroupIngress", "ec2:RevokeSecurityGroupIngress" ], "Resource": "*" }, { "Effect": "Allow", "Action": ["ec2:CreateSecurityGroup"], "Resource": "*" }, { "Effect": "Allow", "Action": ["ec2:CreateTags"], "Resource": "arn:aws:ec2:*:*:security-group/*", "Condition": { "StringEquals": { "ec2:CreateAction": "CreateSecurityGroup" }, "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": False } } }, { "Effect": "Allow", "Action": ["ec2:CreateTags", "ec2:DeleteTags"], "Resource": "arn:aws:ec2:*:*:security-group/*", "Condition": { "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": True, "aws:ResourceTag/elbv2.k8s.aws/cluster": False } } }, { "Effect": "Allow", "Action": [ "ec2:AuthorizeSecurityGroupIngress", "ec2:RevokeSecurityGroupIngress", "ec2:DeleteSecurityGroup" ], "Resource": "*", "Condition": { "Null": { "aws:ResourceTag/elbv2.k8s.aws/cluster": False } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:CreateLoadBalancer", "elasticloadbalancing:CreateTargetGroup" ], "Resource": "*", "Condition": { "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": False } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:CreateListener", "elasticloadbalancing:DeleteListener", "elasticloadbalancing:CreateRule", "elasticloadbalancing:DeleteRule" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags", "elasticloadbalancing:RemoveTags" ], "Resource": [ "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*" ], "Condition": { "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": True, "aws:ResourceTag/elbv2.k8s.aws/cluster": False } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags", "elasticloadbalancing:RemoveTags" ], "Resource": [ "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*" ] }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:ModifyLoadBalancerAttributes", "elasticloadbalancing:SetIpAddressType", "elasticloadbalancing:SetSecurityGroups", "elasticloadbalancing:SetSubnets", "elasticloadbalancing:DeleteLoadBalancer", "elasticloadbalancing:ModifyTargetGroup", "elasticloadbalancing:ModifyTargetGroupAttributes", "elasticloadbalancing:DeleteTargetGroup" ], "Resource": "*", "Condition": { "Null": { "aws:ResourceTag/elbv2.k8s.aws/cluster": False } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:RegisterTargets", "elasticloadbalancing:DeregisterTargets" ], "Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:SetWebAcl", "elasticloadbalancing:ModifyListener", "elasticloadbalancing:AddListenerCertificates", "elasticloadbalancing:RemoveListenerCertificates", "elasticloadbalancing:ModifyRule" ], "Resource": "*" }] } self.custom_policy_document = iam.PolicyDocument.from_json( self.policy_document) self.new_managed_policy = iam.ManagedPolicy( self, "LBControlPolicy", document=self.custom_policy_document) self.lb_role = iam.Role( self, "LBControllerRole", assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"), managed_policies=[self.new_managed_policy]) string_eq = core.CfnJson( self, "ConditionJsonEq", value={ f"{self.cluster.cluster_open_id_connect_issuer}:sub": f"system:serviceaccount:kube-system:aws-load-balancer-controller" }) self.lb_role.assume_role_policy.add_statements( iam.PolicyStatement(effect=iam.Effect.ALLOW, actions=["sts:AssumeRoleWithWebIdentity"], principals=[ iam.OpenIdConnectPrincipal( self.cluster.open_id_connect_provider, conditions={"StringEquals": string_eq}) ])) # Service Account self.lb_svc_acct = self.cluster.add_manifest( "lb_svc_acct", { "apiVersion": "v1", "kind": "ServiceAccount", "metadata": { "labels": { "app.kubernetes.io/component": "controller", "app.kubernetes.io/name": "aws-load-balancer-controller" }, "name": "aws-load-balancer-controller", "namespace": "kube-system", "annotations": { "eks.amazonaws.com/role-arn": self.lb_role.role_arn } }, }) # Helm chart self.cluster.add_helm_chart( "lbcontroller", chart="aws-load-balancer-controller", repository="https://aws.github.io/eks-charts", release="aws-load-balancer-controller", namespace="kube-system", values={ "clusterName": self.cluster.cluster_name, "region": self.region, "vpcId": self.vpc.vpc_id, "serviceAccount": { "create": False, "name": "aws-load-balancer-controller" } }, wait=True)