diff --git a/internal/services/dns/dns_tlsa_record_data_source.go b/internal/services/dns/dns_tlsa_record_data_source.go new file mode 100644 index 0000000000000..86e1ed75222a4 --- /dev/null +++ b/internal/services/dns/dns_tlsa_record_data_source.go @@ -0,0 +1,119 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dns + +import ( + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2023-07-01-preview/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceDnsTLSARecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceDnsTLSARecordRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "matching_type": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "selector": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "usage": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "cert_association_data": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + Set: resourceDnsTLSARecordHash, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.TagsDataSource(), + }, + } +} + +func dataSourceDnsTLSARecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + recordSetsClient := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + + id := recordsets.NewRecordTypeID(subscriptionId, d.Get("resource_group_name").(string), d.Get("zone_name").(string), recordsets.RecordTypeTLSA, d.Get("name").(string)) + resp, err := recordSetsClient.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.SetId(id.ID()) + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.DnsZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsTLSARecords(props.TLSARecords)); err != nil { + return err + } + + return tags.FlattenAndSet(d, props.Metadata) + } + } + + return nil +} diff --git a/internal/services/dns/dns_tlsa_record_data_source_test.go b/internal/services/dns/dns_tlsa_record_data_source_test.go new file mode 100644 index 0000000000000..cb17443f5d1e5 --- /dev/null +++ b/internal/services/dns/dns_tlsa_record_data_source_test.go @@ -0,0 +1,46 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dns_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DnsTLSARecordDataSource struct{} + +func TestAccDataSourceDnsTLSARecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dns_tlsa_record", "test") + r := DnsTLSARecordDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("zone_name").Exists(), + check.That(data.ResourceName).Key("record.#").HasValue("2"), + check.That(data.ResourceName).Key("ttl").Exists(), + check.That(data.ResourceName).Key("fqdn").Exists(), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func (DnsTLSARecordDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_dns_tlsa_record" "test" { + name = azurerm_dns_tlsa_record.test.name + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name +} +`, DnsTLSARecordResource{}.basic(data)) +} diff --git a/internal/services/dns/dns_tlsa_record_resource.go b/internal/services/dns/dns_tlsa_record_resource.go new file mode 100644 index 0000000000000..9f7d9483316df --- /dev/null +++ b/internal/services/dns/dns_tlsa_record_resource.go @@ -0,0 +1,324 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dns + +import ( + "bytes" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2023-07-01-preview/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func resourceDnsTLSARecord() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceDnsTLSARecordCreate, + Read: resourceDnsTLSARecordRead, + Update: resourceDnsTLSARecordUpdate, + Delete: resourceDnsTLSARecordDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + parsed, err := recordsets.ParseRecordTypeID(id) + if err != nil { + return err + } + if parsed.RecordType != recordsets.RecordTypeTLSA { + return fmt.Errorf("this resource only supports 'TLSA' records") + } + return nil + }), + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "zone_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + }, + + "record": { + Type: pluginsdk.TypeSet, + Required: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "matching_type": { + Type: pluginsdk.TypeInt, + Required: true, + }, + + "selector": { + Type: pluginsdk.TypeInt, + Required: true, + }, + + "usage": { + Type: pluginsdk.TypeInt, + Required: true, + }, + + "cert_association_data": { + Type: pluginsdk.TypeString, + Required: true, + }, + }, + }, + Set: resourceDnsTLSARecordHash, + }, + + "ttl": { + Type: pluginsdk.TypeInt, + Required: true, + }, + + "fqdn": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tags": commonschema.Tags(), + }, + } +} + +func resourceDnsTLSARecordCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + defer cancel() + + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + zoneName := d.Get("zone_name").(string) + + id := recordsets.NewRecordTypeID(subscriptionId, resGroup, zoneName, recordsets.RecordTypeTLSA, name) + + existing, err := client.Get(ctx, id) + if err != nil { + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) + } + } + + if !response.WasNotFound(existing.HttpResponse) { + return tf.ImportAsExistsError("azurerm_dns_tlsa_record", id.ID()) + } + + ttl := int64(d.Get("ttl").(int)) + t := d.Get("tags").(map[string]interface{}) + + parameters := recordsets.RecordSet{ + Name: &name, + Properties: &recordsets.RecordSetProperties{ + Metadata: tags.Expand(t), + TTL: pointer.To(ttl), + TLSARecords: expandAzureRmDnsTLSARecords(d), + }, + } + + if _, err := client.CreateOrUpdate(ctx, id, parameters, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceDnsTLSARecordRead(d, meta) +} + +func resourceDnsTLSARecordRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := recordsets.ParseRecordTypeID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + d.Set("name", id.RelativeRecordSetName) + d.Set("resource_group_name", id.ResourceGroupName) + d.Set("zone_name", id.DnsZoneName) + + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("ttl", props.TTL) + d.Set("fqdn", props.Fqdn) + + if err := d.Set("record", flattenAzureRmDnsTLSARecords(props.TLSARecords)); err != nil { + return err + } + if err := tags.FlattenAndSet(d, props.Metadata); err != nil { + return err + } + } + } + + return nil +} + +func resourceDnsTLSARecordUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := recordsets.ParseRecordTypeID(d.Id()) + if err != nil { + return err + } + + existing, err := client.Get(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + if existing.Model == nil { + return fmt.Errorf("retrieving %s: `model` was nil", id) + } + + if existing.Model.Properties == nil { + return fmt.Errorf("retrieving %s: `properties` was nil", id) + } + + payload := *existing.Model + + if d.HasChange("record") { + payload.Properties.TLSARecords = expandAzureRmDnsTLSARecords(d) + } + + if d.HasChange("ttl") { + payload.Properties.TTL = pointer.To(int64(d.Get("ttl").(int))) + } + + if d.HasChange("tags") { + payload.Properties.Metadata = tags.Expand(d.Get("tags").(map[string]interface{})) + } + + if _, err := client.CreateOrUpdate(ctx, *id, payload, recordsets.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("updating %s: %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceDnsSrvRecordRead(d, meta) +} + +func resourceDnsTLSARecordDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Dns.RecordSets + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := recordsets.ParseRecordTypeID(d.Id()) + if err != nil { + return err + } + + if _, err := client.Delete(ctx, *id, recordsets.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + return nil +} + +func flattenAzureRmDnsTLSARecords(records *[]recordsets.TlsaRecord) []map[string]interface{} { + results := make([]map[string]interface{}, 0) + + if records != nil { + for _, record := range *records { + matchingType := int64(0) + if record.MatchingType != nil { + matchingType = *record.MatchingType + } + + selector := int64(0) + if record.Selector != nil { + selector = *record.Selector + } + + usage := int64(0) + if record.Usage != nil { + usage = *record.Usage + } + + certAssociationData := "" + if record.CertAssociationData != nil { + certAssociationData = *record.CertAssociationData + } + + results = append(results, map[string]interface{}{ + "matching_type": matchingType, + "selector": selector, + "usage": usage, + "cert_association_data": certAssociationData, + }) + } + } + + return results +} + +func expandAzureRmDnsTLSARecords(d *pluginsdk.ResourceData) *[]recordsets.TlsaRecord { + recordStrings := d.Get("record").(*pluginsdk.Set).List() + records := make([]recordsets.TlsaRecord, 0) + + for _, v := range recordStrings { + record := v.(map[string]interface{}) + matchingType := int64(record["matching_type"].(int)) + selector := int64(record["selector"].(int)) + usage := int64(record["usage"].(int)) + certAssociationData := record["cert_association_data"].(string) + + records = append(records, recordsets.TlsaRecord{ + MatchingType: &matchingType, + Selector: &selector, + Usage: &usage, + CertAssociationData: &certAssociationData, + }) + } + + return &records +} + +func resourceDnsTLSARecordHash(v interface{}) int { + var buf bytes.Buffer + + if m, ok := v.(map[string]interface{}); ok { + buf.WriteString(fmt.Sprintf("%d-", m["matching_type"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["selector"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["usage"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["cert_association_data"].(string))) + } + + return pluginsdk.HashString(buf.String()) +} diff --git a/internal/services/dns/dns_tlsa_record_resource_test.go b/internal/services/dns/dns_tlsa_record_resource_test.go new file mode 100644 index 0000000000000..ab87db31974cf --- /dev/null +++ b/internal/services/dns/dns_tlsa_record_resource_test.go @@ -0,0 +1,311 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dns_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-sdk/resource-manager/dns/2023-07-01-preview/recordsets" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type DnsTLSARecordResource struct{} + +func TestAccDnsTLSARecord_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dns_tlsa_record", "test") + r := DnsTLSARecordResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("fqdn").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccDnsTLSARecord_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dns_tlsa_record", "test") + r := DnsTLSARecordResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + { + Config: r.requiresImport(data), + ExpectError: acceptance.RequiresImportError("azurerm_dns_tlsa_record"), + }, + }) +} + +func TestAccDnsTLSARecord_updateRecords(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dns_tlsa_record", "test") + r := DnsTLSARecordResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("record.#").HasValue("2"), + ), + }, + { + Config: r.updateRecords(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("record.#").HasValue("3"), + ), + }, + }) +} + +func TestAccDnsTLSARecord_withTags(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dns_tlsa_record", "test") + r := DnsTLSARecordResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withTags(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("tags.%").HasValue("2"), + ), + }, + { + Config: r.withTagsUpdate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("tags.%").HasValue("1"), + ), + }, + data.ImportStep(), + }) +} + +func (DnsTLSARecordResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := recordsets.ParseRecordTypeID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Dns.RecordSets.Get(ctx, *id) + if err != nil { + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) + } + + return utils.Bool(resp.Model != nil), nil +} + +func (DnsTLSARecordResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_dns_tlsa_record" "test" { + name = "myarecord%d" + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name + ttl = 300 + + record { + matching_type = 1 + selector = 1 + usage = 3 + cert_association_data = "370C66FD4A0673CE1B62E76B819835DABB20702E4497CB10AFFE46E8135381E7" + } + + record { + matching_type = 1 + selector = 0 + usage = 0 + cert_association_data = "d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r DnsTLSARecordResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_dns_tlsa_record" "import" { + name = azurerm_dns_tlsa_record.test.name + resource_group_name = azurerm_dns_tlsa_record.test.resource_group_name + zone_name = azurerm_dns_tlsa_record.test.zone_name + ttl = 300 + + record { + matching_type = 1 + selector = 1 + usage = 3 + cert_association_data = "370C66FD4A0673CE1B62E76B819835DABB20702E4497CB10AFFE46E8135381E7" + } + + record { + matching_type = 1 + selector = 0 + usage = 0 + cert_association_data = "d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971" + } +} +`, r.basic(data)) +} + +func (DnsTLSARecordResource) updateRecords(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_dns_tlsa_record" "test" { + name = "myarecord%d" + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name + ttl = 300 + + record { + matching_type = 1 + selector = 1 + usage = 3 + cert_association_data = "370C66FD4A0673CE1B62E76B819835DABB20702E4497CB10AFFE46E8135381E7" + } + + record { + matching_type = 1 + selector = 0 + usage = 0 + cert_association_data = "d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971" + } + + record { + matching_type = 1 + selector = 1 + usage = 3 + cert_association_data = "0C72AC70B745AC19998811B131D662C9AC69DBDBE7CB23E5B514B56664C5D3D6" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (DnsTLSARecordResource) withTags(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_dns_tlsa_record" "test" { + name = "myarecord%d" + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name + ttl = 300 + + record { + matching_type = 1 + selector = 1 + usage = 3 + cert_association_data = "370C66FD4A0673CE1B62E76B819835DABB20702E4497CB10AFFE46E8135381E7" + } + + record { + matching_type = 1 + selector = 0 + usage = 0 + cert_association_data = "d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971" + } + + tags = { + environment = "Production" + cost_center = "MSFT" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (DnsTLSARecordResource) withTagsUpdate(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dns_zone" "test" { + name = "acctestzone%d.com" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_dns_tlsa_record" "test" { + name = "myarecord%d" + resource_group_name = azurerm_resource_group.test.name + zone_name = azurerm_dns_zone.test.name + ttl = 300 + + record { + matching_type = 1 + selector = 1 + usage = 3 + cert_association_data = "370C66FD4A0673CE1B62E76B819835DABB20702E4497CB10AFFE46E8135381E7" + } + + record { + matching_type = 1 + selector = 0 + usage = 0 + cert_association_data = "d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971" + } + + tags = { + environment = "staging" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/dns/registration.go b/internal/services/dns/registration.go index 22e989c81ae32..cdc5b1ed3eb87 100644 --- a/internal/services/dns/registration.go +++ b/internal/services/dns/registration.go @@ -41,6 +41,7 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { "azurerm_dns_ptr_record": dataSourceDnsPtrRecord(), "azurerm_dns_soa_record": dataSourceDnsSoaRecord(), "azurerm_dns_srv_record": dataSourceDnsSrvRecord(), + "azurerm_dns_tlsa_record": dataSourceDnsTLSARecord(), "azurerm_dns_txt_record": dataSourceDnsTxtRecord(), "azurerm_dns_zone": dataSourceDnsZone(), } @@ -58,6 +59,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_dns_ns_record": resourceDnsNsRecord(), "azurerm_dns_ptr_record": resourceDnsPtrRecord(), "azurerm_dns_srv_record": resourceDnsSrvRecord(), + "azurerm_dns_tlsa_record": resourceDnsTLSARecord(), "azurerm_dns_txt_record": resourceDnsTxtRecord(), "azurerm_dns_zone": resourceDnsZone(), } diff --git a/website/docs/d/dns_tlsa_record.html.markdown b/website/docs/d/dns_tlsa_record.html.markdown new file mode 100644 index 0000000000000..a7083c2e916e9 --- /dev/null +++ b/website/docs/d/dns_tlsa_record.html.markdown @@ -0,0 +1,65 @@ +--- +subcategory: "DNS" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_dns_tlsa_record" +description: |- + Gets information about an existing DNS TLSA Record. +--- + +# Data Source: azurerm_dns_tlsa_record + +Use this data source to access information about an existing DNS TLSA Record within Azure DNS. + +~> **Note:** [The Azure DNS API has a throttle limit of 500 read (GET) operations per 5 minutes](https://docs.microsoft.com/azure/azure-resource-manager/management/request-limits-and-throttling#network-throttling) - whilst the default read timeouts will work for most cases - in larger configurations you may need to set a larger [read timeout](https://www.terraform.io/language/resources/syntax#operation-timeouts) then the default 5min. Although, we'd generally recommend that you split the resources out into smaller Terraform configurations to avoid the problem entirely. + +## Example Usage + +```hcl +data "azurerm_dns_tlsa_record" "example" { + name = "test" + zone_name = "test-zone" + resource_group_name = "test-rg" +} + +output "dns_tlsa_record_id" { + value = data.azurerm_dns_tlsa_record.example.id +} +``` + +## Argument Reference + +* `name` - The name of the DNS TLSA Record. + +* `resource_group_name` - Specifies the resource group where the DNS Zone (parent resource) exists. + +* `zone_name` - Specifies the DNS Zone where the resource exists. + +## Attributes Reference + +* `id` - The DNS TLSA Record ID. + +* `fqdn` - The FQDN of the DNS TLSA Record. + +* `ttl` - The Time To Live (TTL) of the DNS record in seconds. + +* `record` - A list of values that make up the TLSA record. Each `record` block supports fields documented below. + +* `tags` - A mapping of tags assigned to the resource. + +--- + +The `record` block supports: + +* `matching_type` - Matching Type of the TLSA record. + +* `selector` - Selector of the TLSA record. + +* `usage` - Usage of the TLSA record. + +* `cert_association_data` - Certificate data to be matched. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the DNS SRV Record. diff --git a/website/docs/r/dns_tlsa_record.html.markdown b/website/docs/r/dns_tlsa_record.html.markdown new file mode 100644 index 0000000000000..788a2ae083511 --- /dev/null +++ b/website/docs/r/dns_tlsa_record.html.markdown @@ -0,0 +1,101 @@ +--- +subcategory: "DNS" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_dns_tlsa_record" +description: |- + Manages a DNS TLSA Record. +--- + +# azurerm_dns_tlsa_record + +Enables you to manage DNS TLSA Records within Azure DNS. + +~> **Note:** [The Azure DNS API has a throttle limit of 500 read (GET) operations per 5 minutes](https://docs.microsoft.com/azure/azure-resource-manager/management/request-limits-and-throttling#network-throttling) - whilst the default read timeouts will work for most cases - in larger configurations you may need to set a larger [read timeout](https://www.terraform.io/language/resources/syntax#operation-timeouts) then the default 5min. Although, we'd generally recommend that you split the resources out into smaller Terraform configurations to avoid the problem entirely. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_dns_zone" "example" { + name = "mydomain.com" + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_dns_tlsa_record" "example" { + name = "test" + zone_name = azurerm_dns_zone.example.name + resource_group_name = azurerm_resource_group.example.name + ttl = 300 + + record { + matching_type = 1 + selector = 1 + usage = 3 + cert_association_data = "370c66fd4a0673ce1b62e76b819835dabb20702e4497cb10affe46e8135381e7" + } + + tags = { + Environment = "Production" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +- `name` - (Required) The name of the DNS TLSA Record. Changing this forces a new resource to be created. + +- `resource_group_name` - (Required) Specifies the resource group where the DNS Zone (parent resource) exists. Changing this forces a new resource to be created. + +- `zone_name` - (Required) Specifies the DNS Zone where the resource exists. Changing this forces a new resource to be created. + +- `ttl` - (Required) The Time To Live (TTL) of the DNS record in seconds. + +- `record` - (Required) A list of values that make up the TLSA record. Each `record` block supports fields documented below. + +- `tags` - (Optional) A mapping of tags to assign to the resource. + +--- + +The `record` block supports: + +- `matching_type` - (Required) Matching Type of the TLSA record. + +- `selector` - (Required) Selector of the TLSA record. + +- `usage` - (Required) Usage of the TLSA record. + +- `cert_association_data` - (Required) Certificate data to be matched. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +- `id` - The DNS TLSA Record ID. + +- `fqdn` - The FQDN of the DNS TLSA Record. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +- `create` - (Defaults to 30 minutes) Used when creating the DNS TLSA Record. + +- `update` - (Defaults to 30 minutes) Used when updating the DNS TLSA Record. + +- `read` - (Defaults to 5 minutes) Used when retrieving the DNS TLSA Record. + +- `delete` - (Defaults to 30 minutes) Used when deleting the DNS TLSA Record. + +## Import + +TLSA records can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_dns_tlsa_record.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Network/dnsZones/zone1/TLSA/myrecord1 +```