-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Terraform Data Source to get DNSKEY records of DNSSEC-signed managed zones #3117
Merged
slevenick
merged 18 commits into
GoogleCloudPlatform:master
from
chrissng:get-dnssec-key-pairs
Feb 18, 2020
Merged
Changes from 13 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
0e23520
Merge pull request #1 from GoogleCloudPlatform/master
chrissng d821416
DNSSEC Keys
chrissng 9423899
update schema
chrissng 4efd907
Define as a data source
chrissng df6b998
add into data sources map
chrissng f265f63
remove unused import
chrissng ace5d32
add tests
chrissng d1a1452
No fill dns keys of zone is not dnssec enabled
chrissng 37296b1
add docs
chrissng 53cfac9
add ds record to ksk
chrissng 623d5b6
fix string templating
chrissng 7cc51a2
improve doc description
chrissng 6def1c0
improve ds record generation
chrissng 97abc5a
Update third_party/terraform/website/docs/d/datasource_dns_key.html.m…
chrissng 34a5433
rename data source in plural
chrissng 03edd76
Merge branch 'get-dnssec-key-pairs' of github.com:chrissng/magic-modu…
chrissng cc1770f
rename file, add comment on maps
chrissng 0291d90
rename doc file
chrissng File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
215 changes: 215 additions & 0 deletions
215
third_party/terraform/data_sources/data_source_dns_key.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema" | ||
"google.golang.org/api/dns/v1" | ||
) | ||
|
||
var dnssecAlgoNums = map[string]int{ | ||
"rsasha1": 5, | ||
"rsasha256": 8, | ||
"rsasha512": 10, | ||
"ecdsap256sha256": 13, | ||
"ecdsap384sha384": 14, | ||
} | ||
|
||
var dnssecDigestType = map[string]int{ | ||
"sha1": 1, | ||
"sha256": 2, | ||
"sha384": 4, | ||
} | ||
|
||
func dataSourceDNSKey() *schema.Resource { | ||
return &schema.Resource{ | ||
Read: dataSourceDNSKeyRead, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"managed_zone": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
DiffSuppressFunc: compareSelfLinkOrResourceName, | ||
}, | ||
"project": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Computed: true, | ||
ForceNew: true, | ||
}, | ||
"key_signing_keys": { | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Elem: kskResource(), | ||
}, | ||
"zone_signing_keys": { | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Elem: dnsKeyResource(), | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dnsKeyResource() *schema.Resource { | ||
return &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"algorithm": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"creation_time": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"description": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"digests": { | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"digest": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
"type": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"is_active": { | ||
Type: schema.TypeBool, | ||
Computed: true, | ||
}, | ||
"key_length": { | ||
Type: schema.TypeInt, | ||
Computed: true, | ||
}, | ||
"key_tag": { | ||
Type: schema.TypeInt, | ||
Computed: true, | ||
}, | ||
"public_key": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func kskResource() *schema.Resource { | ||
resource := dnsKeyResource() | ||
|
||
resource.Schema["ds_record"] = &schema.Schema{ | ||
Type: schema.TypeString, | ||
Computed: true, | ||
} | ||
|
||
return resource | ||
} | ||
|
||
func generateDSRecord(signingKey *dns.DnsKey) (string, error) { | ||
algoNum, found := dnssecAlgoNums[signingKey.Algorithm] | ||
if !found { | ||
return "", fmt.Errorf("DNSSEC Algorithm number for %s not found", signingKey.Algorithm) | ||
} | ||
|
||
digestType, found := dnssecDigestType[signingKey.Digests[0].Type] | ||
if !found { | ||
return "", fmt.Errorf("DNSSEC Digest type for %s not found", signingKey.Digests[0].Type) | ||
} | ||
|
||
return fmt.Sprintf("%d %d %d %s", | ||
signingKey.KeyTag, | ||
algoNum, | ||
digestType, | ||
signingKey.Digests[0].Digest), nil | ||
} | ||
|
||
func flattenSigningKeys(signingKeys []*dns.DnsKey, keyType string) []map[string]interface{} { | ||
var keys []map[string]interface{} | ||
|
||
for _, signingKey := range signingKeys { | ||
if signingKey != nil && signingKey.Type == keyType { | ||
data := map[string]interface{}{ | ||
"algorithm": signingKey.Algorithm, | ||
"creation_time": signingKey.CreationTime, | ||
"description": signingKey.Description, | ||
"digests": flattenDigests(signingKey.Digests), | ||
"id": signingKey.Id, | ||
"is_active": signingKey.IsActive, | ||
"key_length": signingKey.KeyLength, | ||
"key_tag": signingKey.KeyTag, | ||
"public_key": signingKey.PublicKey, | ||
} | ||
|
||
if signingKey.Type == "keySigning" && len(signingKey.Digests) > 0 { | ||
dsRecord, err := generateDSRecord(signingKey) | ||
if err == nil { | ||
data["ds_record"] = dsRecord | ||
} | ||
} | ||
|
||
keys = append(keys, data) | ||
} | ||
} | ||
|
||
return keys | ||
} | ||
|
||
func flattenDigests(dnsKeyDigests []*dns.DnsKeyDigest) []map[string]interface{} { | ||
var digests []map[string]interface{} | ||
|
||
for _, dnsKeyDigest := range dnsKeyDigests { | ||
if dnsKeyDigest != nil { | ||
data := map[string]interface{}{ | ||
"digest": dnsKeyDigest.Digest, | ||
"type": dnsKeyDigest.Type, | ||
} | ||
|
||
digests = append(digests, data) | ||
} | ||
} | ||
|
||
return digests | ||
} | ||
|
||
func dataSourceDNSKeyRead(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
fv, err := parseProjectFieldValue("managedZones", d.Get("managed_zone").(string), "project", d, config, false) | ||
if err != nil { | ||
return err | ||
} | ||
project := fv.Project | ||
managedZone := fv.Name | ||
|
||
d.Set("project", project) | ||
d.SetId(fmt.Sprintf("projects/%s/managedZones/%s", project, managedZone)) | ||
|
||
log.Printf("[DEBUG] Fetching DNS keys from managed zone %s", managedZone) | ||
|
||
response, err := config.clientDns.DnsKeys.List(project, managedZone).Do() | ||
if err != nil && !isGoogleApiErrorWithCode(err, 404) { | ||
return fmt.Errorf("error retrieving DNS keys: %s", err) | ||
} else if isGoogleApiErrorWithCode(err, 404) { | ||
return nil | ||
} | ||
|
||
log.Printf("[DEBUG] Fetched DNS keys from managed zone %s", managedZone) | ||
|
||
d.Set("key_signing_keys", flattenSigningKeys(response.DnsKeys, "keySigning")) | ||
d.Set("zone_signing_keys", flattenSigningKeys(response.DnsKeys, "zoneSigning")) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource" | ||
) | ||
|
||
func TestAccDataSourceDNSKey_basic(t *testing.T) { | ||
t.Parallel() | ||
|
||
dnsZoneName := fmt.Sprintf("data-dnskey-test-%s", acctest.RandString(10)) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckDNSManagedZoneDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccDataSourceDNSKeyConfig(dnsZoneName, "on"), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_dns_key.foo_dns_key", "key_signing_keys.#", "1"), | ||
resource.TestCheckResourceAttr("data.google_dns_key.foo_dns_key", "zone_signing_keys.#", "1"), | ||
resource.TestCheckResourceAttr("data.google_dns_key.foo_dns_key_id", "key_signing_keys.#", "1"), | ||
resource.TestCheckResourceAttr("data.google_dns_key.foo_dns_key_id", "zone_signing_keys.#", "1"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccDataSourceDNSKey_noDnsSec(t *testing.T) { | ||
t.Parallel() | ||
|
||
dnsZoneName := fmt.Sprintf("data-dnskey-test-%s", acctest.RandString(10)) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckDNSManagedZoneDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccDataSourceDNSKeyConfig(dnsZoneName, "off"), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_dns_key.foo_dns_key", "key_signing_keys.#", "0"), | ||
resource.TestCheckResourceAttr("data.google_dns_key.foo_dns_key", "zone_signing_keys.#", "0"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccDataSourceDNSKeyConfig(dnsZoneName, dnssecStatus string) string { | ||
return fmt.Sprintf(` | ||
resource "google_dns_managed_zone" "foo" { | ||
name = "%s" | ||
dns_name = "dnssec.tf-test.club." | ||
|
||
dnssec_config { | ||
state = "%s" | ||
non_existence = "nsec3" | ||
} | ||
} | ||
|
||
data "google_dns_key" "foo_dns_key" { | ||
managed_zone = google_dns_managed_zone.foo.name | ||
} | ||
|
||
data "google_dns_key" "foo_dns_key_id" { | ||
managed_zone = google_dns_managed_zone.foo.id | ||
} | ||
`, dnsZoneName, dnssecStatus) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
third_party/terraform/website/docs/d/datasource_dns_key.html.markdown
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
--- | ||
subcategory: "Cloud DNS" | ||
layout: "google" | ||
page_title: "Google: google_dns_key" | ||
sidebar_current: "docs-google-datasource-dns-key" | ||
description: |- | ||
Get DNSKEY and DS records of DNSSEC-signed managed zones. | ||
--- | ||
|
||
# google\_dns\_key | ||
|
||
Get the DNSKEY and DS records of DNSSEC-signed managed zones. For more information see the | ||
[official documentation](https://cloud.google.com/dns/docs/dnskeys/) | ||
and [API](https://cloud.google.com/dns/docs/reference/v1/dnsKeys). | ||
|
||
|
||
## Example Usage | ||
|
||
```hcl | ||
resource "google_dns_managed_zone" "foo" { | ||
name = "foobar" | ||
dns_name = "foo.bar." | ||
|
||
dnssec_config { | ||
state = "on" | ||
non_existence = "nsec3" | ||
} | ||
} | ||
|
||
data "google_dns_key" "foo_dns_key" { | ||
managed_zone = google_dns_managed_zone.foo.id | ||
} | ||
|
||
output "foo_dns_ds_record" { | ||
description = "DS record of the foo subdomain." | ||
value = data.google_dns_key.foo_dns_key.key_signing_keys[0].ds_record | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `managed_zone` - (Required) The name or id of the Cloud DNS managed zone. | ||
|
||
* `project` - (Optional) The ID of the project in which the resource belongs. If `project` is not provided, the provider project is used. | ||
|
||
## Attributes Reference | ||
|
||
The following attributes are exported: | ||
|
||
* `key_signing_keys` - A list of Key-signing key (KSK) records. Structure is documented below. Additionally, the DS record is provided: | ||
* `ds_record` - The DS record based on the KSK record. This is used when [delegating](https://cloud.google.com/dns/docs/dnssec-advanced#subdelegation) DNSSEC-signed subdomains. | ||
|
||
* `zone_signing_keys` - A list of Zone-signing key (ZSK) records. Structure is documented below. | ||
|
||
--- | ||
|
||
The `key_signing_keys` and `zone_signing_keys` block supports: | ||
* `algorithm` - String mnemonic specifying the DNSSEC algorithm of this key. Immutable after creation time. Possible values are `ecdsap256sha256`, `ecdsap384sha384`, `rsasha1`, `rsasha256`, and `rsasha512`. | ||
* `creation_time` - The time that this resource was created in the control plane. This is in RFC3339 text format. | ||
* `description` - A mutable string of at most 1024 characters associated with this resource for the user's convenience. | ||
* `digest` - A list of cryptographic hashes of the DNSKEY resource record associated with this DnsKey. These digests are needed to construct a DS record that points at this DNS key. Each contains: | ||
chrissng marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- `digest` - The base-16 encoded bytes of this digest. Suitable for use in a DS resource record. | ||
- `type` - Specifies the algorithm used to calculate this digest. Possible values are `sha1`, `sha256` and `sha384` | ||
* `id` - Unique identifier for the resource; defined by the server. | ||
* `is_active` - Active keys will be used to sign subsequent changes to the ManagedZone. Inactive keys will still be present as DNSKEY Resource Records for the use of resolvers validating existing signatures. | ||
* `key_length` - Length of the key in bits. Specified at creation time then immutable. | ||
* `key_tag` - The key tag is a non-cryptographic hash of the a DNSKEY resource record associated with this DnsKey. The key tag can be used to identify a DNSKEY more quickly (but it is not a unique identifier). In particular, the key tag is used in a parent zone's DS record to point at the DNSKEY in this child ManagedZone. The key tag is a number in the range [0, 65535] and the algorithm to calculate it is specified in RFC4034 Appendix B. | ||
* `public_key` - Base64 encoded public half of this key. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense for this resource to be named
google_dns_keys
instead. It returns a collection of keys rather than an individual keyThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it!