public EcsStack(Construct parent, string id, EcsStackProps props) : base(parent, id) { this.ecsCluster = new Cluster(this, "Cluster", new ClusterProps { Vpc = props.Vpc, }); this.ecsCluster.Connections.AllowFromAnyIpv4(Port.Tcp(8080)); Console.Write(props.ecrRepository.RepositoryArn); this.ecsService = new NetworkLoadBalancedFargateService(this, "Service", new NetworkLoadBalancedFargateServiceProps() { Cluster = this.ecsCluster, DesiredCount = 1, PublicLoadBalancer = true, TaskImageOptions = new NetworkLoadBalancedTaskImageOptions { EnableLogging = true, ContainerPort = 8080, Image = ContainerImage.FromEcrRepository(props.ecrRepository), } } ); this.ecsService.Service.Connections.AllowFrom(Peer.Ipv4(props.Vpc.VpcCidrBlock), Port.Tcp(8080)); var taskDefinitionPolicy = new PolicyStatement(); taskDefinitionPolicy.AddActions( // Rules which allow ECS to attach network interfaces to instances // on your behalf in order for awsvpc networking mode to work right "ec2:AttachNetworkInterface", "ec2:CreateNetworkInterface", "ec2:CreateNetworkInterfacePermission", "ec2:DeleteNetworkInterface", "ec2:DeleteNetworkInterfacePermission", "ec2:Describe*", "ec2:DetachNetworkInterface", // Rules which allow ECS to update load balancers on your behalf // with the information sabout how to send traffic to your containers "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", "elasticloadbalancing:DeregisterTargets", "elasticloadbalancing:Describe*", "elasticloadbalancing:RegisterInstancesWithLoadBalancer", "elasticloadbalancing:RegisterTargets", // Rules which allow ECS to run tasks that have IAM roles assigned to them. "iam:PassRole", // Rules that let ECS create and push logs to CloudWatch. "logs:DescribeLogStreams", "logs:CreateLogGroup"); taskDefinitionPolicy.AddAllResources(); this.ecsService.Service.TaskDefinition.AddToExecutionRolePolicy( taskDefinitionPolicy ); var taskRolePolicy = new PolicyStatement(); taskRolePolicy.AddActions( // Allow the ECS Tasks to download images from ECR "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", // Allow the ECS tasks to upload logs to CloudWatch "logs:CreateLogStream", "logs:CreateLogGroup", "logs:PutLogEvents" ); taskRolePolicy.AddAllResources(); this.ecsService.Service.TaskDefinition.AddToTaskRolePolicy( taskRolePolicy ); }
public XRayStack(Construct parent, string id) : base(parent, id) { var table = new Table(this, "Table", new TableProps() { TableName = "MysfitsQuestionsTable", PartitionKey = new Attribute { Name = "QuestionId", Type = AttributeType.STRING }, Stream = StreamViewType.NEW_IMAGE }); var postQuestionLambdaFunctionPolicyStmDDB = new PolicyStatement(); postQuestionLambdaFunctionPolicyStmDDB.AddActions("dynamodb:PutItem"); postQuestionLambdaFunctionPolicyStmDDB.AddResources(table.TableArn); var LambdaFunctionPolicyStmXRay = new PolicyStatement(); LambdaFunctionPolicyStmXRay.AddActions( // Allows the Lambda function to interact with X-Ray "xray:PutTraceSegments", "xray:PutTelemetryRecords", "xray:GetSamplingRules", "xray:GetSamplingTargets", "xray:GetSamplingStatisticSummaries" ); LambdaFunctionPolicyStmXRay.AddAllResources(); var mysfitsPostQuestion = new Function(this, "PostQuestionFunction", new FunctionProps { Handler = "mysfitsPostQuestion.postQuestion", Runtime = Runtime.PYTHON_3_6, Description = "A microservice Lambda function that receives a new question submitted to the MythicalMysfits website from a user and inserts it into a DynamoDB database table.", MemorySize = 128, Code = Code.FromAsset("../../lambda-questions/PostQuestionsService"), Timeout = Duration.Seconds(30), InitialPolicy = new[] { postQuestionLambdaFunctionPolicyStmDDB, LambdaFunctionPolicyStmXRay }, Tracing = Tracing.ACTIVE }); var topic = new Topic(this, "Topic", new TopicProps { DisplayName = "MythicalMysfitsQuestionsTopic", TopicName = "MythicalMysfitsQuestionsTopic" }); topic.AddSubscription(new EmailSubscription("REPLACE@EMAIL_ADDRESS")); var postQuestionLambdaFunctionPolicyStmSNS = new PolicyStatement(); postQuestionLambdaFunctionPolicyStmSNS.AddActions("sns:Publish"); postQuestionLambdaFunctionPolicyStmSNS.AddResources(topic.TopicArn); var mysfitsProcessQuestionStream = new Function(this, "ProcessQuestionStreamFunction", new FunctionProps { Handler = "mysfitsProcessStream.processStream", Runtime = Runtime.PYTHON_3_6, Description = "An AWS Lambda function that will process all new questions posted to mythical mysfits" + " and notify the site administrator of the question that was asked.", MemorySize = 128, Code = Code.FromAsset("../../lambda-questions/ProcessQuestionsStream"), Timeout = Duration.Seconds(30), InitialPolicy = new[] { postQuestionLambdaFunctionPolicyStmSNS, LambdaFunctionPolicyStmXRay }, Tracing = Tracing.ACTIVE, Environment = new Dictionary <string, string>() { { "SNS_TOPIC_ARN", topic.TopicArn } }, Events = new IEventSource[] { new DynamoEventSource(table, new DynamoEventSourceProps { StartingPosition = StartingPosition.TRIM_HORIZON, BatchSize = 1 }) } }); var questionsApiRole = new Role(this, "QuestionsApiRole", new RoleProps { AssumedBy = new ServicePrincipal("apigateway.amazonaws.com") }); var apiPolicy = new PolicyStatement(); apiPolicy.AddActions("lambda:InvokeFunction"); apiPolicy.AddResources(mysfitsPostQuestion.FunctionArn); new Policy(this, "QuestionsApiPolicy", new PolicyProps { PolicyName = "questions_api_policy", Statements = new[] { apiPolicy }, Roles = new IRole[] { questionsApiRole } }); var questionsIntegration = new LambdaIntegration(mysfitsPostQuestion, new LambdaIntegrationOptions { CredentialsRole = questionsApiRole, IntegrationResponses = new IntegrationResponse[] { new IntegrationResponse() { StatusCode = "200", ResponseTemplates = new Dictionary <string, string> { { "application/json", "{\"status\":\"OK\"}" } } } } }); var api = new LambdaRestApi(this, "APIEndpoint", new LambdaRestApiProps { Handler = mysfitsPostQuestion, RestApiName = "Questions API Service", DeployOptions = new StageOptions { TracingEnabled = true }, Proxy = false }); var questionsMethod = api.Root.AddResource("questions"); questionsMethod.AddMethod("POST", questionsIntegration, new MethodOptions { MethodResponses = new MethodResponse[] { new MethodResponse { StatusCode = "200", ResponseParameters = new Dictionary <string, bool>() { { "method.response.header.Access-Control-Allow-Headers", true }, { "method.response.header.Access-Control-Allow-Methods", true }, { "method.response.header.Access-Control-Allow-Origin", true }, } } }, AuthorizationType = AuthorizationType.NONE }); questionsMethod.AddMethod("OPTIONS", new MockIntegration(new IntegrationOptions { IntegrationResponses = new IntegrationResponse[] { new IntegrationResponse { StatusCode = "200", ResponseParameters = new Dictionary <string, string> { { "method.response.header.Access-Control-Allow-Headers", "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'" }, { "method.response.header.Access-Control-Allow-Origin", "'*'" }, { "method.response.header.Access-Control-Allow-Credentials", "'false'" }, { "method.response.header.Access-Control-Allow-Methods", "'OPTIONS,GET,PUT,POST,DELETE'" } } } }, PassthroughBehavior = PassthroughBehavior.NEVER, RequestTemplates = new Dictionary <string, string> { { "application/json", "{\"statusCode\": 200}" } } }), new MethodOptions { MethodResponses = new MethodResponse[] { new MethodResponse { StatusCode = "200", ResponseParameters = new Dictionary <string, bool> { { "method.response.header.Access-Control-Allow-Headers", true }, { "method.response.header.Access-Control-Allow-Methods", true }, { "method.response.header.Access-Control-Allow-Credentials", true }, { "method.response.header.Access-Control-Allow-Origin", true } } } } } ); }
internal StepFunctionDemoStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { Bucket stepFunctionDemoBucket = new Bucket(this, "StepFunctionDemoBucket", new BucketProps { Encryption = BucketEncryption.S3_MANAGED, RemovalPolicy = RemovalPolicy.RETAIN }); Table stepFunctionDemoTable = new Table(this, "StepFunctionDemoTable", new TableProps { BillingMode = BillingMode.PROVISIONED, PartitionKey = new Amazon.CDK.AWS.DynamoDB.Attribute { Name = "Id", Type = AttributeType.STRING }, RemovalPolicy = RemovalPolicy.DESTROY }); //Step Function invoking Lambda function Function invokeOddEvenStepFunction = new Function(this, "InvokeOddEvenStepFunction", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::InvokeOddEvenStepFunction", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Lambda Function that invokes the Demo Step Function", }); //Function to calculate Odd or Even Function oddOrEvenFunction = new Function(this, "OddOrEvenFunction", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::OddOrEvenFunction", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Lambda Function that calculates odd or even", }); //Demo Lambda to perform Process 1 Function process1Function = new Function(this, "Process1Function", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process1Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs process1", }); Function processAFunction = new Function(this, "ProcessAFunction", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process1Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs process1", }); //Demo Lambda to perform Process 2 Function process2Function = new Function(this, "Process2Function", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process2Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs process2", }); //Demo Lambda to perform Process 1 Function process11Function = new Function(this, "Process11Function", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process11Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs job process1", }); //Demo Lambda to perform Process 2 Function process12Function = new Function(this, "Process12Function", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process12Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs job process2", }); Function taskTokenExecutorFunction = new Function(this, "TaskTokenExecutorFunction", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::TaskTokenExecutor", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that executes Task Token Step", Environment = new Dictionary <string, string>() { ["STEP_FUNCTION_DEMO_BUCKET"] = stepFunctionDemoBucket.BucketName } }); stepFunctionDemoBucket.GrantReadWrite(taskTokenExecutorFunction); var oddEvenFunction = new Task(this, "OddEvenFunction", new TaskProps { Task = new InvokeFunction(oddOrEvenFunction.LatestVersion) }); var process1 = new Task(this, "Process1", new TaskProps { Task = new InvokeFunction(process1Function.LatestVersion) }); var processA = new Task(this, "ProcessA", new TaskProps { Task = new InvokeFunction(processAFunction.LatestVersion) }); var process2 = new Task(this, "Process2", new TaskProps { Task = new InvokeFunction(process2Function.LatestVersion) }); var process11 = new Task(this, "Process11", new TaskProps { Task = new InvokeFunction(process11Function.LatestVersion), ResultPath = "$.Resolved" }); var process12 = new Task(this, "Process12", new TaskProps { Task = new InvokeFunction(process12Function.LatestVersion) }); var taskTokenExecutor = new Task(this, "TaskTokenExecutor", new TaskProps { Task = new RunLambdaTask(taskTokenExecutorFunction.LatestVersion, new RunLambdaTaskProps() { IntegrationPattern = ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, Payload = TaskInput.FromContextAt("$$.Task.Token") }), Parameters = new Dictionary <string, object> { ["Payload"] = new Dictionary <string, object> { ["TaskToken.$"] = "$$.Task.Token", ["State.$"] = "$" } } }); //Choice to go to Process 1 or Process 2 based on input number is odd or even. var isEven = new Choice(this, "Is the number Even?"); var isResolvedOrOverriden = new Choice(this, "Is Resolved Or Overriden?"); //var chain1 = Chain.Start(oddEvenFunction) // .Next(isEven // .When( // Condition.StringEquals("$.Result", "Even"), // Chain.Start(process1) // .Next(process11) // .Next(isResolvedOrOverriden // .When( // Condition.Or( // new[] // { // Condition.BooleanEquals("$.Resolved", true), // Condition.BooleanEquals("$.Override", true) // }), process12) // .Otherwise(process2))) // .When(Condition.StringEquals("$.Result", "Odd"), process2)); var chain1 = Chain.Start(oddEvenFunction) .Next(isEven .When( Condition.StringEquals("$.Result", "Even"), Chain.Start(process1) .Next(taskTokenExecutor) .Next(isResolvedOrOverriden .When( Condition.Or( new[] { Condition.BooleanEquals("$.Resolved", true), Condition.BooleanEquals("$.Override", true) }), process12) .Otherwise(process2))) .When(Condition.StringEquals("$.Result", "Odd"), process2)); //State Machine var stateMachine = new StateMachine(this, "JobDemoStateMachine", new StateMachineProps { StateMachineName = "JobDemoStateMachine", Timeout = Duration.Minutes(5), Definition = chain1 }); stateMachine.Role?.AddManagedPolicy(ManagedPolicy.FromManagedPolicyArn(this, "DynamoDBFullAccessForStepFunction", "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess")); stateMachine.Role?.AddManagedPolicy(ManagedPolicy.FromManagedPolicyArn(this, "LambdaFullAccessForStepFunction", "arn:aws:iam::aws:policy/AWSLambdaFullAccess")); var demofargateTask1 = new FargateTaskDefinition(this, "demoECSTask1Definition", new FargateTaskDefinitionProps { MemoryLimitMiB = 4096, Cpu = 2048 }); var demofargateTask2 = new FargateTaskDefinition(this, "demoECSTask2Definition", new FargateTaskDefinitionProps { MemoryLimitMiB = 4096, Cpu = 2048 }); stepFunctionDemoBucket.GrantReadWrite(demofargateTask2.TaskRole); IVpc publicVpc = Vpc.FromLookup(this, "PublicVPC", new VpcLookupOptions { Tags = new Dictionary <string, string> { ["Paces:VpcType"] = "Public" } }); var cluster = Cluster.FromClusterAttributes(this, "PublicCluster", new ClusterAttributes { ClusterName = "OHC-PACES", Vpc = publicVpc, SecurityGroups = new[] { SecurityGroup.FromSecurityGroupId(this, "SecurityGroup", "sg-0a1bab8166d8fb715") } }); var container1 = demofargateTask1.AddContainer("app", new ContainerDefinitionOptions { Image = ContainerImage.FromAsset(".", new AssetImageProps { File = "Dockerfile" }), Logging = LogDriver.AwsLogs(new AwsLogDriverProps { LogGroup = new LogGroup(this, "demoECSTask1LogGroup", new LogGroupProps { LogGroupName = "/ecs/demoECSTask1-" + RandomString.Generate(10, StackId), }), StreamPrefix = "logs" }), }); var container2 = demofargateTask2.AddContainer("app", new ContainerDefinitionOptions { Image = ContainerImage.FromAsset(".", new AssetImageProps { File = "Dockerfile.1" }), Environment = new Dictionary <string, string> { ["STEP_FUNCTION_DEMO_BUCKET"] = stepFunctionDemoBucket.BucketName }, Logging = LogDriver.AwsLogs(new AwsLogDriverProps { LogGroup = new LogGroup(this, "demoECSTask2LogGroup", new LogGroupProps { LogGroupName = $"/ecs/demoECSTask2-{RandomString.Generate(10, StackId)}", }), StreamPrefix = "logs" }) }); Rule rule = new Rule(this, "DemoJobRule", new RuleProps { Schedule = Schedule.Cron(new CronOptions { Day = "*", Hour = "*", Minute = "1", Month = "*", Year = "*" }), Description = "Runs demo job fargate task", Targets = new IRuleTarget[] { new EcsTask( new EcsTaskProps { Cluster = cluster, TaskDefinition = demofargateTask2, SubnetSelection = new SubnetSelection { OnePerAz = true } }) } }); //var ecsTask1 = new Task(this, "ecsTask1", new TaskProps //{ // InputPath = "$", // Task = new CustomTask(new RunEcsFargateTaskProps // { // Cluster = Cluster.FromClusterAttributes(this, "PublicCluster", new ClusterAttributes // { // ClusterName = "OHC-PACES", // Vpc = publicVpc, // SecurityGroups = new[] { SecurityGroup.FromSecurityGroupId(this, "SecurityGroup", "sg-0a1bab8166d8fb715") } // }), // TaskDefinition = fargateTask1, // ContainerOverrides = new[] // { // new ContainerOverride // { // ContainerDefinition = container, // Command = new []{"$.Data"} // }, // } // }) //}); var ecsTask1 = new Task(this, "EcsTask1", new TaskProps { InputPath = "$", Task = new RunEcsFargateTask(new RunEcsFargateTaskProps { Cluster = cluster, TaskDefinition = demofargateTask1, //ContainerOverrides = new[] //{ // new ContainerOverride // { // ContainerDefinition = container, // // }, //} }), Parameters = new Dictionary <string, object> { ["Overrides"] = new Dictionary <string, object> { ["ContainerOverrides"] = new Dictionary <string, string>[] { new Dictionary <string, string> { ["Name"] = "app", ["Command.$"] = "$.ECSPayload" } } } } }); var chain2 = Chain.Start(processA).Next(ecsTask1); var stateMachineWithTask = new StateMachine(this, "JobDemoStateMachine-1", new StateMachineProps { StateMachineName = "JobDemoStateMachine-1", Timeout = Duration.Minutes(15), Definition = chain2, Role = Role.FromRoleArn(this, "StateMachineWithTaskRole", "arn:aws:iam::342600918501:role/service-role/PacesEdi274DefaultStateMachineRole") }); //All Policies // 1. Invoke function policies invokeOddEvenStepFunction.Role?.AddManagedPolicy(ManagedPolicy.FromManagedPolicyArn(this, "InvokeLambdaPolicy", "arn:aws:iam::aws:policy/AWSLambdaFullAccess")); var policyStatement = new PolicyStatement { Sid = "CanInvokeStepFunctions", Effect = Effect.ALLOW }; policyStatement.AddActions(new[] { "states:StartExecution" }); invokeOddEvenStepFunction.AddToRolePolicy(policyStatement); policyStatement.AddResources(stateMachine.StateMachineArn); invokeOddEvenStepFunction.AddEnvironment(Functions.StateMachineArnKey, stateMachine.StateMachineArn); process12Function.AddEnvironment(Functions.StepFunctionDemoBucketKey, stepFunctionDemoBucket.BucketName); stepFunctionDemoBucket.GrantReadWrite(process12Function); var policyStatementDemofargateTask2 = new PolicyStatement { Sid = "CanNotifyStepFunction", Effect = Effect.ALLOW }; policyStatementDemofargateTask2.AddActions(new[] { "states:SendTask*" }); demofargateTask2.AddToExecutionRolePolicy(policyStatementDemofargateTask2); demofargateTask2.AddToTaskRolePolicy(policyStatementDemofargateTask2); policyStatementDemofargateTask2.AddAllResources(); }
public KinesisFirehoseStack(Construct parent, string id, KinesisFirehoseStackProps props) : base(parent, id, props) { var clicksDestinationBucket = new Bucket(this, "Bucket", new BucketProps { Versioned = true }); var firehoseDeliveryRole = new Role(this, "FirehoseDeliveryRole", new RoleProps { RoleName = "FirehoseDeliveryRole", AssumedBy = new ServicePrincipal("firehose.amazonaws.com"), ExternalIds = new string[] { Aws.ACCOUNT_ID } }); var firehoseDeliveryPolicyS3Stm = new PolicyStatement(); firehoseDeliveryPolicyS3Stm.AddActions("s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:PutObject"); firehoseDeliveryPolicyS3Stm.AddResources(clicksDestinationBucket.BucketArn); firehoseDeliveryPolicyS3Stm.AddResources(clicksDestinationBucket.ArnForObjects("*")); var lambdaFunctionPolicy = new PolicyStatement(); lambdaFunctionPolicy.AddActions("dynamodb:GetItem"); lambdaFunctionPolicy.AddResources(props.TableArn); var LambdaFunctionPolicyStmXRay = new PolicyStatement(); LambdaFunctionPolicyStmXRay.AddActions( // Allows the Lambda function to interact with X-Ray "xray:PutTraceSegments", "xray:PutTelemetryRecords", "xray:GetSamplingRules", "xray:GetSamplingTargets", "xray:GetSamplingStatisticSummaries" ); LambdaFunctionPolicyStmXRay.AddAllResources(); var mysfitsClicksProcessor = new Function(this, "Function", new FunctionProps { Handler = "streaming_lambda::streaming_lambda.function::FunctionHandlerAsync", Runtime = Runtime.DOTNET_CORE_2_1, Description = "An Amazon Kinesis Firehose stream processor that enriches click records" + " to not just include a mysfitId, but also other attributes that can be analyzed later.", MemorySize = 128, Code = Code.FromAsset("../lambda/stream/bin/Debug/netcoreapp2.1/Publish"), Timeout = Duration.Seconds(30), Tracing = Tracing.ACTIVE, InitialPolicy = new PolicyStatement[] { lambdaFunctionPolicy, LambdaFunctionPolicyStmXRay }, Environment = new Dictionary <string, string>() { { "mysfits_api_url", string.Format($"https://${props.APIid}.execute-api.{Amazon.CDK.Aws.REGION}.amazonaws.com/prod/") } } }); var firehoseDeliveryPolicyLambdaStm = new PolicyStatement(); firehoseDeliveryPolicyLambdaStm.AddActions("lambda:InvokeFunction"); firehoseDeliveryPolicyLambdaStm.AddResources(mysfitsClicksProcessor.FunctionArn); firehoseDeliveryRole.AddToPolicy(firehoseDeliveryPolicyS3Stm); firehoseDeliveryRole.AddToPolicy(firehoseDeliveryPolicyLambdaStm); var mysfitsFireHoseToS3 = new CfnDeliveryStream(this, "DeliveryStream", new CfnDeliveryStreamProps { ExtendedS3DestinationConfiguration = new CfnDeliveryStream.ExtendedS3DestinationConfigurationProperty() { BucketArn = clicksDestinationBucket.BucketArn, BufferingHints = new CfnDeliveryStream.BufferingHintsProperty { IntervalInSeconds = 60, SizeInMBs = 50 }, CompressionFormat = "UNCOMPRESSED", Prefix = "firehose/", RoleArn = firehoseDeliveryRole.RoleArn, ProcessingConfiguration = new CfnDeliveryStream.ProcessingConfigurationProperty { Enabled = true, Processors = new CfnDeliveryStream.ProcessorProperty[] { new CfnDeliveryStream.ProcessorProperty() { Type = "Lambda", Parameters = new CfnDeliveryStream.ProcessorParameterProperty { ParameterName = "LambdaArn", ParameterValue = mysfitsClicksProcessor.FunctionArn } } } } } }); new CfnPermission(this, "Permission", new CfnPermissionProps { Action = "lambda:InvokeFunction", FunctionName = mysfitsClicksProcessor.FunctionArn, Principal = "firehose.amazonaws.com", SourceAccount = Amazon.CDK.Aws.ACCOUNT_ID, SourceArn = mysfitsFireHoseToS3.AttrArn }); var clickProcessingApiRole = new Role(this, "ClickProcessingApiRole", new RoleProps { AssumedBy = new ServicePrincipal("apigateway.amazonaws.com") }); var apiPolicy = new PolicyStatement(); apiPolicy.AddActions("firehose:PutRecord"); apiPolicy.AddResources(mysfitsFireHoseToS3.AttrArn); new Policy(this, "ClickProcessingApiPolicy", new PolicyProps { PolicyName = "api_gateway_firehose_proxy_role", Statements = new PolicyStatement[] { apiPolicy }, Roles = new[] { clickProcessingApiRole } }); var api = new RestApi(this, "APIEndpoint", new RestApiProps { RestApiName = "ClickProcessing API Service", CloudWatchRole = false, EndpointTypes = new EndpointType[] { EndpointType.REGIONAL } }); var clicks = api.Root.AddResource("clicks"); clicks.AddMethod("PUT", new AwsIntegration(new AwsIntegrationProps { Service = "firehose", IntegrationHttpMethod = "POST", Action = "PutRecord", Options = new IntegrationOptions { ConnectionType = ConnectionType.INTERNET, CredentialsRole = clickProcessingApiRole, IntegrationResponses = new IntegrationResponse[] { new IntegrationResponse() { StatusCode = "200", ResponseTemplates = { { "application/json", "{\"status\":\"OK\"}" } }, ResponseParameters = { { "method.response.header.Access-Control-Allow-Headers", "'Content-Type'" }, { "method.response.header.Access-Control-Allow-Methods", "'OPTIONS,PUT'" }, { "method.response.header.Access-Control-Allow-Origin", "'*'" } } } }, RequestParameters = { { "integration.request.header.Content-Type", "'application/x-amz-json-1.1'" } }, RequestTemplates = { { "application/json", "{\"DeliveryStreamName\":\"" + mysfitsFireHoseToS3.Ref + "\", \"Record\": { \"Data\": \"$util.base64Encode($input.json('$'))\"}" } } } }), new MethodOptions { MethodResponses = new MethodResponse[] { new MethodResponse { StatusCode = "200", ResponseParameters = { { "method.response.header.Access-Control-Allow-Headers", true }, { "method.response.header.Access-Control-Allow-Methods", true }, { "method.response.header.Access-Control-Allow-Origin", true } } } } }); clicks.AddMethod("OPTIONS", new MockIntegration(new IntegrationOptions { IntegrationResponses = new IntegrationResponse[] { new IntegrationResponse { StatusCode = "200", ResponseParameters = new Dictionary <string, string> { { "method.response.header.Access-Control-Allow-Headers", "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'" }, { "method.response.header.Access-Control-Allow-Origin", "'*'" }, { "method.response.header.Access-Control-Allow-Credentials", "'false'" }, { "method.response.header.Access-Control-Allow-Methods", "'OPTIONS,GET,PUT,POST,DELETE'" } } } }, PassthroughBehavior = PassthroughBehavior.NEVER, RequestTemplates = new Dictionary <string, string> { { "application/json", "{\"statusCode\": 200}" } } }), new MethodOptions { MethodResponses = new MethodResponse[] { new MethodResponse { StatusCode = "200", ResponseParameters = new Dictionary <string, bool> { { "method.response.header.Access-Control-Allow-Headers", true }, { "method.response.header.Access-Control-Allow-Methods", true }, { "method.response.header.Access-Control-Allow-Credentials", true }, { "method.response.header.Access-Control-Allow-Origin", true } } } } }); }
public DynamoDbStack(Construct parent, string id, DynamoDbStackProps props) : base(parent, id, props) { var dynamoDbEndpoint = props.Vpc.AddGatewayEndpoint("DynamoDbEndpoint", new GatewayVpcEndpointOptions { Service = GatewayVpcEndpointAwsService.DYNAMODB }); var dynamoDbPolicy = new PolicyStatement(); dynamoDbPolicy.AddAnyPrincipal(); dynamoDbPolicy.AddActions("*"); dynamoDbPolicy.AddAllResources(); dynamoDbEndpoint.AddToPolicy( dynamoDbPolicy ); this.table = new Table(this, "Table", new TableProps { TableName = "MysfitsTable", PartitionKey = new Attribute { Name = "MysfitId", Type = AttributeType.STRING } }); this.table.AddGlobalSecondaryIndex(new GlobalSecondaryIndexProps { IndexName = "LawChaosIndex", PartitionKey = new Attribute { Name = "LawChaos", Type = AttributeType.STRING }, SortKey = new Attribute { Name = "MysfitId", Type = AttributeType.STRING }, ReadCapacity = 5, WriteCapacity = 5, ProjectionType = ProjectionType.ALL }); this.table.AddGlobalSecondaryIndex(new GlobalSecondaryIndexProps { IndexName = "GoodEvilIndex", PartitionKey = new Attribute { Name = "GoodEvil", Type = AttributeType.STRING }, SortKey = new Attribute { Name = "MysfitId", Type = AttributeType.STRING }, ReadCapacity = 5, WriteCapacity = 5, ProjectionType = ProjectionType.ALL }); var fargatePolicy = new PolicyStatement(); fargatePolicy.AddActions( // Allows the ECS tasks to interact with only the MysfitsTable in DynamoDB "dynamodb:Scan", "dynamodb:Query", "dynamodb:UpdateItem", "dynamodb:GetItem", "dynamodb:DescribeTable" ); fargatePolicy.AddResources( "arn:aws:dynamodb:*:*:table/MysfitsTable*" ); props.fargateService.TaskDefinition.AddToTaskRolePolicy( fargatePolicy ); }