Skip to content

Commit

Permalink
Add trigger on create and fixes
Browse files Browse the repository at this point in the history
Provider docs
Request which was generating an asn1 error
Add trigger value on create resource to trigger a recreate when changed
  • Loading branch information
axon-droe committed Jul 11, 2024
1 parent d9079e6 commit f17a5f8
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 14 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
83 changes: 76 additions & 7 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -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 generated by tfplugindocs -->
## 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 = [
"[email protected]",
]
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
4 changes: 4 additions & 0 deletions docs/resources/create.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions internal/provider/create_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}

Expand Down Expand Up @@ -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,
Expand Down
2 changes: 0 additions & 2 deletions internal/provider/merge_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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{
Expand Down
8 changes: 6 additions & 2 deletions internal/provider/request_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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())
Expand Down Expand Up @@ -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",
Expand Down
85 changes: 85 additions & 0 deletions templates/index.md.tmpl
Original file line number Diff line number Diff line change
@@ -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 = [
"[email protected]",
]
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

0 comments on commit f17a5f8

Please sign in to comment.