Skip to content

Commit

Permalink
Support complex configuration in consul_certificate_authority (#341)
Browse files Browse the repository at this point in the history
When configuration Consul to use Vault as the certificate authority
provider for Consul Connect the configuration can have more than strings
so we need to use jsonencode for Terraform to accept the configuration.

Also remove the copyright notices in the examples.

Closes #324
  • Loading branch information
remilapeyre committed Jul 24, 2023
1 parent 8b89c8a commit 5f1ede6
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 191 deletions.
67 changes: 58 additions & 9 deletions consul/resource_consul_certificate_authority.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package consul

import (
"encoding/json"
"fmt"

consulapi "github.com/hashicorp/consul/api"
Expand All @@ -19,18 +20,39 @@ func resourceConsulCertificateAuthority() *schema.Resource {
State: schema.ImportStatePassthrough,
},

Description: "The `consul_certificate_authority` resource can be used to manage the configuration of the Certificate Authority used by [Consul Connect](https://www.consul.io/docs/connect/ca).\n\n-> **Note:** The keys in the `config` argument must be using Camel case.",

Schema: map[string]*schema.Schema{
"connect_provider": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Specifies the CA provider type to use.",
},

"config": {
Type: schema.TypeMap,
Required: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
Type: schema.TypeMap,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "The raw configuration to use for the chosen provider. For more information on configuring the Connect CA providers, see [Provider Config](https://developer.hashicorp.com/consul/docs/connect/ca).",
Deprecated: "The config attribute is deprecated, please use config_json instead.",
ConflictsWith: []string{"config_json"},
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return new == "" || new == "0"
},
},

"config_json": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "The raw configuration to use for the chosen provider. For more information on configuring the Connect CA providers, see [Provider Config](https://developer.hashicorp.com/consul/docs/connect/ca).",
ConflictsWith: []string{"config"},
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return new == "" || new == "0"
},
},
},
}
Expand All @@ -39,9 +61,23 @@ func resourceConsulCertificateAuthority() *schema.Resource {
func resourceConsulCertificateAuthorityCreate(d *schema.ResourceData, meta interface{}) error {
client, _, wOpts := getClient(d, meta)

var config map[string]interface{}
if c := d.Get("config_json").(string); c != "" {
err := json.Unmarshal([]byte(c), &config)
if err != nil {
return fmt.Errorf("failed to read 'config_json': %v", err)
}
} else {
config = d.Get("config").(map[string]interface{})
}

if len(config) == 0 {
return fmt.Errorf("one of 'config' or 'config_json' must be set")
}

caConfig := &consulapi.CAConfig{
Provider: d.Get("connect_provider").(string),
Config: d.Get("config").(map[string]interface{}),
Config: config,
}

if _, err := client.Connect().CASetConfig(caConfig, wOpts); err != nil {
Expand All @@ -64,7 +100,20 @@ func resourceConsulCertificateAuthorityRead(d *schema.ResourceData, meta interfa
sw := newStateWriter(d)

sw.set("connect_provider", conf.Provider)
sw.set("config", conf.Config)
sw.setJson("config_json", conf.Config)

if err = d.Set("config", conf.Config); err != nil {
// When a complex configuration is used we can fail to set config as it
// will not support fields with maps or lists in them. In this case it
// means that the user used the 'config_json' field, and since we
// succeeded to set that and 'config' is deprecated, we can just use
// an empty placeholder value and ignore the error.
if c := d.Get("config_json").(string); c != "" {
sw.set("config", map[string]interface{}{})
} else {
return fmt.Errorf("failed to set 'config': %v", err)
}
}

return sw.error()
}
43 changes: 43 additions & 0 deletions consul/resource_consul_certificate_authority_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package consul

import (
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
Expand All @@ -25,6 +26,13 @@ func TestAccConsulCertificateAuthority(t *testing.T) {
resource.TestCheckResourceAttr("consul_certificate_authority.test", "config.IntermediateCertTTL", "5678h"),
),
},
{
Config: testAccConsulCertificateAuthorityConfigBoth,
ExpectError: regexp.MustCompile(`"config": conflicts with config_json`),
},
{
Config: testAccConsulCertificateAuthorityConfigJSON,
},
{
Config: testAccConsulCertificateAuthorityConfig,
ResourceName: "consul_certificate_authority.test",
Expand All @@ -46,3 +54,38 @@ resource "consul_certificate_authority" "test" {
}
}
`

const testAccConsulCertificateAuthorityConfigBoth = `
resource "consul_certificate_authority" "test" {
connect_provider = "consul"
config = {
LeafCertTTL = "72h"
RotationPeriod = "1234h"
IntermediateCertTTL = "5678h"
}
config_json = jsonencode({})
}
`

const testAccConsulCertificateAuthorityConfigJSON = `
resource "consul_certificate_authority" "test" {
connect_provider = "consul"
config_json = jsonencode({
address = "http://localhost:8200"
auth_method = {
type = "approle"
mount_path = "approle"
params = {
role_id = "role_id"
secret_id = "secret_id"
}
}
namespace = "namespace"
root_pki_path = "root_pki_path"
intermediate_pki_path = "intermediate_pki_path"
})
}
`
78 changes: 19 additions & 59 deletions docs/resources/certificate_authority.md
Original file line number Diff line number Diff line change
@@ -1,80 +1,40 @@
---
layout: "consul"
page_title: "Consul: consul_certificate_authority"
sidebar_current: "docs-consul-resource-certificate-authority"
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "consul_certificate_authority Resource - terraform-provider-consul"
subcategory: ""
description: |-
A resource that manage the Consul Connect Certificate Authority
The consul_certificate_authority resource can be used to manage the configuration of the Certificate Authority used by Consul Connect https://www.consul.io/docs/connect/ca.
-> Note: The keys in the config argument must be using Camel case.
---

# certificate_authority
# consul_certificate_authority (Resource)

The `consul_certificate_authority` resource can be used to manage the configuration of
the Certificate Authority used by [Consul Connect](https://www.consul.io/docs/connect/ca).
The `consul_certificate_authority` resource can be used to manage the configuration of the Certificate Authority used by [Consul Connect](https://www.consul.io/docs/connect/ca).

-> **Note:** The keys in the `config` argument must be using Camel case.

## Example Usage

### Using the built-in CA with specific TTL

```hcl
resource "consul_certificate_authority" "connect" {
connect_provider = "consul"
<!-- schema generated by tfplugindocs -->
## Schema

config = {
LeafCertTTL = "24h"
RotationPeriod = "2160h"
IntermediateCertTTL = "8760h"
}
}
```

### Using Vault to manage and sign certificates

```hcl
resource "consul_certificate_authority" "connect" {
connect_provider = "vault"
config = {
Address = "http://localhost:8200"
Token = "..."
RootPKIPath = "connect-root"
IntermediatePKIPath = "connect-intermediate"
}
}
```

### Using the [AWS Certificate Manager Private Certificate Authority](https://aws.amazon.com/certificate-manager/private-certificate-authority/)
### Required

```hcl
resource "consul_certificate_authority" "connect" {
connect_provider = "aws-pca"
- `connect_provider` (String) Specifies the CA provider type to use.

config = {
ExistingARN = "arn:aws:acm-pca:region:account:certificate-authority/12345678-1234-1234-123456789012"
}
}
```

## Argument Reference

The following arguments are supported:
### Optional

* `connect_provider` - (Required, string) Specifies the CA provider type to use.
* `config` - (Required, map) The raw configuration to use for the chosen provider.
- `config` (Map of String, Deprecated) The raw configuration to use for the chosen provider. For more information on configuring the Connect CA providers, see [Provider Config](https://developer.hashicorp.com/consul/docs/connect/ca).
- `config_json` (String) The raw configuration to use for the chosen provider. For more information on configuring the Connect CA providers, see [Provider Config](https://developer.hashicorp.com/consul/docs/connect/ca).

### Read-Only

## Attributes Reference

The following attributes are exported:

* `connect_provider` - Specifies the CA provider type to use.
* `config` - The raw configuration to use for the chosen provider.
- `id` (String) The ID of this resource.

## Import

`certificate_authority` can be imported:
Import is supported using the following syntax:

```
$ terraform import certificate_authority.connect connect-ca
```shell
terraform import certificate_authority.connect connect-ca
```
1 change: 1 addition & 0 deletions examples/resources/consul_certificate_authority/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import certificate_authority.connect connect-ca
34 changes: 34 additions & 0 deletions examples/resources/consul_certificate_authority/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Using the built-in CA with specific TTL
resource "consul_certificate_authority" "connect" {
connect_provider = "consul"

config_json = jsondecode({
LeafCertTTL = "24h"
RotationPeriod = "2160h"
IntermediateCertTTL = "8760h"
})
}


# Using Vault to manage and sign certificates
resource "consul_certificate_authority" "connect" {
connect_provider = "vault"

config_json = jsonencode({
Address = "http://localhost:8200"
Token = "..."
RootPKIPath = "connect-root"
IntermediatePKIPath = "connect-intermediate"
})
}


# Using the AWS Certificate Manager Private Certificate Authority
# * https://aws.amazon.com/certificate-manager/private-certificate-authority/
resource "consul_certificate_authority" "connect" {
connect_provider = "aws-pca"

config_json = jsonencode({
ExistingARN = "arn:aws:acm-pca:region:account:certificate-authority/12345678-1234-1234-123456789012"
})
}
14 changes: 7 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module github.com/hashicorp/terraform-provider-consul

require (
github.com/hashicorp/consul/api v1.22.0
github.com/hashicorp/consul/api v1.23.0
github.com/hashicorp/errwrap v1.1.0
github.com/hashicorp/terraform-plugin-sdk v1.17.2
github.com/mitchellh/mapstructure v1.5.0
Expand All @@ -12,7 +12,7 @@ require (
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v0.12.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
)

require (
Expand All @@ -31,7 +31,7 @@ require (
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fatih/color v1.14.1 // indirect
github.com/frankban/quicktest v1.14.4 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
Expand Down Expand Up @@ -69,7 +69,7 @@ require (
github.com/klauspost/compress v1.15.11 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mitchellh/cli v1.1.2 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
Expand All @@ -87,11 +87,11 @@ require (
github.com/zclconf/go-cty v1.8.2 // indirect
github.com/zclconf/go-cty-yaml v1.0.2 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.114.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
Expand Down
Loading

0 comments on commit 5f1ede6

Please sign in to comment.