internal LogSourceStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { var logGroupName = new CfnParameter(this, "LogGroupName", new CfnParameterProps { Type = "String", Description = "The name of the CloudWatch Log Group Name to apply the subscription." }); if (!string.IsNullOrEmpty(logGroupName.ValueAsString)) { Console.WriteLine("LogDestinationArn: ----------- " + logGroupName.ValueAsString); } _logGroupName = logGroupName.ValueAsString; var logDestinationArn = new CfnParameter(this, "LogDestinationArn", new CfnParameterProps { Type = "String", Description = "The ARN of the LogDestination." }); if (!string.IsNullOrEmpty(logDestinationArn.ValueAsString)) { Console.WriteLine("LogGroupName: ----------- " + logDestinationArn.ValueAsString); } _logDestinationArn = logDestinationArn.ValueAsString; AddLogSubscription(); }
internal InfraStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { var stackProps = props as InfraStackProps; var imageTag = new CfnParameter(this, "ImageTag", new CfnParameterProps { Type = "String", Default = "latest", Description = "The tag of the image that needs to be deployed to the lambda" }); var dockerImageCode = DockerImageCode.FromEcr(Repository.FromRepositoryName( this, stackProps.EcrRepoName, stackProps.EcrRepoName ), new EcrImageCodeProps { Tag = imageTag.ValueAsString }); var lambda = new DockerImageFunction(this, "TimesheetApi", new DockerImageFunctionProps { FunctionName = "TimesheetApi", Code = dockerImageCode, Description = "Timesheet API", Timeout = Duration.Seconds(10), }); // DynamoDb Table var table = new Table(this, "Timesheet", new TableProps { TableName = "Timesheet", PartitionKey = new Attribute { Name = "Id", Type = AttributeType.STRING }, SortKey = new Attribute { Name = "Day", Type = AttributeType.STRING } }); // Assign permission to lambda to access the Timesheet Table lambda.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { Actions = new[] { "dynamodb:*" }, Resources = new[] { table.TableArn } })); }
internal LogDestinationStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { this.DestinationAccountId = props.Env.Account; var sourceAcctNumParam = new CfnParameter(this, "SourceAccountNumber", new CfnParameterProps { Description = "Account Number which is given access to push the logs." }); if (!string.IsNullOrEmpty(sourceAcctNumParam.ValueAsString)) { Console.WriteLine("SourceAccountNumber: ----------- " + sourceAcctNumParam.ValueAsString); } this.SourceLogAccountId = sourceAcctNumParam.ValueAsString ?? props.Env.Account; CreateLogBucket(); CreateLogConsumerResources(); }
public ApplicationStack(Construct scope, string id, HackatonStackProperties props) : base(scope, id, props) { var environmentName = new CfnParameter(this, "EnvironmentName", new CfnParameterProps { Type = "String", Default = "", Description = "The name of the environment to push the resources in" }); Props = props; CreateS3Bucket(environmentName.ValueAsString); CreateEventsTable(environmentName.ValueAsString); CreateParticipantsTable(environmentName.ValueAsString); CreateBackersTable(environmentName.ValueAsString); CreateBackerNotifyParticipantFinishedQueue(environmentName.ValueAsString); }
internal AutoScaledInstances( CdkStack stack, CfnParameter targetPlatform, Vpc vpc, bool publicAccess, SecurityGroup albSecurityGroup, SecurityGroup instanceSecurityGroup, Database database = null, Policy policy = null, ApplicationLoadBalancer restApiLoadBalancer = null) { IMachineImage selectedImage; bool targetWindows = false; if (targetWindows) { var userData = UserData.ForWindows(); userData.AddCommands( "New-Item -Path c:\\temp -ItemType Directory -Force", $"Read-S3Object -BucketName aws-codedeploy-{stack.Region}/latest -Key codedeploy-agent.msi -File c:\\temp\\codedeploy-agent.msi", "Start-Process -Wait -FilePath c:\\temp\\codedeploy-agent.msi -WindowStyle Hidden" ); selectedImage = new WindowsImage( WindowsVersion.WINDOWS_SERVER_2019_ENGLISH_CORE_BASE, new WindowsImageProps { UserData = userData } ); } else { var userData = UserData.ForLinux(new LinuxUserDataOptions { Shebang = "#!/bin/bash -xe" }); userData.AddCommands( "exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1", "yum install -y aws-cli ruby jq", "yum -y update", "cd /tmp/", $"curl -O https://aws-codedeploy-{stack.Region}.s3.amazonaws.com/latest/install", "chmod +x ./install", "if ./install auto; then", " echo \"CodeDeploy Agent installation completed successfully!\"", " exit 0", "else", " echo \"CodeDeploy Agent installation failed, please investigate.\"", " rm -f /tmp/install", " exit 1", "fi", "rm -rf /tmp/*" ); selectedImage = new AmazonLinuxImage(new AmazonLinuxImageProps { Edition = AmazonLinuxEdition.STANDARD, Virtualization = AmazonLinuxVirt.HVM, Generation = AmazonLinuxGeneration.AMAZON_LINUX_2, Storage = AmazonLinuxStorage.EBS, UserData = userData }); }; var alb = new ApplicationLoadBalancer(stack, $"ApplicationLoadBalancer-{(publicAccess ? "public" : "private")}", new ApplicationLoadBalancerProps { InternetFacing = publicAccess, Vpc = vpc, VpcSubnets = new SubnetSelection { SubnetType = publicAccess ? SubnetType.PUBLIC : SubnetType.PRIVATE }, SecurityGroup = albSecurityGroup, IpAddressType = IpAddressType.IPV4, Http2Enabled = true }); var albTargetGroup = new ApplicationTargetGroup(stack, $"ApplicationTargetGroup-{(publicAccess ? "public" : "private")}", new ApplicationTargetGroupProps { Vpc = vpc, Port = 80, Protocol = ApplicationProtocol.HTTP, TargetType = TargetType.INSTANCE, HealthCheck = new Amazon.CDK.AWS.ElasticLoadBalancingV2.HealthCheck { Timeout = Duration.Seconds(5), Interval = Duration.Seconds(10), HealthyThresholdCount = 2 } }); var albListener = new ApplicationListener(stack, $"ApplicationListener-{(publicAccess ? "public" : "private")}", new ApplicationListenerProps { Port = 80, Protocol = ApplicationProtocol.HTTP, DefaultAction = ListenerAction.Forward(new[] { albTargetGroup }), LoadBalancer = alb }); var asg = new AutoScalingGroup(stack, $"ASG-{(publicAccess ? "public" : "private")}", new AutoScalingGroupProps { Vpc = vpc, MinCapacity = 2, InstanceType = InstanceType.Of(InstanceClass.BURSTABLE3, InstanceSize.MEDIUM), MachineImage = selectedImage, BlockDevices = new[] { new Amazon.CDK.AWS.AutoScaling.BlockDevice() { DeviceName = "/dev/xvda", Volume = Amazon.CDK.AWS.AutoScaling.BlockDeviceVolume.Ebs( targetWindows ? 30: 8, new Amazon.CDK.AWS.AutoScaling.EbsDeviceOptions { VolumeType = Amazon.CDK.AWS.AutoScaling.EbsDeviceVolumeType.GP2, DeleteOnTermination = true } ) } }, AssociatePublicIpAddress = false, VpcSubnets = new SubnetSelection { SubnetType = SubnetType.PRIVATE } }); if (policy != null) { asg.Role.AttachInlinePolicy(policy); } asg.Role.AddToPrincipalPolicy( new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Actions = new[] { "ec2:DescribeTags" }, Resources = new[] { "*" } }) ); asg.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonSSMManagedInstanceCore")); asg.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AWSXRayDaemonWriteAccess")); asg.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("CloudWatchAgentServerPolicy")); Tag.Add(asg, "Application", stack.StackName); if (publicAccess) { Tag.Add(asg, "ApplicationRole", "Front End"); Tag.Add(asg, "RESTAPIAddress", restApiLoadBalancer.LoadBalancerDnsName); } else { Tag.Add(asg, "ApplicationRole", "REST API"); } if (database != null) { asg.Node.AddDependency(database.DatabaseResource); Tag.Add(asg, "DBSecretArn", database.Password.SecretArn); } // Enable access from the ALB asg.AddSecurityGroup(instanceSecurityGroup); Result = new LoadBalancedInstancesResult { AutoScalingGroup = asg, TargetGroup = albTargetGroup, LoadBalancer = alb }; }
internal CICD( CdkStack stack, CfnParameter targetPlatform, LoadBalancedInstancesResult frontEndInstanceInfo, LoadBalancedInstancesResult restAPIInstanceInfo) { var artifactBucket = new Bucket(stack, "ArtifactBucket"); var repo = new Repository(stack, "ApplicationRepository", new RepositoryProps { RepositoryName = stack.StackName, Description = $"Contains the code for the {stack.StackName} application." }); var cfnRepo = repo.Node.DefaultChild as Amazon.CDK.AWS.CodeCommit.CfnRepository; cfnRepo.Code = new CfnRepository.CodeProperty { S3 = new CfnRepository.S3Property { Bucket = SourceBucketName, Key = SourceBucketKey } }; var build = new PipelineProject(stack, "ApplicationBuild", new PipelineProjectProps { Environment = new BuildEnvironment { BuildImage = LinuxBuildImage.AMAZON_LINUX_2_3, EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable> { { "TARGET_OS", new BuildEnvironmentVariable { Type = BuildEnvironmentVariableType.PLAINTEXT, Value = targetPlatform.Value } } } } }); var frontEndApplication = new ServerApplication(stack, "FrontEnd", new ServerApplicationProps { ApplicationName = $"{stack.StackName}-FrontEnd" }); var frontEndDeploymentGroup = new ServerDeploymentGroup(stack, "FrontEndDeploymentGroup", new ServerDeploymentGroupProps { Application = frontEndApplication, DeploymentGroupName = $"{stack.StackName.ToLower()}-frontend-deployment-group", //Role = new Role(stack, "DeploymentServiceRole", new RoleProps //{ // AssumedBy = new ServicePrincipal("codedeploy.amazonaws.com"), // Description = "Allows Application Deployment.", // ManagedPolicies = new[] { ManagedPolicy.FromAwsManagedPolicyName("service-role/AWSCodeDeployRole") } //}), //AutoRollback = new AutoRollbackConfig { FailedDeployment = true }, //DeploymentConfig = ServerDeploymentConfig.HALF_AT_A_TIME, LoadBalancer = LoadBalancer.Application(frontEndInstanceInfo.TargetGroup), AutoScalingGroups = new[] { frontEndInstanceInfo.AutoScalingGroup } }); var restApiApplication = new ServerApplication(stack, "RestAPI", new ServerApplicationProps { ApplicationName = $"{stack.StackName}-RESTAPI" }); var restApiDeploymentGroup = new ServerDeploymentGroup(stack, "RestAPIDeploymentGroup", new ServerDeploymentGroupProps { Application = restApiApplication, DeploymentGroupName = $"{stack.StackName.ToLower()}-restapi-deployment-group", //AutoRollback = new AutoRollbackConfig { FailedDeployment = true }, //DeploymentConfig = ServerDeploymentConfig.HALF_AT_A_TIME, LoadBalancer = LoadBalancer.Application(restAPIInstanceInfo.TargetGroup), AutoScalingGroups = new[] { restAPIInstanceInfo.AutoScalingGroup } }); var sourceOutput = new Artifact_(); var frontEndArtifacts = new Artifact_("FrontEndOutput"); var restAPIArtifacts = new Artifact_("RESTAPIOutput"); var pipeline = new Pipeline(stack, "ApplicationPipeline", new PipelineProps { ArtifactBucket = artifactBucket, PipelineName = $"{stack.StackName}-Pipeline", Stages = new[] { new Amazon.CDK.AWS.CodePipeline.StageProps { StageName = "Source", Actions = new [] { new CodeCommitSourceAction(new CodeCommitSourceActionProps { ActionName = "Source", Repository = repo, Output = sourceOutput }) } }, new Amazon.CDK.AWS.CodePipeline.StageProps { StageName = "Build", Actions = new [] { new CodeBuildAction(new CodeBuildActionProps { ActionName = "CodeBuild", Project = build, Input = sourceOutput, Outputs = new [] { frontEndArtifacts, restAPIArtifacts } }) } }, new Amazon.CDK.AWS.CodePipeline.StageProps { StageName = "Deploy", Actions = new [] { new CodeDeployServerDeployAction(new CodeDeployServerDeployActionProps { ActionName = "DeployFrontEnd", DeploymentGroup = frontEndDeploymentGroup, Input = frontEndArtifacts }), new CodeDeployServerDeployAction(new CodeDeployServerDeployActionProps { ActionName = "DeployRESTAPI", DeploymentGroup = restApiDeploymentGroup, Input = restAPIArtifacts }) } } } }); }
internal PipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { var stackProps = props as PipelineStackProps; var codestarArn = $"arn:aws:codestar-connections:us-east-1:{this.Account}:connection/{stackProps.CodeStarConnectionId}"; var encryptionKey = Key.FromKeyArn(this, "encryptionKey", $"arn:aws:kms:{this.Region}:{this.Account}:key/{stackProps.KMSKeyId}"); var sourceArtifact = Bucket.FromBucketAttributes(this, "sourceArtifact", new BucketAttributes { BucketArn = $"arn:aws:s3:::codepipeline-artifacts-{this.Account}-{this.Region}", EncryptionKey = encryptionKey }); var pipelineRole = Role.FromRoleArn(this, "pipelineRole", $"arn:aws:iam::{this.Account}:role/CodePipelineMasterRole", new FromRoleArnOptions { Mutable = false } ); var sourceOutputArtifact = new Artifact_(); var cdkBuildOutput = new Artifact_("CdkBuildOutput"); var apiName = new CfnParameter(this, "ApiName", new CfnParameterProps { Type = "String", Description = "The name of the API" }); var apiNameLower = new CfnParameter(this, "ApiNameLower", new CfnParameterProps { Type = "String", Description = "The name of the API in Lowercase" }); // // Create the pipeline // var pipeline = new Pipeline(this, $"ApiPipeline", new PipelineProps { PipelineName = $"{apiName.ValueAsString}ApiPipeline", ArtifactBucket = sourceArtifact, Role = pipelineRole, Stages = new[] { new Amazon.CDK.AWS.CodePipeline.StageProps { StageName = "Source", Actions = new [] { new CodeStarConnectionsSourceAction(new CodeStarConnectionsSourceActionProps { ActionName = "Github", Branch = "main", Output = sourceOutputArtifact, Owner = "kumaranbsundar", Repo = stackProps.RepoName, TriggerOnPush = true, ConnectionArn = codestarArn, Role = pipelineRole, VariablesNamespace = "SourceVariables" }) } }, new Amazon.CDK.AWS.CodePipeline.StageProps { StageName = "Build", Actions = new [] { new CodeBuildAction(new CodeBuildActionProps { ActionName = "CDK_Synth", Project = GetCdkBuildProject(encryptionKey, pipelineRole), Input = sourceOutputArtifact, Outputs = new[] { cdkBuildOutput }, Role = pipelineRole, EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable> { { "API_NAME", new BuildEnvironmentVariable { Type = BuildEnvironmentVariableType.PLAINTEXT, Value = apiNameLower.ValueAsString } } } }) } } } }); stackProps.DeployEnvs.ToList().ForEach(de => { var crossAccountRole = Role.FromRoleArn(this, "crossAccountRole", $"arn:aws:iam::{de.AccountId}:role/CodePipelineCrossAccountRole", new FromRoleArnOptions { Mutable = false } ); var deploymentRole = Role.FromRoleArn(this, "deploymentRole", $"arn:aws:iam::{de.AccountId}:role/CodePipelineCfnDeploymentRole", new FromRoleArnOptions { Mutable = false } ); pipeline.AddStage(GetPipelineStage( de, apiNameLower.ValueAsString, cdkBuildOutput, crossAccountRole, deploymentRole, pipelineRole, sourceOutputArtifact, GetContainerBuildProject(encryptionKey, pipelineRole) )); }); }
internal CdkStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { var targetPlatform = new CfnParameter(this, "TargetPlatform", new CfnParameterProps { AllowedValues = new[] { "Linux", "Windows" }, Type = "String", Default = "Linux" }); var vpc = new Vpc(this, "VPC", new VpcProps { Cidr = "10.0.0.0/16", MaxAzs = 2, NatGatewayProvider = NatProvider.Gateway(), NatGateways = 2, NatGatewaySubnets = new SubnetSelection { SubnetType = SubnetType.PUBLIC, OnePerAz = true }, SubnetConfiguration = new[] { new SubnetConfiguration { CidrMask = 24, Name = "PublicSubnet", SubnetType = SubnetType.PUBLIC }, new SubnetConfiguration { CidrMask = 24, Name = "PrivateSubnet", SubnetType = SubnetType.PRIVATE }, } }); var externalLoadBalancerSecurityGroup = new SecurityGroup(vpc, "ExternalLoadBalancerSecurityGroup", new SecurityGroupProps { Vpc = vpc, Description = "Allows HTTP access to the application." }); externalLoadBalancerSecurityGroup.AddIngressRule(externalLoadBalancerSecurityGroup, Port.Tcp(80), "Allow HTTP"); var frontEndSecurityGroup = new SecurityGroup(vpc, "UISecurityGroup", new SecurityGroupProps { Vpc = vpc, Description = "Allows HTTP access to the UI." }); frontEndSecurityGroup.AddIngressRule(externalLoadBalancerSecurityGroup, Port.Tcp(80), "Allow HTTP"); var internalLoadBalancerSecurityGroup = new SecurityGroup(vpc, "InternalLoadBalancerSecurityGroup", new SecurityGroupProps { Vpc = vpc, Description = "Allows HTTP access to the REST API." }); internalLoadBalancerSecurityGroup.AddIngressRule(frontEndSecurityGroup, Port.Tcp(80)); var restApiSecurityGroup = new SecurityGroup(vpc, "ApiSecurityGroup", new SecurityGroupProps { Vpc = vpc, Description = "Allows HTTP access to the Rest API." }); restApiSecurityGroup.AddIngressRule(internalLoadBalancerSecurityGroup, Port.Tcp(80)); var db = new Database(this, vpc, restApiSecurityGroup); var policy = new Amazon.CDK.AWS.IAM.Policy(this, "DBPasswordSecretAccess", new Amazon.CDK.AWS.IAM.PolicyProps { PolicyName = "AllowPasswordAccess", Statements = new[] { new Amazon.CDK.AWS.IAM.PolicyStatement(new Amazon.CDK.AWS.IAM.PolicyStatementProps { Effect = Amazon.CDK.AWS.IAM.Effect.ALLOW, Actions = new [] { "secretsmanager:GetSecretValue" }, Resources = new [] { db.Password.SecretArn } }) } }); var restApiInstances = new AutoScaledInstances(this, targetPlatform, vpc, false, internalLoadBalancerSecurityGroup, restApiSecurityGroup, db, policy: policy); var frontEndInstances = new AutoScaledInstances(this, targetPlatform, vpc, true, externalLoadBalancerSecurityGroup, frontEndSecurityGroup, restApiLoadBalancer: restApiInstances.Result.LoadBalancer); //var instances = new AutoScaledInstances(this, targetPlatform, vpc, appSecurityGroup); new CICD(this, targetPlatform, frontEndInstances.Result, restApiInstances.Result); }
public ApiStack(Construct parent, string id, IApiStackProps props) : base(parent, id, props) { var cluster = new Cluster( this, "Example", new ClusterProps { Vpc = props.Vpc, }); var logging = new AwsLogDriver(new AwsLogDriverProps { StreamPrefix = "Example", }); var taskDef = new FargateTaskDefinition( this, "Task", new FargateTaskDefinitionProps { MemoryLimitMiB = 512, Cpu = 256, }); var repo = Repository.FromRepositoryName( this, "EcrRepository", props.Repository.RepositoryName); var imageTag = new CfnParameter( this, props.ApiImageTag, new CfnParameterProps { Default = "latest", }); var container = new ContainerDefinition( this, "ApiContainer", new ContainerDefinitionProps { TaskDefinition = taskDef, Image = ContainerImage.FromEcrRepository(repo, imageTag.ValueAsString), Logging = logging, }); container.AddPortMappings(new PortMapping { ContainerPort = 80, HostPort = 80, Protocol = Amazon.CDK.AWS.ECS.Protocol.TCP, }); var loadBalancer = new ApplicationLoadBalancer( this, "LoadBalancer", new ApplicationLoadBalancerProps { Vpc = props.Vpc, Http2Enabled = false, IdleTimeout = Duration.Seconds(5), InternetFacing = true, IpAddressType = IpAddressType.IPV4, VpcSubnets = new SubnetSelection { Subnets = props.Vpc.PublicSubnets, }, }); var ecsService = new ApplicationLoadBalancedFargateService( this, "Service", new ApplicationLoadBalancedFargateServiceProps { Cluster = cluster, TaskDefinition = taskDef, AssignPublicIp = false, PublicLoadBalancer = true, LoadBalancer = loadBalancer, }); PrintLoadBalancerDnsName(ecsService); }