Restore tls_cert_request to being a managed resource

In c244e5a6 this resource was converted to a data source, but that was
a mistake since data sources are expected to produce stable results on
each run, and yet certificate requests contain a random nonce as part of
the signature.

Additionally, using the data source as a managed resource through the
provided compatibility shim was not actually working, since "Read" was
trying to parse the private key out of a SHA1 hash of the key, which is
what we place in state due to the StateFunc on that attribute.

By restoring this we restore Terraform's ability to produce all of the
parts of a basic PKI/CA, which is useful for creating dev environments
and bootstrapping PKI for production environments.
This commit is contained in:
Martin Atkins 2016-09-24 12:22:07 -07:00
parent 7d2b51e6c5
commit 804d714ff6
5 changed files with 37 additions and 24 deletions

View File

@ -12,18 +12,11 @@ import (
func Provider() terraform.ResourceProvider {
return &schema.Provider{
DataSourcesMap: map[string]*schema.Resource{
"tls_cert_request": dataSourceCertRequest(),
},
ResourcesMap: map[string]*schema.Resource{
"tls_private_key": resourcePrivateKey(),
"tls_locally_signed_cert": resourceLocallySignedCert(),
"tls_self_signed_cert": resourceSelfSignedCert(),
"tls_cert_request": schema.DataSourceResourceShim(
"tls_cert_request",
dataSourceCertRequest(),
),
"tls_cert_request": resourceCertRequest(),
},
}
}

View File

@ -12,8 +12,10 @@ import (
const pemCertReqType = "CERTIFICATE REQUEST"
func dataSourceCertRequest() *schema.Resource {
func resourceCertRequest() *schema.Resource {
return &schema.Resource{
Create: CreateCertRequest,
Delete: DeleteCertRequest,
Read: ReadCertRequest,
Schema: map[string]*schema.Schema{
@ -22,6 +24,7 @@ func dataSourceCertRequest() *schema.Resource {
Type: schema.TypeList,
Optional: true,
Description: "List of DNS names to use as subjects of the certificate",
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
@ -31,6 +34,7 @@ func dataSourceCertRequest() *schema.Resource {
Type: schema.TypeList,
Optional: true,
Description: "List of IP addresses to use as subjects of the certificate",
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
@ -40,12 +44,14 @@ func dataSourceCertRequest() *schema.Resource {
Type: schema.TypeString,
Required: true,
Description: "Name of the algorithm to use to generate the certificate's private key",
ForceNew: true,
},
"private_key_pem": &schema.Schema{
Type: schema.TypeString,
Required: true,
Description: "PEM-encoded private key that the certificate will belong to",
ForceNew: true,
StateFunc: func(v interface{}) string {
return hashForState(v.(string))
},
@ -55,6 +61,7 @@ func dataSourceCertRequest() *schema.Resource {
Type: schema.TypeList,
Required: true,
Elem: nameSchema,
ForceNew: true,
},
"cert_request_pem": &schema.Schema{
@ -65,7 +72,7 @@ func dataSourceCertRequest() *schema.Resource {
}
}
func ReadCertRequest(d *schema.ResourceData, meta interface{}) error {
func CreateCertRequest(d *schema.ResourceData, meta interface{}) error {
key, err := parsePrivateKey(d, "private_key_pem", "key_algorithm")
if err != nil {
return err
@ -109,3 +116,12 @@ func ReadCertRequest(d *schema.ResourceData, meta interface{}) error {
return nil
}
func DeleteCertRequest(d *schema.ResourceData, meta interface{}) error {
d.SetId("")
return nil
}
func ReadCertRequest(d *schema.ResourceData, meta interface{}) error {
return nil
}

View File

@ -12,12 +12,12 @@ import (
)
func TestCertRequest(t *testing.T) {
r.UnitTest(t, r.TestCase{
r.Test(t, r.TestCase{
Providers: testProviders,
Steps: []r.TestStep{
r.TestStep{
Config: fmt.Sprintf(`
data "tls_cert_request" "test" {
resource "tls_cert_request" "test" {
subject {
common_name = "example.com"
organization = "Example, Inc"
@ -46,7 +46,7 @@ func TestCertRequest(t *testing.T) {
EOT
}
output "key_pem" {
value = "${data.tls_cert_request.test.cert_request_pem}"
value = "${tls_cert_request.test.cert_request_pem}"
}
`, testPrivateKey),
Check: func(s *terraform.State) error {

View File

@ -13,11 +13,21 @@ typical format used to request a certificate from a certificate authority.
This resource is intended to be used in conjunction with a Terraform provider
for a particular certificate authority in order to provision a new certificate.
This is a *logical resource*, so it contributes only to the current Terraform
state and does not create any external managed resources.
~> **Compatibility Note** From Terraform 0.7.0 to 0.7.4 this resource was
converted to a data source, and the resource form of it was deprecated. This
turned out to be a design error since a cert request includes a random number
in the form of the signature nonce, and so the data source form of this
resource caused non-convergent configuration. The data source form is no longer
supported as of Terraform 0.7.5 and any users should return to using the
resource form.
## Example Usage
```
data "tls_cert_request" "example" {
resource "tls_cert_request" "example" {
key_algorithm = "ECDSA"
private_key_pem = "${file(\"private_key.pem\")}"

View File

@ -10,15 +10,6 @@
<a href="/docs/providers/tls/index.html">TLS Provider</a>
</li>
<li<%= sidebar_current(/^docs-tls-data-source/) %>>
<a href="#">Data Sources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-tls-data-source-cert-request") %>>
<a href="/docs/providers/tls/d/cert_request.html">tls_cert_request</a>
</li>
</ul>
</li>
<li<%= sidebar_current(/^docs-tls-resource/) %>>
<a href="#">Resources</a>
<ul class="nav nav-visible">
@ -31,6 +22,9 @@
<li<%= sidebar_current("docs-tls-resource-locally-signed-cert") %>>
<a href="/docs/providers/tls/r/locally_signed_cert.html">tls_locally_signed_cert</a>
</li>
<li<%= sidebar_current("docs-tls-resourse-cert-request") %>>
<a href="/docs/providers/tls/r/cert_request.html">tls_cert_request</a>
</li>
</ul>
</li>
</ul>