// Asserts that the specified HostedZone is valid and represents the same // HostedZone that we initially created at the very start of this test. private void assertValidCreatedHostedZone(HostedZone hostedZone) { Assert.AreEqual(CALLER_REFERENCE, hostedZone.CallerReference); Assert.AreEqual(ZONE_NAME, hostedZone.Name); Assert.IsNotNull(hostedZone.Id); Assert.AreEqual(COMMENT, hostedZone.Config.Comment); }
public FrontendStack(Construct scope, string name, string url, StackProps props = null) : base(scope, $"frontend-{name}", props) { // pricing - hosted zone // 0,50 USD por zona hospedada/mês para as primeiras 25 zonas hospedadas // 0,10 USD por zona hospedada/mês para zonas hospedadas adicionais // Consultas padrão // 0,40 USD por milhão de consultas – primeiro 1 bilhão de consultas/mês // 0,20 USD por milhão de consultas – mais de 1 bilhão de consultas/mês // Consultas de roteamento baseado em latência // 0,60 USD por milhão de consultas – primeiro 1 bilhão de consultas/mês // 0,30 USD por milhão de consultas – mais de 1 bilhão de consultas/mês // Consultas de Geo DNS e geoproximidade // 0,70 USD por milhão de consultas -- primeiro 1 bilhão de consultas/mês // 0,35 USD por milhão de consultas -- mais de 1 bilhão de consultas/mês _bucket = new Bucket(this, $"frontend-{name}-bucket", new BucketProps() { BucketName = name + "72b302bf297a228a75730123efef7c41", WebsiteIndexDocument = "index.html", PublicReadAccess = true, RemovalPolicy = RemovalPolicy.DESTROY }); _bucketDeployment = new BucketDeployment(this, $"frontend-{name}-deployment", new BucketDeploymentProps() { Sources = new[] { Source.Asset("../tools/frontend/") }, DestinationBucket = _bucket, RetainOnDelete = false }); _hostedZone = new HostedZone(this, $"frontend-{name}-hostedzone", new HostedZoneProps { ZoneName = url }); _certificate = new Certificate(this, $"frontend-{name}-certificate", new CertificateProps { DomainName = url, Validation = CertificateValidation.FromDns(_hostedZone) }); _distribution = new Distribution(this, $"frontend-{name}-distribution", new DistributionProps { DefaultBehavior = new BehaviorOptions { Origin = new S3Origin(_bucket), ViewerProtocolPolicy = ViewerProtocolPolicy.REDIRECT_TO_HTTPS }, DomainNames = new[] { url }, Certificate = _certificate, DefaultRootObject = "index.html" }); _aRecord = new ARecord(this, $"frontend-{name}-arecord", new ARecordProps { Zone = _hostedZone, RecordName = url, Target = RecordTarget.FromAlias(new CloudFrontTarget(_distribution)) }); }
public IEnumerable <ResourceRecordSet> GetResourceRecordSets(HostedZone zone) { var request = new ListResourceRecordSetsRequest(zone.Id); ListResourceRecordSetsResponse response = _route53Client.ListResourceRecordSets(request); return(response.ResourceRecordSets); }
/// <summary> /// Retrieve the hosted zone for a specific domain. /// </summary> /// <param name="domain">The name of the domain</param> /// <param name="settings">The <see cref="Route53Settings"/> required to connect to Route53.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> public async Task <HostedZone> GetHostedZone(string domain, Route53Settings settings, CancellationToken cancellationToken = default(CancellationToken)) { if (String.IsNullOrEmpty(domain)) { throw new ArgumentNullException("domain"); } IList <HostedZone> zones = await this.GetHostedZones(settings); HostedZone zone = null; if (zones != null) { zone = zones.FirstOrDefault(z => z.Name == domain); } if (zone == null) { _Log.Error("Could not find a hosted zone with the domain {0}", domain); } return(zone); }
private static List <ResourceRecord> GetResourceRecords(IAwsClient awsClient, IEnumerable <StackResource> stackResources, AwsStack awsStack, string hostedZoneName) { var resourceRecords = new List <ResourceRecord>(); if (stackResources.Any(x => x.ResourceType == ResourceTypeConstants.RecordSet)) { string zoneName = hostedZoneName.Trim(new[] { '.' }); HostedZone hostedZone = awsClient.DnsService.GetHostedZoneByName(zoneName); IEnumerable <ResourceRecordSet> resourceRecordSets = awsClient.DnsService.GetResourceRecordSets(hostedZone); string nameFilter = string.Format("{0}.{1}", awsStack.StackName, zoneName); resourceRecords = resourceRecordSets .Where(x => x.Name.ToLower().Contains(nameFilter.ToLower())) .Select(x => new ResourceRecord { FullyQualifiedDomainName = x.Name, TimeToLive = (int)x.TTL, Type = x.Type, Values = x.ResourceRecords.Select(rr => rr.Value).ToList(), ResourceId = x.Name // resource records don't have an ID in AWS, but this is unique so it's good enough for now }).ToList(); } return(resourceRecords); }
private bool ApplyDnsChange(HostedZone zone, ResourceRecordSet recordSet, ChangeAction action) { // Prepare change as Batch Change changeDetails = new Change() { ResourceRecordSet = recordSet, Action = action }; ChangeBatch changeBatch = new ChangeBatch() { Changes = new List <Change> { changeDetails } }; // Prepare zone's resource record sets var recordsetRequest = new ChangeResourceRecordSetsRequest() { HostedZoneId = zone.Id, ChangeBatch = changeBatch }; logger.Debug($"Route53 :: ApplyDnsChange : ChangeResourceRecordSets: {recordsetRequest.ChangeBatch} "); var recordsetResponse = route53Client.ChangeResourceRecordSets(recordsetRequest); logger.Debug($"Route53 :: ApplyDnsChange : ChangeResourceRecordSets Response: {recordsetResponse} "); logger.Info("DNS change completed."); return(true); }
public void CreateHostedZoneByName() { Template template = StackTest.GetNewBlankTemplateWithVpc($"Vpc{this.TestContext.TestName}"); string hostedZoneName = $"{this.TestContext.TestName}{Guid.NewGuid().ToString().Replace("-", string.Empty)}.com"; HostedZone hz = new HostedZone(hostedZoneName); template.Resources.Add(hostedZoneName, hz); StackTest.CreateTestStack(template, this.TestContext); }
private ARecord AddRoute53Alias(string hostedZoneUrl, string applicationUrl, DomainName domainName) { return(new ARecord(stack, "Route53Alias", new ARecordProps { Zone = HostedZone.FromLookup(stack, "HostedZone", new HostedZoneProviderProps { DomainName = hostedZoneUrl }), RecordName = applicationUrl, Target = RecordTarget.FromAlias(new ApiGatewayv2Domain(domainName)) })); }
public void CreatePrivateHostedZone() { Template template = StackTest.GetNewBlankTemplateWithVpc($"VpcCreatePrivateHostedZone"); string hostedZoneName = $"{this.TestContext.TestName}{Guid.NewGuid().ToString().Replace("-", string.Empty)}"; HostedZone hz = new HostedZone("example.com"); template.Resources.Add(hostedZoneName, hz); hz.AddVpc(template.Vpcs.First(), Region.UsEast1); StackTest.CreateTestStack(template, this.TestContext); }
internal Stack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { //setup the image var asset = new DockerImageAsset(this, $"{Config.AppName}Image", new DockerImageAssetProps { Directory = Path.Combine(System.Environment.CurrentDirectory, "api"), }); //Create the Fargate service var vpc = Vpc.FromLookup( this, "sandbox", new VpcLookupOptions { VpcName = "sandbox_vpc" } ); var cluster = new Cluster(this, $"{Config.AppName}Cluster", new ClusterProps { Vpc = vpc }); var applicationDomain = $"{Config.ApplicationSubdomain}.{Config.DomainName}"; var hostedZone = HostedZone.FromLookup( this, "HostedZone", new HostedZoneProviderProps { DomainName = $"{Config.DomainName}.", PrivateZone = false } ); // Create a load-balanced Fargate service and make it public var fargateService = new ApplicationLoadBalancedFargateService(this, $"{Config.AppName}Service", new ApplicationLoadBalancedFargateServiceProps { Cluster = cluster, // Required DesiredCount = 1, // Default is 1 TaskImageOptions = new ApplicationLoadBalancedTaskImageOptions { Image = ContainerImage.FromDockerImageAsset(asset) }, MemoryLimitMiB = 1024, // Default is 256 PublicLoadBalancer = true, // Default is false DomainName = applicationDomain, DomainZone = hostedZone, } ); new CfnOutput( this, "Route53Url", new CfnOutputProps { Value = applicationDomain, Description = "Nice Route53 Url" } ); }
private async Task UpdateRoute53(HostedZone zone, Instance instance, ILambdaContext context) { if (zone == null) { return; } string hostName = instance.Tags.GetTag("HostName"); if (string.IsNullOrWhiteSpace(hostName)) { context.Logger.LogLine($"Hostname missing!"); return; } string ipAddress = instance.PublicIpAddress; if (string.IsNullOrWhiteSpace(ipAddress)) { context.Logger.LogLine($"ipAddress missing!"); return; } context.Logger.LogLine($"Update Zone: {zone.Name} host: {hostName} with IpAddress: {ipAddress}"); ChangeResourceRecordSetsRequest request = new ChangeResourceRecordSetsRequest { HostedZoneId = zone.Id, ChangeBatch = new ChangeBatch { Changes = new List <Change> { new Change { Action = ChangeAction.UPSERT, ResourceRecordSet = new ResourceRecordSet { Name = $"{hostName}.{zone.Name}", Type = "A", ResourceRecords = new List <ResourceRecord> { new ResourceRecord { Value = ipAddress } }, TTL = 60, } } } } }; await _amazonRoute53Client.ChangeResourceRecordSetsAsync(request); }
public async Task <string> GetHostedZoneIdByName(string hostedZoneName) { using (AmazonRoute53Client route53Client = GetAmazonRoute53Client()) { ListHostedZonesByNameResponse zones = await route53Client.ListHostedZonesByNameAsync(new ListHostedZonesByNameRequest() { DNSName = hostedZoneName }); HostedZone matchingZone = zones?.HostedZones.FirstOrDefault(zone => zone.Name == hostedZoneName); return(matchingZone?.Id); } }
public void Route53GetHostedZone() { #region to-get-information-about-a-hosted-zone-1481752361124 var response = client.GetHostedZone(new GetHostedZoneRequest { Id = "Z3M3LMPEXAMPLE" }); DelegationSet delegationSet = response.DelegationSet; HostedZone hostedZone = response.HostedZone; #endregion }
private async Task UpdateRoute53Entry(EC2InstanceStateChangeEvent cloudWatchEvent, ILambdaContext context) { Instance instance = await GetInstanceDetails(cloudWatchEvent.Detail.InstanceId, context); if (instance != null) { HostedZone zone = await GetZone(instance, context); await UpdateRoute53(zone, instance, context); } else { context.Logger.LogLine($"**** InstanceId Not Found: {cloudWatchEvent.Detail.InstanceId}"); } }
/// <summary> /// Instance is stopping /// /// Remove the route 53 entry for it. /// </summary> /// <param name="cloudWatchEvent"></param> /// <param name="context"></param> /// <returns></returns> private async Task RemoveRoute53Entry(EC2InstanceStateChangeEvent cloudWatchEvent, ILambdaContext context) { Instance instance = await GetInstanceDetails(cloudWatchEvent.Detail.InstanceId, context); if (instance != null) { HostedZone zone = await GetZone(instance, context); if (zone == null) { return; } await DeleteRoute53RecordSet(zone, instance, context); } }
private async Task <bool> ApplyDnsChange(HostedZone zone, ResourceRecordSet recordSet, ChangeAction action) { // prepare change var changeDetails = new Change() { ResourceRecordSet = recordSet, Action = action }; var changeBatch = new ChangeBatch() { Changes = new List <Change> { changeDetails } }; // Update the zone's resource record sets var recordsetRequest = new ChangeResourceRecordSetsRequest() { HostedZoneId = zone.Id, ChangeBatch = changeBatch }; _log?.Debug($"Route53 :: ApplyDnsChange : ChangeResourceRecordSetsAsync: {JsonConvert.SerializeObject(recordsetRequest.ChangeBatch)} "); var recordsetResponse = await _route53Client.ChangeResourceRecordSetsAsync(recordsetRequest); _log?.Debug($"Route53 :: ApplyDnsChange : ChangeResourceRecordSetsAsync Response: {JsonConvert.SerializeObject(recordsetResponse)} "); // Monitor the change status var changeRequest = new GetChangeRequest() { Id = recordsetResponse.ChangeInfo.Id }; while (ChangeStatus.PENDING == (await _route53Client.GetChangeAsync(changeRequest)).ChangeInfo.Status) { System.Diagnostics.Debug.WriteLine("DNS change is pending."); await Task.Delay(1500); } _log?.Information("DNS change completed."); return(true); }
private async static Task <string> GetHostedZoneIdByName(string hostedZoneName) { AmazonRoute53Config config = new AmazonRoute53Config() { RegionEndpoint = RegionEndpoint.GetBySystemName(Settings.AWSRegion) // TODO: inject }; using (AmazonRoute53Client route53Client = new AmazonRoute53Client(Settings.AWSAccessKeyId, Settings.AWSAccessKeySecret, config)) { ListHostedZonesByNameResponse zones = await route53Client.ListHostedZonesByNameAsync(new ListHostedZonesByNameRequest() { DNSName = hostedZoneName }); HostedZone matchingZone = zones?.HostedZones.FirstOrDefault(zone => zone.Name == hostedZoneName); return(matchingZone?.Id); } }
private static NetworkConfig GetNetworkConfig(Stack stack) { var result = new NetworkConfig(); result.Zone = HostedZone.FromLookup(stack, "Zone", new HostedZoneProviderProps { DomainName = baseDomainName }); result.Certificate = Certificate.FromCertificateArn(stack, "Certificate", "arn:aws:acm:us-east-1:249221827206:certificate/72c985a5-1576-4348-954b-34e4161d05f5"); //result.Certificate = new DnsValidatedCertificate(stack, "SiteCertificate", new DnsValidatedCertificateProps //{ // DomainName = $"*.{baseDomainName}", // HostedZone = result.Zone, // Region = "us-east-1" // Cloudfront only checks this region for certificates. //}); return(result); }
public void copyNsRecordsFromSubDomainToParentDomain(string fullSubDomainName, string parentName) { Task <ListHostedZonesResponse> ListOfHostedZones = listAwsHostedZonesAsync(); ListOfHostedZones.Wait(); HostedZone subZone = ListOfHostedZones.Result.HostedZones.Find(h => h.Name == $"{ fullSubDomainName }."); HostedZone parentZone = ListOfHostedZones.Result.HostedZones.Find(h => h.Name == $"{ parentName }."); Task <ListResourceRecordSetsResponse> getResourceRecords = getAwsResourceRecordsAsync(subZone.Id); getResourceRecords.Wait(); ResourceRecordSet rrs = getResourceRecords.Result.ResourceRecordSets.Find(r => r.Name == $"{ fullSubDomainName }." && r.Type == RRType.NS); Task <ChangeResourceRecordSetsResponse> ResourceResponse = createAws_NS_ResourceRecords(parentZone.Id, fullSubDomainName, rrs); ResourceResponse.Wait(); }
private async Task <IEnumerable <ResourceRecordSet> > FindRecordSetsAsync(HostedZone zone, string dnsName, string recordType) { _logger.LogDebug("Finding record sets for {RecordType} {DnsName} in zone {Zone}", recordType, dnsName, zone.Name); var result = new List <ResourceRecordSet>(); var rootedDnsName = dnsName.EndsWith(DomainSegmentSeparator.ToString()) ? dnsName : dnsName + DomainSegmentSeparator; var remainder = dnsName.Replace(zone.Name, String.Empty); var recordSets = await _route53Client.ListResourceRecordSetsAsync( new ListResourceRecordSetsRequest() { HostedZoneId = zone.Id, StartRecordType = RRType.FindValue(recordType), StartRecordName = dnsName }); do { foreach (var recordSet in recordSets.ResourceRecordSets) { if (recordSet.Name.ToLower().Equals(rootedDnsName.ToLower())) { result.Add(recordSet); } } recordSets = await _route53Client.ListResourceRecordSetsAsync( new ListResourceRecordSetsRequest() { HostedZoneId = zone.Id, StartRecordType = recordSets.NextRecordType, StartRecordName = recordSets.NextRecordName, StartRecordIdentifier = recordSets.NextRecordIdentifier }); } while (recordSets.IsTruncated); _logger.LogInformation("{Count} record sets were found for {RecordType} {DnsName} in zone {Zone}", result.Count, recordType, dnsName, zone.Name); return(result); }
public void RecordSetByNewHostZoneTest() { Template template = StackTest.GetNewBlankTemplateWithVpc($"Vpc{this.TestContext.TestName}"); HostedZone hz = new HostedZone("zeta.yadayada.software."); template.Resources.Add("hostedZoneRecordSetByNewHostZoneTest", hz); hz.AddVpc(template.Vpcs.First(), Region.UsEast1); var target = RecordSet.AddByHostedZone(template, "test", hz, "test.zeta.yadayada.software.", RecordSet.RecordSetTypeEnum.A); target.TTL = "60"; target.RecordSetType = RecordSet.RecordSetTypeEnum.A.ToString(); var DMZSubnet = new Subnet(template.Vpcs.First(), "10.0.0.0/20", AvailabilityZone.UsEast1A, true); template.Resources.Add("DMZSubnet", DMZSubnet); Instance testBox = new Instance(DMZSubnet, InstanceTypes.T2Micro, "ami-60b6c60a", OperatingSystem.Linux); template.Resources.Add("testbox", testBox); var eip = testBox.AddElasticIp(); target.AddResourceRecord(eip); StackTest.CreateTestStack(template, this.TestContext); }
public static async Task Create(this HostedZone zone, Credentials credentials) { var client = credentials.CreateClient(); //[3] Create a resource record set change batch var recordSet = new ResourceRecordSet { Name = zone.Name, TTL = 60, Type = RRType.A, ResourceRecords = new List <ResourceRecord> { new ResourceRecord { Value = "192.0.2.235" } } }; var change1 = new Change { ResourceRecordSet = recordSet, Action = ChangeAction.CREATE }; var changeBatch = new ChangeBatch { Changes = new List <Change> { change1 } }; //[4] Update the zone's resource record sets var recordsetRequest = new ChangeResourceRecordSetsRequest { HostedZoneId = zone.Id, ChangeBatch = changeBatch }; var recordsetResponse = client.ChangeResourceRecordSets(recordsetRequest); var status = await recordsetResponse.ChangeInfo.WaitForStatusAync(credentials); }
public ApiStack(Construct scope, string id, ApiProps props = null) : base(scope, id, props) { var hostedZone = HostedZone.FromHostedZoneAttributes(this, "HostedZone", new HostedZoneAttributes { ZoneName = props.HostedZoneName, HostedZoneId = props.HostedZoneId }); FargateService = new ApplicationLoadBalancedFargateService(this, $"{props.ServiceName}-fargate-service", new ApplicationLoadBalancedFargateServiceProps { ServiceName = props.ServiceName, Cluster = props.EcsCluster, TaskImageOptions = new ApplicationLoadBalancedTaskImageOptions { ContainerName = props.ServiceName, Image = ContainerImage.FromEcrRepository(props.EcrRepository), Environment = props.ContainerEnvVars, Secrets = props.ContainerSecrets, EnableLogging = true }, Certificate = props.Certificate, DomainName = $"{props.SubDomain}.{props.HostedZoneName}", DomainZone = hostedZone, //this has an internet-facing ALB open to the world - could enhance security by hiding behind an API gateway }); FargateService.TargetGroup.ConfigureHealthCheck(new HealthCheck { Path = "/health" }); ApiUrl = $"https://{props.SubDomain}.{props.HostedZoneName}"; //seems handy https://github.com/aws/aws-cdk/issues/8352 //also handy https://chekkan.com/iam-policy-perm-for-public-load-balanced-ecs-fargate-on-cdk/ }
// Asserts that the specified HostedZone is valid and represents the same // HostedZone that we initially created at the very start of this test. private void assertValidCreatedHostedZone(HostedZone hostedZone) { Assert.AreEqual(ZONE_NAME, hostedZone.Name); Assert.IsNotNull(hostedZone.Id); Assert.AreEqual(COMMENT, hostedZone.Config.Comment); }
internal CdkStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { var stackProps = ReportStackProps.ParseOrDefault(props); var dframeWorkerLogGroup = "MagicOnionBenchWorkerLogGroup"; var dframeMasterLogGroup = "MagicOnionBenchMasterLogGroup"; var benchNetwork = stackProps.GetBenchNetwork(); var recreateMagicOnionTrigger = stackProps.GetBenchmarkServerBinariesHash(); // s3 var s3 = new Bucket(this, "Bucket", new BucketProps { AutoDeleteObjects = true, RemovalPolicy = RemovalPolicy.DESTROY, AccessControl = BucketAccessControl.PRIVATE, }); var lifecycleRule = new LifecycleRule { Enabled = true, Prefix = "reports/", Expiration = Duration.Days(stackProps.DaysKeepReports), AbortIncompleteMultipartUploadAfter = Duration.Days(1), }; s3.AddLifecycleRule(lifecycleRule); s3.AddToResourcePolicy(new PolicyStatement(new PolicyStatementProps { Sid = "AllowPublicRead", Effect = Effect.ALLOW, Principals = new[] { new AnyPrincipal() }, Actions = new[] { "s3:GetObject*" }, Resources = new[] { $"{s3.BucketArn}/html/*" }, })); s3.AddToResourcePolicy(new PolicyStatement(new PolicyStatementProps { Sid = "AllowAwsAccountAccess", Effect = Effect.ALLOW, Principals = new[] { new AccountRootPrincipal() }, Actions = new[] { "s3:*" }, Resources = new[] { $"{s3.BucketArn}/*" }, })); // s3 deploy var masterDllDeployment = new BucketDeployment(this, "DeployMasterDll", new BucketDeploymentProps { DestinationBucket = s3, Sources = new[] { Source.Asset(Path.Combine(Directory.GetCurrentDirectory(), $"out/linux/server")) }, DestinationKeyPrefix = $"assembly/linux/server" }); var userdataDeployment = new BucketDeployment(this, "UserData", new BucketDeploymentProps { DestinationBucket = s3, Sources = new[] { Source.Asset(Path.Combine(Directory.GetCurrentDirectory(), "userdata/")) }, DestinationKeyPrefix = "userdata/" }); // docker deploy var dockerImage = new DockerImageAsset(this, "dframeWorkerImage", new DockerImageAssetProps { Directory = Path.Combine(Directory.GetCurrentDirectory(), "app"), File = "ConsoleAppEcs/Dockerfile.Ecs", }); var dframeImage = ContainerImage.FromDockerImageAsset(dockerImage); // network var vpc = new Vpc(this, "Vpc", new VpcProps { MaxAzs = 2, NatGateways = 0, SubnetConfiguration = new[] { new SubnetConfiguration { Name = "public", SubnetType = SubnetType.PUBLIC } }, }); var allsubnets = new SubnetSelection { Subnets = vpc.PublicSubnets }; var singleSubnets = new SubnetSelection { Subnets = new[] { vpc.PublicSubnets.First() } }; var sg = new SecurityGroup(this, "MasterSg", new SecurityGroupProps { AllowAllOutbound = true, Vpc = vpc, }); foreach (var subnet in vpc.PublicSubnets) { sg.AddIngressRule(Peer.Ipv4(vpc.VpcCidrBlock), Port.AllTcp(), "VPC", true); } // service discovery var serviceDiscoveryDomain = "local"; var serverMapName = "server"; var dframeMapName = "dframe-master"; var ns = new PrivateDnsNamespace(this, "Namespace", new PrivateDnsNamespaceProps { Vpc = vpc, Name = serviceDiscoveryDomain, }); var serviceDiscoveryServer = ns.CreateService("server", new DnsServiceProps { Name = serverMapName, DnsRecordType = DnsRecordType.A, RoutingPolicy = RoutingPolicy.MULTIVALUE, }); // alb var albDnsName = "benchmark-alb"; var benchToMagicOnionDnsName = benchNetwork.RequireAlb ? $"{benchNetwork.EndpointScheme}://{albDnsName}.{stackProps.AlbDomain.domain}" : $"{benchNetwork.EndpointScheme}://{serverMapName}.{serviceDiscoveryDomain}"; IApplicationTargetGroup grpcTargetGroup = null; IApplicationTargetGroup httpsTargetGroup = null; if (benchNetwork.RequireAlb) { // route53 var hostedZone = HostedZone.FromHostedZoneAttributes(this, "HostedZone", new HostedZoneAttributes { HostedZoneId = stackProps.AlbDomain.zoneId, ZoneName = stackProps.AlbDomain.domain, }); // acm var certificate = new DnsValidatedCertificate(this, "certificate", new DnsValidatedCertificateProps { DomainName = $"{albDnsName}.{hostedZone.ZoneName}", HostedZone = hostedZone, }); // alb var lb = new ApplicationLoadBalancer(this, "LB", new ApplicationLoadBalancerProps { Vpc = vpc, VpcSubnets = allsubnets, SecurityGroup = new SecurityGroup(this, "AlbSg", new SecurityGroupProps { AllowAllOutbound = true, Vpc = vpc, }), InternetFacing = false, Http2Enabled = true, }); grpcTargetGroup = AddGrpcTargetGroup(benchNetwork, vpc, certificate, lb); httpsTargetGroup = AddHttpsTargetGroup(benchNetwork, vpc, certificate, lb); // Dns Record _ = new CnameRecord(this, "alb-alias-record", new CnameRecordProps { RecordName = $"{albDnsName}.{stackProps.AlbDomain.domain}", Ttl = Duration.Seconds(60), Zone = hostedZone, DomainName = lb.LoadBalancerDnsName, }); } // iam var iamEc2MagicOnionRole = GetIamEc2MagicOnionRole(s3, serviceDiscoveryServer); var iamEcsTaskExecuteRole = GetIamEcsTaskExecuteRole(new[] { dframeWorkerLogGroup, dframeMasterLogGroup }); var iamDFrameTaskDefRole = GetIamEcsDframeTaskDefRole(s3); var iamWorkerTaskDefRole = GetIamEcsWorkerTaskDefRole(s3); // secrets var ddToken = stackProps.UseEc2DatadogAgentProfiler || stackProps.UseFargateDatadogAgentProfiler ? Amazon.CDK.AWS.SecretsManager.Secret.FromSecretNameV2(this, "dd-token", "magiconion-benchmark-datadog-token") : null; // MagicOnion var asg = new AutoScalingGroup(this, "MagicOnionAsg", new AutoScalingGroupProps { // Monitoring is default DETAILED. SpotPrice = "1.0", // 0.0096 for spot price average for m3.medium Vpc = vpc, SecurityGroup = sg, VpcSubnets = singleSubnets, InstanceType = stackProps.MagicOnionInstanceType, DesiredCapacity = 1, MaxCapacity = 1, MinCapacity = 0, AssociatePublicIpAddress = true, MachineImage = new AmazonLinuxImage(new AmazonLinuxImageProps { CpuType = AmazonLinuxCpuType.X86_64, Generation = AmazonLinuxGeneration.AMAZON_LINUX_2, Storage = AmazonLinuxStorage.GENERAL_PURPOSE, Virtualization = AmazonLinuxVirt.HVM, }), AllowAllOutbound = true, GroupMetrics = new[] { GroupMetrics.All() }, Role = iamEc2MagicOnionRole, UpdatePolicy = UpdatePolicy.ReplacingUpdate(), Signals = Signals.WaitForCount(1, new SignalsOptions { Timeout = Duration.Minutes(10), }), }); asg.AddSecretsReadGrant(ddToken, () => stackProps.UseEc2DatadogAgentProfiler); var userdata = GetUserData(recreateMagicOnionTrigger, s3.BucketName, stackProps.BenchmarkBinaryNames, serviceDiscoveryServer.ServiceId, stackProps.UseEc2CloudWatchAgentProfiler, stackProps.UseEc2DatadogAgentProfiler); asg.AddUserData(userdata); asg.UserData.AddSignalOnExitCommand(asg); asg.Node.AddDependency(masterDllDeployment); asg.Node.AddDependency(userdataDeployment); if (stackProps.EnableMagicOnionScaleInCron) { asg.ScaleOnSchedule("ScheduleOut", new BasicScheduledActionProps { DesiredCapacity = 1, MaxCapacity = 1, // AM9:00 (JST+9) on Monday to Wednesday Schedule = Schedule.Expression("0 0 * 1-3 *"), }); asg.ScaleOnSchedule("ScheduleIn", new BasicScheduledActionProps { DesiredCapacity = 0, MaxCapacity = 0, // PM9:00 (JST+9) on Everyday Schedule = Schedule.Expression("0 12 * 1-7 *"), }); } if (benchNetwork.RequireAlb) { asg.AttachToApplicationTargetGroup(grpcTargetGroup); asg.AttachToApplicationTargetGroup(httpsTargetGroup); } // ECS var cluster = new Cluster(this, "WorkerCluster", new ClusterProps { Vpc = vpc, }); cluster.Node.AddDependency(asg); // wait until asg is up // dframe-worker var dframeWorkerContainerName = "worker"; var dframeWorkerTaskDef = new FargateTaskDefinition(this, "DFrameWorkerTaskDef", new FargateTaskDefinitionProps { ExecutionRole = iamEcsTaskExecuteRole, TaskRole = iamWorkerTaskDefRole, Cpu = stackProps.WorkerFargate.CpuSize, MemoryLimitMiB = stackProps.WorkerFargate.MemorySize, }); dframeWorkerTaskDef.AddContainer(dframeWorkerContainerName, new ContainerDefinitionOptions { Image = dframeImage, Command = new[] { "--worker-flag" }, Environment = new Dictionary <string, string> { { "DFRAME_MASTER_CONNECT_TO_HOST", $"{dframeMapName}.{serviceDiscoveryDomain}" }, { "DFRAME_MASTER_CONNECT_TO_PORT", "12345" }, { "BENCH_SERVER_HOST", benchToMagicOnionDnsName }, { "BENCH_REPORTID", stackProps.ReportId }, { "BENCH_S3BUCKET", s3.BucketName }, }, Logging = LogDriver.AwsLogs(new AwsLogDriverProps { LogGroup = new LogGroup(this, "WorkerLogGroup", new LogGroupProps { LogGroupName = dframeWorkerLogGroup, RemovalPolicy = RemovalPolicy.DESTROY, Retention = RetentionDays.TWO_WEEKS, }), StreamPrefix = dframeWorkerLogGroup, }), }); dframeWorkerTaskDef.AddDatadogContainer($"{dframeWorkerContainerName}-datadog", ddToken, () => stackProps.UseFargateDatadogAgentProfiler); var dframeWorkerService = new FargateService(this, "DFrameWorkerService", new FargateServiceProps { ServiceName = "DFrameWorkerService", DesiredCount = 0, Cluster = cluster, TaskDefinition = dframeWorkerTaskDef, VpcSubnets = singleSubnets, SecurityGroups = new[] { sg }, PlatformVersion = FargatePlatformVersion.VERSION1_4, MinHealthyPercent = 0, AssignPublicIp = true, }); // dframe-master var dframeMasterTaskDef = new FargateTaskDefinition(this, "DFrameMasterTaskDef", new FargateTaskDefinitionProps { ExecutionRole = iamEcsTaskExecuteRole, TaskRole = iamDFrameTaskDefRole, Cpu = stackProps.MasterFargate.CpuSize, MemoryLimitMiB = stackProps.MasterFargate.MemorySize, }); dframeMasterTaskDef.AddContainer("dframe", new ContainerDefinitionOptions { Image = dframeImage, Environment = new Dictionary <string, string> { { "DFRAME_CLUSTER_NAME", cluster.ClusterName }, { "DFRAME_MASTER_SERVICE_NAME", "DFrameMasterService" }, { "DFRAME_WORKER_CONTAINER_NAME", dframeWorkerContainerName }, { "DFRAME_WORKER_SERVICE_NAME", dframeWorkerService.ServiceName }, { "DFRAME_WORKER_TASK_NAME", Fn.Select(1, Fn.Split("/", dframeWorkerTaskDef.TaskDefinitionArn)) }, { "DFRAME_WORKER_IMAGE", dockerImage.ImageUri }, { "BENCH_REPORTID", stackProps.ReportId }, { "BENCH_S3BUCKET", s3.BucketName }, }, Logging = LogDriver.AwsLogs(new AwsLogDriverProps { LogGroup = new LogGroup(this, "MasterLogGroup", new LogGroupProps { LogGroupName = dframeMasterLogGroup, RemovalPolicy = RemovalPolicy.DESTROY, Retention = RetentionDays.TWO_WEEKS, }), StreamPrefix = dframeMasterLogGroup, }), }); dframeMasterTaskDef.AddDatadogContainer($"dframe-datadog", ddToken, () => stackProps.UseFargateDatadogAgentProfiler); var dframeMasterService = new FargateService(this, "DFrameMasterService", new FargateServiceProps { ServiceName = "DFrameMasterService", DesiredCount = 1, Cluster = cluster, TaskDefinition = dframeMasterTaskDef, VpcSubnets = singleSubnets, SecurityGroups = new[] { sg }, PlatformVersion = FargatePlatformVersion.VERSION1_4, MinHealthyPercent = 0, AssignPublicIp = true, }); dframeMasterService.EnableCloudMap(new CloudMapOptions { CloudMapNamespace = ns, Name = dframeMapName, DnsRecordType = DnsRecordType.A, DnsTtl = Duration.Seconds(300), }); // output new CfnOutput(this, "ReportUrl", new CfnOutputProps { Value = $"https://{s3.BucketRegionalDomainName}/html/{stackProps.ReportId}/index.html" }); new CfnOutput(this, "EndPointStyle", new CfnOutputProps { Value = stackProps.BenchmarkEndpoint.ToString() }); new CfnOutput(this, "AsgName", new CfnOutputProps { Value = asg.AutoScalingGroupName }); new CfnOutput(this, "EcsClusterName", new CfnOutputProps { Value = cluster.ClusterName }); new CfnOutput(this, "DFrameWorkerEcsTaskdefImage", new CfnOutputProps { Value = dockerImage.ImageUri }); }
private async Task <HostedZone> FindHostedZoneAsync(string dnsName) { _logger.LogDebug("Finding hosted zone responsible for {DnsName}", dnsName); var partsToMatch = dnsName.Split(DomainSegmentSeparator); var isWildcard = dnsName.StartsWith(WildcardPrefix); var bestPossibleScore = isWildcard ? partsToMatch.Length - 1 : partsToMatch.Length; HostedZone bestMatch = null; int bestMatchScore = 0; var normalizedDnsName = NormalizeDnsName(dnsName); // Enumerate all hosted zones until a match is found, or until all hosted zones have been enumerated var hostedZones = await _route53Client.ListHostedZonesAsync(); do { foreach (var hostedZone in hostedZones.HostedZones) { _logger.LogDebug("Checking zone {Zone}", hostedZone.Name); if (normalizedDnsName.EndsWith(hostedZone.Name, StringComparison.InvariantCultureIgnoreCase)) { var hostedZoneParts = hostedZone.Name.Split(DomainSegmentSeparator); var score = hostedZoneParts.Length; if (score == bestPossibleScore) { _logger.LogInformation("Exact match for {DnsName} found (zone {Zone})", dnsName, hostedZone.Name); return(hostedZone); } else if (score > bestMatchScore) { _logger.LogDebug("Setting best match for {DnsName} to zone {Zone}", dnsName, hostedZone.Name); bestMatch = hostedZone; bestMatchScore = score; } } } hostedZones = await _route53Client.ListHostedZonesAsync( new ListHostedZonesRequest() { Marker = hostedZones.Marker }); } while (hostedZones.IsTruncated); if (bestMatch == null) { _logger.LogInformation("No zone match for {DnsName} found", dnsName); } else { _logger.LogInformation("Best match for {DnsName} found (zone {Zone})", dnsName, bestMatch.Name); } return(bestMatch); }
public IvrStack(Construct scope, string stackId, StackProps stackProps, IvrSiteSchema schema, IEnumerable <SecurityGroupRule> securityGroupRules) : base(scope, stackId, stackProps) { IVpc vpc = null; var MaxIpsPerSubnet = IvrVpcProps.MaxIpsPerSubnet; if (!string.IsNullOrWhiteSpace(schema.VpcName)) { vpc = Vpc.FromLookup(this, "$VPC", new VpcLookupOptions { VpcName = schema.VpcName, }); // will error if not found //MaxIpsPerSubnet = ???; } else if (!string.IsNullOrWhiteSpace(schema.VpcId)) { vpc = Vpc.FromLookup(this, "$VPC", new VpcLookupOptions { VpcId = schema.VpcId, }); // will error if not found //MaxIpsPerSubnet = ???; } else if (null != schema.VpcProps) { // use provided props to create brand new VPC vpc = new IvrVpc(this, $"VPC", schema.VpcProps); } if (schema.AddVpcS3Gateway) { var s3gw = new GatewayVpcEndpoint(this, $"S3GW", new GatewayVpcEndpointProps { Vpc = vpc, Service = GatewayVpcEndpointAwsService.S3, Subnets = new SubnetSelection[] { new SubnetSelection { SubnetType = SubnetType.PUBLIC, } }, }); } var role = new Role(this, "IVR", new RoleProps { AssumedBy = new ServicePrincipal("ec2.amazonaws.com"), InlinePolicies = new IvrInlinePolicies(stackProps.Env.Account, stackId, schema), }); // Configure inbound security for RDP (and more?) var securityGroup = new SecurityGroup(this, $"Ingress", new SecurityGroupProps { Vpc = vpc, AllowAllOutbound = schema.AllowAllOutbound, }); securityGroupRules.ForEach(rule => securityGroup.WithSecurityGroupRule(rule)); if (schema.AllowAllIntranet) { securityGroup.WithSecurityGroupRule(new IngressRule(Peer.Ipv4($"{vpc.VpcCidrBlock}"), Port.AllTraffic()).WithDescription($"All intranet traffic")); } // Finally - create our instances! var hosts = new List <HostInstance>(); for (var subnetIndex = 0; ++subnetIndex <= Math.Min(vpc.PublicSubnets.Length, schema.MaxSubnets);) { var hostIndexInSubnet = 0; foreach (var group in schema.HostGroups) { var numberOfHosts = Math.Min(group.HostCount, MaxIpsPerSubnet); if (numberOfHosts != group.HostCount) { Console.WriteLine($"Group({group.Name}) host count changed from {group.HostCount} to {numberOfHosts}"); group.HostCount = numberOfHosts; } var instanceProps = IvrInstanceProps.InstanceProps(vpc, vpc.PublicSubnets[subnetIndex - 1], role, securityGroup, group.InstanceProps); for (var hostCount = 0; ++hostCount <= numberOfHosts; ++hostIndexInSubnet) { var hostName = $"{schema.HostNamePrefix}{subnetIndex}{hostIndexInSubnet:00}"; var hostPrimingProps = new HostPrimingProps { HostName = hostName.AsWindowsComputerName(), // must fit into 15 chars WorkingFolder = $"{stackId}".AsWindowsFolder(), AwsAccount = stackProps.Env.Account, AwsRoleName = role.RoleName, RdpProps = schema.RdpProps, EC2Users = schema.EC2Users, DownloadAndInstall = group.DownloadAndInstall, S3iArgs = $"{group.InstallS3i} --verbose", }; var hostCommands = HostPriming.PrimeForS3i(hostPrimingProps) .WithFirewallAllowInbound($"{vpc.VpcCidrBlock}"); hostCommands.WithRenameAndRestart(hostPrimingProps.HostName); instanceProps.KeyName = schema.KeyPairName; instanceProps.UserData = hostCommands.UserData; hosts.Add(new HostInstance { Group = group, Instance = new Instance_(this, hostName.AsCloudFormationId(), instanceProps), }); } } } // associate pre-allocated EIPs var preAllocatedEIPs = schema.PreAllocatedElasticIPs?.SelectMany(s => s.Csv()).ToList() ?? new List <string> { }; var hostsThatRequireEIP = hosts.Where(h => h.Group.UsePreAllocatedElasticIPs).ToList(); if (preAllocatedEIPs.Count < hostsThatRequireEIP.Count) { throw new ArgumentException($"Pre-Allocated Elastic IPs needed: {hostsThatRequireEIP.Count()}, but only {preAllocatedEIPs.Count()} configured in schema.{nameof(IvrSiteSchema.PreAllocatedElasticIPs)}"); } var elasticIPAssociations = hostsThatRequireEIP.Zip(preAllocatedEIPs, (h, a) => { return(new CfnEIPAssociation(this, $"EIPA{h.Instance.InstancePrivateIp}".AsCloudFormationId(), new CfnEIPAssociationProps { AllocationId = a, InstanceId = h.Instance.InstanceId, })); }).ToList(); // execute LINQ now // We have schema.Domain registered in advance if (!string.IsNullOrWhiteSpace(schema.HostedZoneDomain)) { var theZone = HostedZone.FromLookup(this, $"{stackId}_Zone_", new HostedZoneProviderProps { DomainName = schema.HostedZoneDomain, //Comment = "HostedZone created by Route53 Registrar", }); // assign new Elastic IPs as needed if (!string.IsNullOrWhiteSpace(schema.SubdomainEIPs)) { var newElasticIPs = hosts.Where(h => h.Group.AllocateNewElasticIPs).Select(h => { return(new CfnEIP(this, $"EIP{h.Instance.InstancePrivateIp}".AsCloudFormationId(), new CfnEIPProps { // 'standard' or 'vpc': https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-eip.html#cfn-ec2-eip-domain Domain = "vpc", InstanceId = h.Instance.InstanceId, })); }).ToList(); // collect them now to prevent LINQ side effects if (newElasticIPs.Any()) { // Register public Elastic IPs var arNewPublic = new ARecord(this, $"ARecord_Public_NewAlloc".AsCloudFormationId(), new ARecordProps { Zone = theZone, RecordName = $"{schema.SubdomainEIPs}.{theZone.ZoneName}", Target = RecordTarget.FromValues(newElasticIPs.Select(eip => eip.Ref).ToArray()), Ttl = Duration.Seconds(300), }); } else if (elasticIPAssociations.Any()) { // Register public Elastic IPs /* * var arPrePublic = new ARecord(this, $"ARecord_Public_PreAlloc".AsCloudFormationId(), new ARecordProps * { * Zone = theZone, * RecordName = $"{schema.SubdomainEIPs}.{theZone.ZoneName}", * Target = RecordTarget.FromValues(elasticIPAssociations.Select(eipa => eipa.Ref).ToArray()), // ***** how to do that? * Ttl = Duration.Seconds(300), * }); */ foreach (var a in elasticIPAssociations) { Console.WriteLine($"Pre-Allocated Elastic IP Associations: {a.AllocationId}/{a.InstanceId}, {a.Eip}/{a.PrivateIpAddress}, {a.Ref} - please put it to {schema.SubdomainEIPs}.{theZone.ZoneName} ARecord manually"); } } } if (0 < hosts.Count && !string.IsNullOrWhiteSpace(schema.SubdomainHosts)) { // Register private IPs (never changing, as opposed to public - which change on stop/start) addresses of all hosts var arPrivate = new ARecord(this, $"ARecord_Private_".AsCloudFormationId(), new ARecordProps { Zone = theZone, RecordName = $"{schema.SubdomainHosts}.{theZone.ZoneName}", Target = RecordTarget.FromIpAddresses(hosts.Select(h => h.Instance.InstancePrivateIp).ToArray()), Ttl = Duration.Seconds(300), }); } //throw new Exception(); } }
public SpaStack(Construct scope, string id, SpaStackProps props) : base(scope, id, props) { //s3 bucket var bucket = new Bucket(this, $"{props.ServiceName}-bucket", new BucketProps { WebsiteIndexDocument = "index.html", Versioned = true, BucketName = props.ServiceName, RemovalPolicy = RemovalPolicy.DESTROY }); //cloudfront distribution var cloudFrontOai = new OriginAccessIdentity(this, $"{props.ServiceName}-oai", new OriginAccessIdentityProps { Comment = $"OAI for {props.ServiceName}." }); var cloudfrontDist = new CloudFrontWebDistribution(this, $"{props.ServiceName}-cfd", new CloudFrontWebDistributionProps { ViewerCertificate = ViewerCertificate.FromAcmCertificate( props.CloudFrontCert, new ViewerCertificateOptions { Aliases = new [] { $"{props.SubDomain}.{props.HostedZoneName}" }, SslMethod = SSLMethod.SNI }), OriginConfigs = new ISourceConfiguration[] { new SourceConfiguration { S3OriginSource = new S3OriginConfig { S3BucketSource = bucket, OriginAccessIdentity = cloudFrontOai }, Behaviors = new IBehavior[] { new Behavior { IsDefaultBehavior = true, } } } } }); var cnameRecord = new CnameRecord(this, $"{props.ServiceName}CloudFrontCname", new CnameRecordProps { Zone = HostedZone.FromHostedZoneAttributes(this, "HostedZone", new HostedZoneAttributes { ZoneName = props.HostedZoneName, HostedZoneId = props.HostedZoneId }), RecordName = props.SubDomain, DomainName = cloudfrontDist.DistributionDomainName }); var cloudfrontS3Access = new PolicyStatement(); cloudfrontS3Access.AddActions("s3:GetBucket*", "s3:GetObject*", "s3:List*"); cloudfrontS3Access.AddResources(bucket.BucketArn); cloudfrontS3Access.AddResources($"{bucket.BucketArn}/*"); cloudfrontS3Access.AddCanonicalUserPrincipal(cloudFrontOai.CloudFrontOriginAccessIdentityS3CanonicalUserId); bucket.AddToResourcePolicy(cloudfrontS3Access); //codebuild project var codeBuildProject = new Project(this, $"{props.ServiceName}-codeBuild-project", new ProjectProps { Vpc = props.Vpc, ProjectName = props.ServiceName, Environment = new BuildEnvironment { BuildImage = LinuxBuildImage.STANDARD_4_0, }, Source = Source.GitHub(props.GitHubSourceProps), BuildSpec = BuildSpec.FromSourceFilename(props.BuildSpecFile), EnvironmentVariables = new Dictionary <string, IBuildEnvironmentVariable> { { "SPA_DIRECTORY", new BuildEnvironmentVariable { Value = props.SpaDirectory } }, { "S3_BUCKET", new BuildEnvironmentVariable { Value = bucket.BucketName } }, { "CLOUDFRONT_ID", new BuildEnvironmentVariable { Value = cloudfrontDist.DistributionId } }, { "API_URL", new BuildEnvironmentVariable { Value = props.ApiUrl } } } }); // iam policy to push your build to S3 codeBuildProject.AddToRolePolicy( new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Resources = new[] { bucket.BucketArn, $"{bucket.BucketArn}/*" }, Actions = new[] { "s3:GetBucket*", "s3:List*", "s3:GetObject*", "s3:DeleteObject", "s3:PutObject" } })); codeBuildProject.AddToRolePolicy( new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Resources = new [] { "*" }, Actions = new [] { "cloudfront:CreateInvalidation", "cloudfront:GetDistribution*", "cloudfront:GetInvalidation", "cloudfront:ListInvalidations", "cloudfront:ListDistributions" } })); //codepipeline? }
// A simple construct that contains a collection of AWS S3 buckets. public StaticSiteConstruct(Construct scope, string id, StaticSiteConstructProps props) : base(scope, id) { var zone = HostedZone.FromLookup(this, "Zone", new HostedZoneProviderProps { DomainName = props.DomainName }); var siteDomain = (string)($"{props.SiteSubDomain}.{props.DomainName}"); new CfnOutput(this, "Site", new CfnOutputProps { Value = $"https://{siteDomain}" }); var siteBucket = new Bucket(this, "SiteBucket", new BucketProps { BucketName = siteDomain, WebsiteIndexDocument = "index.html", WebsiteErrorDocument = "error.html", PublicReadAccess = true, // The default removal policy is RETAIN, which means that cdk destroy will not attempt to delete // the new bucket, and it will remain in your account until manually deleted. By setting the policy to // DESTROY, cdk destroy will attempt to delete the bucket, but will error if the bucket is not empty. RemovalPolicy = RemovalPolicy.DESTROY // NOT recommended for production code }); new CfnOutput(this, "Bucket", new CfnOutputProps { Value = siteBucket.BucketName }); var certificateArn = new DnsValidatedCertificate(this, "SiteCertificate", new DnsValidatedCertificateProps { DomainName = siteDomain, HostedZone = zone }).CertificateArn; new CfnOutput(this, "Certificate", new CfnOutputProps { Value = certificateArn }); var behavior = new Behavior(); behavior.IsDefaultBehavior = true; var distribution = new CloudFrontWebDistribution(this, "SiteDistribution", new CloudFrontWebDistributionProps { AliasConfiguration = new AliasConfiguration { AcmCertRef = certificateArn, Names = new string[] { siteDomain }, SslMethod = SSLMethod.SNI, SecurityPolicy = SecurityPolicyProtocol.TLS_V1_2016 }, OriginConfigs = new ISourceConfiguration[] { new SourceConfiguration { S3OriginSource = new S3OriginConfig { S3BucketSource = siteBucket }, Behaviors = new Behavior[] { behavior } } } }); new CfnOutput(this, "DistributionId", new CfnOutputProps { Value = distribution.DistributionId }); new ARecord(this, "SiteAliasRecord", new ARecordProps { RecordName = siteDomain, Target = RecordTarget.FromAlias(new CloudFrontTarget(distribution)), Zone = zone }); new BucketDeployment(this, "DeployWithInvalidation", new BucketDeploymentProps { Sources = new ISource[] { Source.Asset("./site-contents") }, DestinationBucket = siteBucket, Distribution = distribution, DistributionPaths = new string[] { "/*" } }); }
private async Task DeleteRoute53RecordSet(HostedZone zone, Instance instance, ILambdaContext context) { context.Logger.LogLine($"**** TODO: Delete route53 record set!"); // TODO: }