public override async Task <bool> CreateRecord(DnsValidationRecord record) { try { var recordName = record.Authority.Domain; var token = record.Value; var hostedZoneIds = await GetHostedZoneIds(recordName); if (hostedZoneIds == null) { return(false); } _log.Information("Creating TXT record {recordName} with value {token}", recordName, token); var updateTasks = hostedZoneIds.Select(hostedZoneId => _route53Client.ChangeResourceRecordSetsAsync( new ChangeResourceRecordSetsRequest( hostedZoneId, new ChangeBatch(new List <Change> { new Change( ChangeAction.UPSERT, CreateResourceRecordSet(recordName, token)) })))); var results = await Task.WhenAll(updateTasks); var propagationTasks = results.Select(result => WaitChangesPropagation(result.ChangeInfo)); await Task.WhenAll(propagationTasks); return(true); } catch (Exception ex) { _log.Warning($"Error creating TXT record: {ex.Message}"); return(false); } }
public override async Task <bool> CreateRecord(string recordName, string token) { try { var hostedZoneId = await GetHostedZoneId(recordName); if (hostedZoneId == null) { return(false); } _log.Information("Creating TXT record {recordName} with value {token}", recordName, token); var response = await _route53Client.ChangeResourceRecordSetsAsync( new ChangeResourceRecordSetsRequest( hostedZoneId, new ChangeBatch(new List <Change> { new Change( ChangeAction.UPSERT, CreateResourceRecordSet(recordName, token)) }))); await WaitChangesPropagation(response.ChangeInfo); return(true); } catch (Exception ex) { _log.Warning($"Error creating TXT record: {ex.Message}"); return(false); } }
public override async Task CreateRecord(string recordName, string token) { var hostedZoneId = await GetHostedZoneId(recordName); _log.Information("Creating TXT record {recordName} with value {token}", recordName, token); var response = await _route53Client.ChangeResourceRecordSetsAsync( new ChangeResourceRecordSetsRequest( hostedZoneId, new ChangeBatch(new List <Change> { new Change( ChangeAction.UPSERT, CreateResourceRecordSet(recordName, token)) }))); await WaitChangesPropagation(response.ChangeInfo); }
/// <summary> /// Creates a record set if none exists, else updates an existing record set of type A, assigning the supplied public ip address to the supplied domain /// </summary> /// <param name="hostedZoneId">the hosted zone id to create or update a recordset for</param> /// <param name="domainName">the domain to assign the public ip to</param> /// <param name="publicIp">the public ip to assign to the supplied domain</param> /// <returns>the change request id and </returns> public async Task <(string, string)> UpsertRecordset(string hostedZoneId, string domainName, string publicIp) { // Create recordset change request var recordsetRequest = new ChangeResourceRecordSetsRequest(hostedZoneId, new ChangeBatch(new List <Change>() { new Change { ResourceRecordSet = new ResourceRecordSet(domainName, RRType.A) { TTL = 60, ResourceRecords = new List <ResourceRecord>() { new ResourceRecord(publicIp) } }, Action = ChangeAction.UPSERT } })); // Reqeust change var recordsetResponse = await _route53Client.ChangeResourceRecordSetsAsync(recordsetRequest); if (recordsetResponse.HttpStatusCode == System.Net.HttpStatusCode.OK) { return(recordsetResponse.ChangeInfo.Id, recordsetResponse.ChangeInfo.Status); } else { throw new System.Exception($"Failed to Upsert recordset, ChangeResourceRecordSetsRequest status: {recordsetResponse.HttpStatusCode}"); } }
public async Task HandleInitR53(Instance inst, Dictionary <string, string> tags) { _logger.LogInformation("Handling CREATING R53 records"); var r53Spec = ResolveR53Spec(inst, tags); var r53Routing = ResolveR53RoutingSpec(inst, tags); var rrset = new ResourceRecordSet { Name = r53Spec.Name, Type = RRType.FindValue(r53Spec.Type), TTL = r53Spec.TTL, ResourceRecords = new List <ResourceRecord> { new ResourceRecord(r53Spec.Value), }, }; // Optional routing policy configuration r53Routing?.Apply(rrset); var changeRequ = new ChangeResourceRecordSetsRequest { HostedZoneId = r53Spec.Zone, ChangeBatch = new ChangeBatch { Changes = new List <Change> { new Change { Action = ChangeAction.UPSERT, ResourceRecordSet = rrset, } } } }; var changeResp = await _r53.ChangeResourceRecordSetsAsync(changeRequ); _logger.LogInformation("UPSERT request completed, response:"); _logger.LogInformation(JsonSerializer.Serialize(changeResp)); }
public async Task UpdateSingleAsync(string ipAddress, HostedDomainInfo domain) { var currentExternalIp = ipAddress; // Ensure the domain name doesn't end with a dot. This is how they are returned from AWS API but they will be trimmed // as well so that they match var domainName = domain.DomainName; domainName = domainName.TrimEnd(".".ToCharArray()); var zoneId = domain.ZoneId; var listResourceRecordSetsResponse = await amazonClient.ListResourceRecordSetsAsync(new ListResourceRecordSetsRequest() { HostedZoneId = zoneId }); if (listResourceRecordSetsResponse.ResourceRecordSets.Count == 0) { throw new InvalidOperationException($"Could not find any ResourceRecordSets for zone: {zoneId}"); } var resourceRecordSet = listResourceRecordSetsResponse.ResourceRecordSets.FirstOrDefault(recordset => recordset.Name.TrimEnd(".".ToCharArray()) == domainName); if (resourceRecordSet == null) { throw new InvalidOperationException($"Could not find any resource record set for domain: {domainName}"); } var resourceRecord = resourceRecordSet.ResourceRecords.FirstOrDefault(); if (resourceRecord == null) { throw new InvalidOperationException($"Could not find any resouce record in the set"); } if (resourceRecord.Value != currentExternalIp) { resourceRecord.Value = currentExternalIp; await amazonClient.ChangeResourceRecordSetsAsync(new ChangeResourceRecordSetsRequest() { HostedZoneId = zoneId, ChangeBatch = new ChangeBatch() { Changes = new List <Change>() { new Change(ChangeAction.UPSERT, resourceRecordSet) } } }); } }
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); }
internal void Update(string hostname, IPAddress ipAddress) { var lhzTask = route53Client.ListHostedZonesAsync(); ResourceRecord resourceRecord = new ResourceRecord(ipAddress.ToString()); ResourceRecordSet resourceRecordSet = new ResourceRecordSet { Name = hostname, TTL = 30, Type = RRType.A, ResourceRecords = new List <ResourceRecord> { resourceRecord } }; Change change = new Change { Action = ChangeAction.UPSERT, ResourceRecordSet = resourceRecordSet }; ChangeBatch changeBatch = new ChangeBatch { Changes = new List <Change> { change }, Comment = DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture) }; // This is wrong and does The Wrong Thing, I'm fairly certain string domain = DomainName.Parse(hostname).Domain; var zones = lhzTask.Result.HostedZones; string hostedZoneId = zones.Single(z => z.Name.StartsWith(domain)).Id; ChangeResourceRecordSetsRequest request = new ChangeResourceRecordSetsRequest { ChangeBatch = changeBatch, HostedZoneId = hostedZoneId }; var crrsTask = route53Client.ChangeResourceRecordSetsAsync(request); var response = crrsTask.Result; }
private Amazon.Route53.Model.ChangeResourceRecordSetsResponse CallAWSServiceOperation(IAmazonRoute53 client, Amazon.Route53.Model.ChangeResourceRecordSetsRequest request) { Utils.Common.WriteVerboseEndpointMessage(this, client.Config, "Amazon Route 53", "ChangeResourceRecordSets"); try { #if DESKTOP return(client.ChangeResourceRecordSets(request)); #elif CORECLR return(client.ChangeResourceRecordSetsAsync(request).GetAwaiter().GetResult()); #else #error "Unknown build edition" #endif } catch (AmazonServiceException exc) { var webException = exc.InnerException as System.Net.WebException; if (webException != null) { throw new Exception(Utils.Common.FormatNameResolutionFailureMessage(client.Config, webException.Message), webException); } throw; } }
protected override async Task DeleteAsync(string recordName, string recordType, string recordValue) { _logger.LogDebug("Starting deletion of {RecordType} {RecordName} with value {RecordValue}", recordType, recordName, recordValue); var zone = await FindHostedZoneAsync(recordName); if (zone == null) { _logger.LogDebug("No zone was found"); return; } if (recordType == TxtRecordType) { recordValue = NormalizeTxtValue(recordValue); } var recordSets = await FindRecordSetsAsync(zone, recordName, recordType); var changeBatch = new ChangeBatch(); if (!recordSets.Any()) { _logger.LogInformation("No DNS records matching {RecordType} {RecordName} were found to delete in zone {Zone}", recordType, recordName, zone.Name); return; } foreach (var recordSet in recordSets) { if (!recordSet.ResourceRecords.Any(x => x.Value != recordValue)) { _logger.LogDebug("Will delete record {RecordType} {RecordName}", recordType, recordName); changeBatch.Changes.Add(new Change() { Action = ChangeAction.DELETE, ResourceRecordSet = recordSet }); } else { recordSet.ResourceRecords.RemoveAll(x => x.Value == recordValue); _logger.LogDebug("Will retain remaining answers for {RecordType} {RecordName}", recordType, recordName); changeBatch.Changes.Add(new Change() { Action = ChangeAction.UPSERT, ResourceRecordSet = recordSet }); } } _logger.LogInformation("Deleting or modifying {Count} DNS records matching {RecordType} {RecordName} with value {RecordValue} in zone {Zone}", changeBatch.Changes.Count, recordType, recordName, recordValue, zone.Name); var deleteResponse = await _route53Client.ChangeResourceRecordSetsAsync( new ChangeResourceRecordSetsRequest() { ChangeBatch = changeBatch, HostedZoneId = zone.Id }); var changeRequest = new GetChangeRequest { Id = deleteResponse.ChangeInfo.Id }; while ((await _route53Client.GetChangeAsync(changeRequest)).ChangeInfo.Status == ChangeStatus.PENDING) { _logger.LogDebug("Deletion or modification of {RecordType} {RecordName} is pending. Checking for status update in {StatusPollIntervalSeconds} seconds.", recordType, recordName, StatusPollIntervalSeconds); Thread.Sleep(TimeSpan.FromSeconds(StatusPollIntervalSeconds)); } }
public async Task <Response> Delete() { var props = Request.ResourceProperties; IAmazonCertificateManager acmClient = await acmFactory.Create(props.CreationRoleArn); IAmazonRoute53 route53Client = await route53Factory.Create(props.ValidationRoleArn); var describeResponse = await acmClient.DescribeCertificateAsync(new DescribeCertificateRequest { CertificateArn = Request.PhysicalResourceId, }); Console.WriteLine($"Got describe certificate response: {JsonSerializer.Serialize(describeResponse)}"); var names = new HashSet <string>(); var changes = new List <Change>(); foreach (var option in describeResponse.Certificate.DomainValidationOptions) { var query = from name in names where name == option.ResourceRecord.Name select name; if (query.Count() != 0) { continue; } names.Add(option.ResourceRecord.Name); changes.Add(new Change { Action = ChangeAction.DELETE, ResourceRecordSet = new ResourceRecordSet { Name = option.ResourceRecord.Name, Type = new RRType(option.ResourceRecord.Type.Value), SetIdentifier = Request.PhysicalResourceId, Weight = 1, TTL = 60, ResourceRecords = new List <ResourceRecord> { new ResourceRecord { Value = option.ResourceRecord.Value } } } }); } if (changes.Count() != 0) { try { var roleArn = Request.ResourceProperties.ValidationRoleArn; var changeRecordsResponse = await route53Client.ChangeResourceRecordSetsAsync(new ChangeResourceRecordSetsRequest { HostedZoneId = Request.ResourceProperties.HostedZoneId, ChangeBatch = new ChangeBatch { Changes = changes } }); Console.WriteLine($"Got delete record response: {JsonSerializer.Serialize(changeRecordsResponse)}"); } catch (Exception e) { Console.WriteLine($"Error deleting old resource records: {e.Message} {e.StackTrace}"); } } var deleteResponse = await acmClient.DeleteCertificateAsync(new DeleteCertificateRequest { CertificateArn = Request.PhysicalResourceId, }); Console.WriteLine($"Received delete certificate response: {JsonSerializer.Serialize(deleteResponse)}"); return(new Response { PhysicalResourceId = Request.PhysicalResourceId }); }
public async Task <Response?> Create() { var props = Request.ResourceProperties; IAmazonCertificateManager acmClient = await acmFactory.Create(props.CreationRoleArn); IAmazonRoute53 route53Client = await route53Factory.Create(props.ValidationRoleArn); var request = new RequestCertificateRequest { DomainName = props.DomainName, ValidationMethod = props.ValidationMethod }; if (props.CertificateAuthorityArn != null) { request.CertificateAuthorityArn = props.CertificateAuthorityArn; } if (props.DomainValidationOptions != null) { request.DomainValidationOptions = props.DomainValidationOptions; } if (props.Options != null) { request.Options = props.Options; } if (props.SubjectAlternativeNames != null) { request.SubjectAlternativeNames = props.SubjectAlternativeNames; } var requestCertificateResponse = await acmClient.RequestCertificateAsync(request); Console.WriteLine($"Got Request Certificate Response: {JsonSerializer.Serialize(requestCertificateResponse)}"); PhysicalResourceId = requestCertificateResponse.CertificateArn; var describeCertificateRequest = new DescribeCertificateRequest { CertificateArn = PhysicalResourceId }; var tasks = new List <Task>(); Thread.Sleep(500); bool foundValidationOptions = false; List <DomainValidation> validationOptions = new List <DomainValidation>(); // For some reason, the domain validation options aren't immediately populated. while (!foundValidationOptions) { var describeCertificateResponse = await acmClient.DescribeCertificateAsync(describeCertificateRequest); Console.WriteLine($"Got Describe Certificate Response: {JsonSerializer.Serialize(describeCertificateResponse)}"); validationOptions = describeCertificateResponse.Certificate.DomainValidationOptions; foundValidationOptions = true; if (validationOptions.Count() == 0) { foundValidationOptions = false; } foreach (var option in validationOptions) { if (option.ResourceRecord?.Name == null) { foundValidationOptions = false; } } Thread.Sleep(1000); } if (props.Tags != null) { tasks.Add(Task.Run(async delegate { var addTagsResponse = await acmClient.AddTagsToCertificateAsync(new AddTagsToCertificateRequest { Tags = props.Tags, CertificateArn = PhysicalResourceId, }); Console.WriteLine($"Got Add Tags Response: {JsonSerializer.Serialize(addTagsResponse)}"); })); } // add DNS validation records if applicable var names = new HashSet <string>(); var changes = new List <Change>(); if (props.ValidationMethod == ValidationMethod.DNS) { foreach (var option in validationOptions) { var query = from name in names where name == option.ResourceRecord.Name select name; if (query.Count() != 0) { continue; } names.Add(option.ResourceRecord.Name); changes.Add(new Change { Action = ChangeAction.UPSERT, ResourceRecordSet = new ResourceRecordSet { Name = option.ResourceRecord.Name, Type = new RRType(option.ResourceRecord.Type.Value), SetIdentifier = PhysicalResourceId, Weight = 1, TTL = 60, ResourceRecords = new List <ResourceRecord> { new ResourceRecord { Value = option.ResourceRecord.Value } } } }); } tasks.Add( Task.Run(async delegate { var changeRecordsResponse = await route53Client.ChangeResourceRecordSetsAsync(new ChangeResourceRecordSetsRequest { HostedZoneId = props.HostedZoneId, ChangeBatch = new ChangeBatch { Changes = changes } }); Console.WriteLine($"Got Change Record Sets Response: {JsonSerializer.Serialize(changeRecordsResponse)}"); }) ); } Task.WaitAll(tasks.ToArray()); Request.PhysicalResourceId = PhysicalResourceId; Request.RequestType = RequestType.Wait; return(await Wait()); }