From f17a5f8c2adb45a746d2d88456950f857de5b0ac Mon Sep 17 00:00:00 2001 From: David Roe Date: Thu, 11 Jul 2024 14:13:48 -0700 Subject: [PATCH] Add trigger on create and fixes Provider docs Request which was generating an asn1 error Add trigger value on create resource to trigger a recreate when changed --- README.md | 6 +- docs/index.md | 83 +++++++++++++++++++++++--- docs/resources/create.md | 4 ++ internal/provider/create_resource.go | 8 +++ internal/provider/merge_resource.go | 2 - internal/provider/request_resource.go | 8 ++- templates/index.md.tmpl | 85 +++++++++++++++++++++++++++ 7 files changed, 182 insertions(+), 14 deletions(-) create mode 100644 templates/index.md.tmpl diff --git a/README.md b/README.md index d696ed2..1419b53 100644 --- a/README.md +++ b/README.md @@ -30,13 +30,13 @@ resource "azurekvca_create" "test" { key_type = "RSA" reuse_key = true } + + trigger = "Change me to trigger a recreate" } # Optionally mangle the CSR to add values not supported by Azure (URI SAN for example) resource "azurekvca_request" "test" { - vault_url = azurekvca_create.test.vault_url - key_name = azurekvca_create.test.name - + vault_url = azurekvca_create.test.vault_url csr_pem_in = azurekvca_create.test.csr_pem names = { diff --git a/docs/index.md b/docs/index.md index 5c2729a..1b64842 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,16 +1,85 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs -page_title: "azurekvca Provider" -subcategory: "" +page_title: "Provider: AzureKVCA" description: |- - + The Random provider is used to generate randomness. --- -# azurekvca Provider +# Terraform Provider for using Azure KeyVault as a CA +Traditionally using Azure KeyVault(KV) as a CA requires exporting the CA private key into terraform where it gets saved into state. +KV has support for a sign operation on stored keys regardless of their exportability. With a little work this sign operation can be used to generate certificates. +This provider encapsulates that functionality +# Example Usage - -## Schema +```hcl +terraform { + required_providers { + azurekvca = { + source = "OpenAxon/azurekvca" + } + } +} + +provider "azurekvca" {} + +# Generate a new cert version (and cert if needed) +resource "azurekvca_create" "test" { + vault_url = "https://something.vault.azure.net/" + name = "test-cert" + + key = { + exportable = true + key_size = 2048 + key_type = "RSA" + reuse_key = true + } + + trigger = "Change me to trigger a recreate" +} + +# Optionally mangle the CSR to add values not supported by Azure (URI SAN for example) +resource "azurekvca_request" "test" { + vault_url = azurekvca_create.test.vault_url + csr_pem_in = azurekvca_create.test.csr_pem + + names = { + email = [ + "test@test.com", + ] + dns = [ + "test.com" + ] + ip = [ + "127.0.0.1" + ] + uri = [ + "spiffe://test" + ] + } +} + +# Sign CSR with CA cert in Key Vault. This does not check the CSR signature just blindly pulls the public key, subject and SAN from the request +resource "azurekvca_sign" "test" { + vault_url = "https://something.vault.azure.net/" + ca_name = "test-ca" + validity_days = 30 + signature_algorithm = "RS256" + csr_pem = azurekvca_request.test.csr_pem_out +} + +# Merge the signed cert back into the original request +resource "azurekvca_merge" "test" { + vault_url = azurekvca_create.test.vault_url + name = azurekvca_create.test.name + cert_pem = azurekvca_sign.test.signed_cert_pem +} + +``` + +# TODO +* Create and Merge resources don't attempt to sync their state with the Azure +* Create doesn't support self-signed or CA certs for creating the CA itself +* Only support for PEM certs so far, no pkcs12 diff --git a/docs/resources/create.md b/docs/resources/create.md index 946214e..350b905 100644 --- a/docs/resources/create.md +++ b/docs/resources/create.md @@ -21,6 +21,10 @@ Create a new certificate version and if needed cert ready for signing - `name` (String) Name of cert to create - `vault_url` (String) URL of Azure Key Vault +### Optional + +- `trigger` (String) String value that when changed triggers a recreate. Good for triggering rotations + ### Read-Only - `csr_pem` (String) Resulting CSR in PEM format diff --git a/internal/provider/create_resource.go b/internal/provider/create_resource.go index 6ee58b4..56b8318 100644 --- a/internal/provider/create_resource.go +++ b/internal/provider/create_resource.go @@ -41,6 +41,7 @@ type createResourceModel struct { CSRPEM types.String `tfsdk:"csr_pem"` Key createKey `tfsdk:"key"` Name types.String `tfsdk:"name"` + Trigger types.String `tfsdk:"trigger"` VaultURL types.String `tfsdk:"vault_url"` } @@ -94,6 +95,13 @@ func (r *createResource) Schema(_ context.Context, _ resource.SchemaRequest, res stringplanmodifier.RequiresReplace(), }, }, + "trigger": schema.StringAttribute{ + MarkdownDescription: "String value that when changed triggers a recreate. Good for triggering rotations", + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, "vault_url": schema.StringAttribute{ MarkdownDescription: "URL of Azure Key Vault", Required: true, diff --git a/internal/provider/merge_resource.go b/internal/provider/merge_resource.go index a7b755d..a2fd7e0 100644 --- a/internal/provider/merge_resource.go +++ b/internal/provider/merge_resource.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-log/tflog" ) // Ensure the implementation satisfies the expected interfaces. @@ -100,7 +99,6 @@ func (r *mergeResource) Create(ctx context.Context, req resource.CreateRequest, } certBase64 := base64.StdEncoding.EncodeToString(certBlock.Bytes) - tflog.Info(ctx, certBase64) var certs = [][]byte{[]byte(certBase64)} certParams := azcertificates.MergeCertificateParameters{ diff --git a/internal/provider/request_resource.go b/internal/provider/request_resource.go index d3f9532..4e5b593 100644 --- a/internal/provider/request_resource.go +++ b/internal/provider/request_resource.go @@ -126,7 +126,7 @@ func (r *requestResource) Create(ctx context.Context, req resource.CreateRequest return } - template, err := x509.ParseCertificateRequest(csrBlock.Bytes) + parsedCSR, err := x509.ParseCertificateRequest(csrBlock.Bytes) if err != nil { resp.Diagnostics.AddError( "Error decoding CSR", @@ -135,6 +135,10 @@ func (r *requestResource) Create(ctx context.Context, req resource.CreateRequest return } + template := &x509.CertificateRequest{ + Subject: parsedCSR.Subject, + } + if plan.Names.Email != nil { for i := 0; i < len(plan.Names.Email); i++ { template.EmailAddresses = append(template.EmailAddresses, plan.Names.Email[i].ValueString()) @@ -175,7 +179,7 @@ func (r *requestResource) Create(ctx context.Context, req resource.CreateRequest } } - signer, err := NewAzureKVSigner(ctx, *r.azureCred, plan.VaultURL.ValueString(), "", "", template.PublicKey) + signer, err := NewAzureKVSigner(ctx, *r.azureCred, plan.VaultURL.ValueString(), "", "", parsedCSR.PublicKey) if err != nil { resp.Diagnostics.AddError( "Error creating signer", diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl new file mode 100644 index 0000000..1b64842 --- /dev/null +++ b/templates/index.md.tmpl @@ -0,0 +1,85 @@ +--- +page_title: "Provider: AzureKVCA" +description: |- + The Random provider is used to generate randomness. +--- + +# Terraform Provider for using Azure KeyVault as a CA + +Traditionally using Azure KeyVault(KV) as a CA requires exporting the CA private key into terraform where it gets saved into state. + +KV has support for a sign operation on stored keys regardless of their exportability. With a little work this sign operation can be used to generate certificates. + +This provider encapsulates that functionality + +# Example Usage + +```hcl +terraform { + required_providers { + azurekvca = { + source = "OpenAxon/azurekvca" + } + } +} + +provider "azurekvca" {} + +# Generate a new cert version (and cert if needed) +resource "azurekvca_create" "test" { + vault_url = "https://something.vault.azure.net/" + name = "test-cert" + + key = { + exportable = true + key_size = 2048 + key_type = "RSA" + reuse_key = true + } + + trigger = "Change me to trigger a recreate" +} + +# Optionally mangle the CSR to add values not supported by Azure (URI SAN for example) +resource "azurekvca_request" "test" { + vault_url = azurekvca_create.test.vault_url + csr_pem_in = azurekvca_create.test.csr_pem + + names = { + email = [ + "test@test.com", + ] + dns = [ + "test.com" + ] + ip = [ + "127.0.0.1" + ] + uri = [ + "spiffe://test" + ] + } +} + +# Sign CSR with CA cert in Key Vault. This does not check the CSR signature just blindly pulls the public key, subject and SAN from the request +resource "azurekvca_sign" "test" { + vault_url = "https://something.vault.azure.net/" + ca_name = "test-ca" + validity_days = 30 + signature_algorithm = "RS256" + csr_pem = azurekvca_request.test.csr_pem_out +} + +# Merge the signed cert back into the original request +resource "azurekvca_merge" "test" { + vault_url = azurekvca_create.test.vault_url + name = azurekvca_create.test.name + cert_pem = azurekvca_sign.test.signed_cert_pem +} + +``` + +# TODO +* Create and Merge resources don't attempt to sync their state with the Azure +* Create doesn't support self-signed or CA certs for creating the CA itself +* Only support for PEM certs so far, no pkcs12