-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Adds support for creating KMS CryptoKeys resources #692
Conversation
1c4023a
to
23535fa
Compare
Still need to add docs. Pushing now so that I can see the result of running the acceptance test because I've not yet figured out access to a setup with permissions to run acceptance tests. |
Hey @amfarrell, looks like this doesn't build. Happy to run the tests for you once that's all squared away. |
900fe2e
to
2cb6a47
Compare
2cb6a47
to
0aa931e
Compare
@danawillow This should now build. Interface looks like resource "google_kms_key_ring" "mykeyring" {
location = "global"
name = "mykeyring"
project = "myproject"
}
resource "google_kms_crypto_key" "mykey" {
name = "mykey"
key_ring = "${google_kms_key_ring.mykeyring.id}"
}
resource "google_kms_crypto_key" "myrotatingkey" {
name = "myrotatingkey"
key_ring = "${google_kms_key_ring.mykeyring.id}"
# Next rotation time will be set automatically to now + rotation_period
rotation_period = "100000s"
} |
cc @mrparkers |
google/resource_kms_crypto_key.go
Outdated
|
||
log.Printf("[WARNING] KMS CryptoKey resources cannot be deleted from GCP. This CryptoKey %s will be removed from Terraform state, but will still be present on the server.", cryptoKeyId.cryptoKeyId()) | ||
|
||
d.SetId("") |
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.
We probably shouldn't do this until the very end of the function. clearCryptoKeyVersions
could still error.
google/resource_kms_crypto_key.go
Outdated
return err | ||
} | ||
|
||
log.Printf("[WARNING] KMS CryptoKey resources cannot be deleted from GCP. This CryptoKey %s will be removed from Terraform state, but will still be present on the server.", cryptoKeyId.cryptoKeyId()) |
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.
It might be helpful to add the bit about destroying all of the CryptoKey's versions to this warning message.
google/resource_kms_crypto_key.go
Outdated
|
||
if cryptoKeyIdWithoutProjectRegex.MatchString(id) { | ||
if config.Project == "" { | ||
return nil, fmt.Errorf("The default project for the provider must be set when using the `{location}/{cryptoKeyName}` id format.") |
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.
You're missing the keyRingName
in the example format
google/resource_kms_crypto_key.go
Outdated
}, nil | ||
} | ||
|
||
return nil, fmt.Errorf("Invalid CryptoKey id format, expecting `{projectId}/{locationId}/{KeyringName}/{cryptoKeyName}` or `{locationId}/{KeyringName}/{cryptoKeyName}.`") |
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.
Nitpick: Could you use keyRingName
instead of KeyringName
here?
google/resource_kms_crypto_key.go
Outdated
|
||
if d.Get("purpose") == "" { | ||
d.Set("purpose", "ENCRYPT_DECRYPT") | ||
} |
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.
Is this needed? purpose
isn't defined in your resource schema.
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.
It's one of those weird ones you get in GCP (and AWS as well) where there is a parameter that accepts an enum with one possible value (see the REST API docs for CryptoKey). My feeling is that it is not necessary to support this parameter as an argument to the resource, and instead just set it 'on the quiet', until there is another purpose value defined, at which point it will in any case be necessary to add more validation. But I'm new to the Terraform codebases, so perhaps it is better to be explicit but have a default?
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.
It looks like its only being set during import though, not creation. I think we should either set it in both places, or neither. Like you mentioned, there's only one possible value for this enum, so I think we should just get rid of it until more are added.
resource "google_kms_crypto_key" "crypto_key" { | ||
name = "%s" | ||
key_ring = "${google_kms_key_ring.key_ring.id}" | ||
rotation_period = "100000s" |
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.
Could you fix the formatting here?
@@ -0,0 +1,63 @@ | |||
--- | |||
layout: "google" | |||
page_title: "Google: google_kms_key_ring" |
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.
Could you fix this? Should be google_kms_crypto_key
name = "my-crypto-key" | ||
key_ring = "my_project/us-central1/my-key-ring" | ||
rotation_period = "100000s" | ||
} |
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.
It might be nice to include a google_kms_key_ring
resource here as well, so you could demonstrate using string interpolation for the key_ring
field.
``` | ||
$ terraform import google_kms_key_ring.my_key_ring my-gcp-project/us-central1/my-key-ring/my-crypto-key | ||
|
||
$ terraform import google_kms_key_ring.my_key_ring us-central1/my-key-ring/my-crypto-key |
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.
The resource name should be google_kms_crypto_key.my_crypto_key
ExpectedCryptoKeyId: "projects/test-project/locations/us-central1/keyRings/test-key-ring/cryptoKeys/test-key-id", | ||
Config: &Config{Project: "test-project"}, | ||
}, | ||
"id is in location/keyRingName/CyptoKeyID format without project in config": { |
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.
Nitpick: For each of these test descriptions, could you use cryptoKeyName
instead of CryptoKeyID
? This way, the format will be consistent with the error messages in parseKmsCryptoKeyId
google/resource_kms_crypto_key.go
Outdated
"rotation_period": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, |
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 believe a CryptoKey's rotation period can be changed, or at least there's an API for it.
If this changed, Update
would have to be implemented as well. This change probably doesn't need to hold up the PR, but @danawillow can make that call.
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 did bump into this, actually, but decided to defer it.
On reflection, it might be worth doing given that you can't destroy the damn things properly...
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'm fine with deferring it to a follow-up PR!
google/resource_kms_crypto_key.go
Outdated
d.SetId(cryptoKeyId.terraformId()) | ||
|
||
return []*schema.ResourceData{d}, nil | ||
} |
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.
It might be a good idea to set rotation_period
if it exists.
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.
Done - further up so comment isn't hidden ...
Also add more detail to warning message.
|
||
resource "google_kms_crypto_key" "crypto_key" { | ||
name = "%s" | ||
key_ring = "${google_kms_key_ring.key_ring.id}" |
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.
Could you fix this indentation?
resource "google_kms_crypto_key" "crypto_key" { | ||
name = "%s" | ||
key_ring = "${google_kms_key_ring.key_ring.id}" | ||
rotation_period = "%s" |
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.
Here as well
@tragiclifestories sorry for the confusion about the indentation. Most of it was fine, there were just a couple of lines where spaces were used instead of tabs. It looks like they were all changed to use spaces, which will probably need to be changed back to tabs. The only reason I'm asking is because I received similar comments on my PR 😉 |
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.
Thanks for those changes, this looks good to me
And thanks for a very thorough review - I'm quite new to mucking about with terraform internals so it's all helpful! |
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.
Thanks @amfarrell, this is super exciting!
And wow @mrparkers you rock, thanks for making my life a lot easier by reviewing this!
I have a bunch of comments, but most of them are pretty small- overall this looks really good.
"os" | ||
) | ||
|
||
func TestAccGoogleKmsCryptoKey_importBasic(t *testing.T) { |
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.
Can you add t.Parallel()
(and then a newline) to the beginning of all tests?
google/resource_kms_crypto_key.go
Outdated
"rotation_period": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, |
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'm fine with deferring it to a follow-up PR!
google/resource_kms_crypto_key.go
Outdated
if err != nil { | ||
return fmt.Errorf("Error reading CryptoKey: %s", err) | ||
} | ||
|
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.
Generally we like to set as many fields as possible inside of Read
, in order to catch out-of-band modifications.
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.
Just curious, are you just looking for rotation_period
here? Or would you also set name
and key_ring
by getting it from cryptoKeyId
?
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 went for Actually, in relation to the import passthrough comment I realised that it would be better to set them all here anyway.rotation_period
only, since I believe the other fields are immutable anyway. although the docs are unclear about this.
google/resource_kms_crypto_key.go
Outdated
return nil | ||
} | ||
|
||
func validateKmsCryptoKeyRotationPeriod(period string) error { |
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.
This could actually probably become a ValidateFunc, which would allow doing these checks during terraform plan
instead of during terraform apply
. Here's an example of what that would look like (this example has it inlined but it can certainly be a separate fn): https://github.com/terraform-providers/terraform-provider-google/blob/master/google/resource_dataproc_cluster.go#L39
google/resource_kms_crypto_key.go
Outdated
return nil, fmt.Errorf("Invalid CryptoKey id format, expecting `{projectId}/{locationId}/{KeyringName}/{cryptoKeyName}` or `{locationId}/{keyRingName}/{cryptoKeyName}.`") | ||
} | ||
|
||
func resourceKmsCryptoKeyImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { |
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 this is actually similar enough to the Read fn that you don't need a separate Import fn, but instead could use the passthrough one:
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Then inside the read function, you would do the same d.Set
calls that you're doing here, plus an additional one for the rotation_period
.
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckGoogleKmsCryptoKeyWasRemovedFromState("google_kms_crypto_key.crypto_key"), |
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.
Since your second TestStep
calls this already, this is just duplicating that check- not wrong, but also not necessary.
|
||
_, err = time.Parse(time.RFC3339Nano, getCryptoKeyResponse.NextRotationTime) | ||
|
||
return err |
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.
It might be worth it to wrap this error, something like return fmt.Errorf("Error parsing NextRotationTime: %s", err)
config := testAccProvider.Meta().(*Config) | ||
gcpResourceUri := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", projectId, location, keyRingName, cryptoKeyName) | ||
|
||
response, _ := config.clientKms.Projects.Locations.KeyRings.CryptoKeys.CryptoKeyVersions.List(gcpResourceUri).Do() |
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'd feel more comfortable if this error were handled: if we got a mysterious server error, then response.CryptoKeyVersions
would (I believe) be empty, which means this test would succeed, even though we don't actually know that the versions were destroyed.
} | ||
|
||
resource "google_kms_key_ring" "key_ring" { | ||
project = "${google_project.acceptance.project_id}" |
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.
Let's also use ${google_project_services.acceptance.project}
like in the basic test, so that we guarantee the API is enabled before trying to use it.
} | ||
|
||
resource "google_kms_key_ring" "key_ring" { | ||
project = "${google_project.acceptance.project_id}" |
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.
here too
Whoops sorry @tragiclifestories, I should be thanking you! |
@danawillow I think that's everything ... |
google/resource_kms_crypto_key.go
Outdated
func parseKmsCryptoKeyId(id string, config *Config) (*kmsCryptoKeyId, error) { | ||
parts := strings.Split(id, "/") | ||
|
||
cryptoKeyIdRegex := regexp.MustCompile("^([a-z0-9-]+)/([a-z0-9-])+/([a-zA-Z0-9_-]{1,63})+/([a-zA-Z0-9_-]{1,63})$") |
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.
Sorry I didn't catch this earlier- shouldn't the third plus not be there since it already has the {1, 63}? I think that would end up essentially overriding the {1, 63} by allowing it to repeat some number of times
google/resource_kms_crypto_key.go
Outdated
parts := strings.Split(id, "/") | ||
|
||
cryptoKeyIdRegex := regexp.MustCompile("^([a-z0-9-]+)/([a-z0-9-])+/([a-zA-Z0-9_-]{1,63})+/([a-zA-Z0-9_-]{1,63})$") | ||
cryptoKeyIdWithoutProjectRegex := regexp.MustCompile("^([a-z0-9-])+/([a-zA-Z0-9_-]{1,63})+/([a-zA-Z0-9_-]{1,63})$") |
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.
likewise
} | ||
|
||
/* | ||
Because KMS CryptoKey resources cannot be deleted on GCP, we are only going to remove it from state |
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.
nit: this comment has mismatched tabs/spaces for indentation, mind choosing one or the other?
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.
Fixed
google/resource_kms_crypto_key.go
Outdated
Name string | ||
} | ||
|
||
// TODO: Add the info about rotation frequency and start time. |
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.
nit: can you be a bit more specific here as to what you're adding it to? I don't think it belongs in the id, which is the section of code this comment is living in.
Looks great, thanks so much @tragiclifestories! |
You're welcome, and thanks for the thorough review! |
Somehow this snuck in to #692 but it doesn't look like it's actually used anywhere.
Somehow this snuck in to #692 but it doesn't look like it's actually used anywhere.
* Adds support for creating KMS CryptoKeys resources * Destroy extant CryptoKeyVersions on CryptoKey destroy * Inherit project, location etc from KeyRing in CryptoKey * Add function to calculate next rotation * Implement RotationPeriod parameter on CryptoKey * Import CryptoKey state * Uncommit my local acceptance test hacks * Docs for google_kms_crypto_key * Clear id at the end of CryptoKey deletion Also add more detail to warning message. * Fix parseCryptoKeyId error messages * Use correct naming in CryptoKeyIdParsing test * Check RotationPeriod is present in acceptance test * Rename variable in test function for consistency * Fix wrong resource name in cryptokey docs * Add KeyRing to CryptoKey doc example * Run test CryptoKey configs through terraform fmt * Don't set CryptoKey purpose in terraform state on import * Fix indentation in CryptoKey test * Parallelise CryptoKey tests * Set rotation_key on CryptoKey read * Move RotationPeriod validation to planning phase * Use import state passthrough for CryptoKey * Correct casing issues in test case names * Remove redundant CheckDestroy calls in CryptoKey tests * Add explanatory comment about extra test steps * More explicit error handling in CryptoKey tests * Explicit dependency on project services in test keyring configs * Clean up comments in cryptokey resource * Do not repeat in cryptokey id regexes
…ashicorp#689)" (hashicorp#692) This reverts commit e46f436.
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 [email protected]. Thanks! |
No description provided.