mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-07-05 05:24:01 +00:00
Add certificate resource
This commit is contained in:
parent
8396d92ddf
commit
dffff063ab
@ -3,6 +3,7 @@
|
||||
FEATURES:
|
||||
|
||||
* **New Data Source:** `proxmox_virtual_environment_dns`
|
||||
* **New Resource:** `proxmox_virtual_environment_certificate`
|
||||
* **New Resource:** `proxmox_virtual_environment_dns`
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
11
README.md
11
README.md
@ -251,6 +251,17 @@ This data source doesn't accept arguments.
|
||||
|
||||
#### Virtual Environment
|
||||
|
||||
##### Certificate (proxmox_virtual_environment_certificate)
|
||||
|
||||
###### Arguments
|
||||
* `certificate` - (Required) The PEM encoded certificate
|
||||
* `certificate_chain` - (Optional) The PEM encoded certificate chain
|
||||
* `node_name` - (Required) A node name
|
||||
* `private_key` - (Required) The PEM encoded private key
|
||||
|
||||
###### Attributes
|
||||
This resource doesn't expose any additional attributes.
|
||||
|
||||
##### DNS (proxmox_virtual_environment_dns)
|
||||
|
||||
###### Arguments
|
||||
|
28
example/resource_virtual_environment_certificate.tf
Normal file
28
example/resource_virtual_environment_certificate.tf
Normal file
@ -0,0 +1,28 @@
|
||||
resource "proxmox_virtual_environment_certificate" "example" {
|
||||
certificate = "${tls_self_signed_cert.proxmox_virtual_environment_certificate.cert_pem}"
|
||||
node_name = "${data.proxmox_virtual_environment_nodes.example.names[0]}"
|
||||
private_key = "${tls_private_key.proxmox_virtual_environment_certificate.private_key_pem}"
|
||||
}
|
||||
|
||||
resource "tls_private_key" "proxmox_virtual_environment_certificate" {
|
||||
algorithm = "RSA"
|
||||
rsa_bits = 2048
|
||||
}
|
||||
|
||||
resource "tls_self_signed_cert" "proxmox_virtual_environment_certificate" {
|
||||
key_algorithm = "${tls_private_key.proxmox_virtual_environment_certificate.algorithm}"
|
||||
private_key_pem = "${tls_private_key.proxmox_virtual_environment_certificate.private_key_pem}"
|
||||
|
||||
subject {
|
||||
common_name = "example.com"
|
||||
organization = "Terraform Provider for Proxmox"
|
||||
}
|
||||
|
||||
validity_period_hours = 8760
|
||||
|
||||
allowed_uses = [
|
||||
"key_encipherment",
|
||||
"digital_signature",
|
||||
"server_auth",
|
||||
]
|
||||
}
|
37
proxmox/virtual_environment_certificate.go
Normal file
37
proxmox/virtual_environment_certificate.go
Normal file
@ -0,0 +1,37 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package proxmox
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// DeleteCertificate deletes the custom certificate for a node.
|
||||
func (c *VirtualEnvironmentClient) DeleteCertificate(nodeName string, d *VirtualEnvironmentCertificateDeleteRequestBody) error {
|
||||
return c.DoRequest(hmDELETE, fmt.Sprintf("nodes/%s/certificates/custom", url.PathEscape(nodeName)), d, nil)
|
||||
}
|
||||
|
||||
// ListCertificates retrieves the list of certificates for a node.
|
||||
func (c *VirtualEnvironmentClient) ListCertificates(nodeName string) (*[]VirtualEnvironmentCertificateListResponseData, error) {
|
||||
resBody := &VirtualEnvironmentCertificateListResponseBody{}
|
||||
err := c.DoRequest(hmGET, fmt.Sprintf("nodes/%s/certificates/info", url.PathEscape(nodeName)), nil, resBody)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resBody.Data == nil {
|
||||
return nil, errors.New("The server did not include a data object in the response")
|
||||
}
|
||||
|
||||
return resBody.Data, nil
|
||||
}
|
||||
|
||||
// UpdateCertificate updates the custom certificate for a node.
|
||||
func (c *VirtualEnvironmentClient) UpdateCertificate(nodeName string, d *VirtualEnvironmentCertificateUpdateRequestBody) error {
|
||||
return c.DoRequest(hmPOST, fmt.Sprintf("nodes/%s/certificates/custom", url.PathEscape(nodeName)), d, nil)
|
||||
}
|
37
proxmox/virtual_environment_certificate_types.go
Normal file
37
proxmox/virtual_environment_certificate_types.go
Normal file
@ -0,0 +1,37 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package proxmox
|
||||
|
||||
// VirtualEnvironmentCertificateDeleteRequestBody contains the data for a custom certificate delete request.
|
||||
type VirtualEnvironmentCertificateDeleteRequestBody struct {
|
||||
Restart *CustomBool `json:"restart,omitempty" url:"restart,omitempty,int"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentCertificateListResponseBody contains the body from a certificate list response.
|
||||
type VirtualEnvironmentCertificateListResponseBody struct {
|
||||
Data *[]VirtualEnvironmentCertificateListResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentCertificateListResponseData contains the data from a certificate list response.
|
||||
type VirtualEnvironmentCertificateListResponseData struct {
|
||||
Certificates *string `json:"pem,omitempty"`
|
||||
FileName *string `json:"filename,omitempty"`
|
||||
Fingerprint *string `json:"fingerprint,omitempty"`
|
||||
Issuer *string `json:"issuer,omitempty"`
|
||||
NotAfter *CustomTimestamp `json:"notafter,omitempty"`
|
||||
NotBefore *CustomTimestamp `json:"notbefore,omitempty"`
|
||||
PublicKeyBits *int `json:"public-key-bits,omitempty"`
|
||||
PublicKeyType *string `json:"public-key-type,omitempty"`
|
||||
Subject *string `json:"subject,omitempty"`
|
||||
SubjectAlternativeNames *[]string `json:"san,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentCertificateUpdateRequestBody contains the body for a custom certificate update request.
|
||||
type VirtualEnvironmentCertificateUpdateRequestBody struct {
|
||||
Certificates string `json:"certificates" url:"certificates"`
|
||||
Force *CustomBool `json:"force,omitempty" url:"force,omitempty,int"`
|
||||
PrivateKey *string `json:"key,omitempty" url:"key,omitempty"`
|
||||
Restart *CustomBool `json:"restart,omitempty" url:"restart,omitempty,int"`
|
||||
}
|
@ -4,12 +4,12 @@
|
||||
|
||||
package proxmox
|
||||
|
||||
// VirtualEnvironmentDNSGetResponseBody contains the body from an pool get response.
|
||||
// VirtualEnvironmentDNSGetResponseBody contains the body from a DNS get response.
|
||||
type VirtualEnvironmentDNSGetResponseBody struct {
|
||||
Data *VirtualEnvironmentDNSGetResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentDNSGetResponseData contains the data from an pool get response.
|
||||
// VirtualEnvironmentDNSGetResponseData contains the data from a DNS get response.
|
||||
type VirtualEnvironmentDNSGetResponseData struct {
|
||||
Server1 *string `json:"dns1,omitempty" url:"dns1,omitempty"`
|
||||
Server2 *string `json:"dns2,omitempty" url:"dns2,omitempty"`
|
||||
@ -17,7 +17,7 @@ type VirtualEnvironmentDNSGetResponseData struct {
|
||||
SearchDomain *string `json:"search,omitempty" url:"search,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentDNSUpdateRequestBody contains the data for an pool create request.
|
||||
// VirtualEnvironmentDNSUpdateRequestBody contains the body for a DNS update request.
|
||||
type VirtualEnvironmentDNSUpdateRequestBody struct {
|
||||
Server1 *string `json:"dns1,omitempty" url:"dns1,omitempty"`
|
||||
Server2 *string `json:"dns2,omitempty" url:"dns2,omitempty"`
|
||||
|
@ -44,6 +44,7 @@ func Provider() *schema.Provider {
|
||||
"proxmox_virtual_environment_version": dataSourceVirtualEnvironmentVersion(),
|
||||
},
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"proxmox_virtual_environment_certificate": resourceVirtualEnvironmentCertificate(),
|
||||
"proxmox_virtual_environment_dns": resourceVirtualEnvironmentDNS(),
|
||||
"proxmox_virtual_environment_file": resourceVirtualEnvironmentFile(),
|
||||
"proxmox_virtual_environment_group": resourceVirtualEnvironmentGroup(),
|
||||
|
203
proxmoxtf/resource_virtual_environment_certificate.go
Normal file
203
proxmoxtf/resource_virtual_environment_certificate.go
Normal file
@ -0,0 +1,203 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package proxmoxtf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/danitso/terraform-provider-proxmox/proxmox"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
dvResourceVirtualEnvironmentCertificateCertificateChain = ""
|
||||
dvResourceVirtualEnvironmentCertificateOverwrite = false
|
||||
|
||||
mkResourceVirtualEnvironmentCertificateCertificate = "certificate"
|
||||
mkResourceVirtualEnvironmentCertificateCertificateChain = "certificate_chain"
|
||||
mkResourceVirtualEnvironmentCertificateNodeName = "node_name"
|
||||
mkResourceVirtualEnvironmentCertificateOverwrite = "overwrite"
|
||||
mkResourceVirtualEnvironmentCertificatePrivateKey = "private_key"
|
||||
)
|
||||
|
||||
func resourceVirtualEnvironmentCertificate() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
mkResourceVirtualEnvironmentCertificateCertificate: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Description: "The PEM encoded certificate",
|
||||
Required: true,
|
||||
},
|
||||
mkResourceVirtualEnvironmentCertificateCertificateChain: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Description: "The PEM encoded certificate chain",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentCertificateCertificateChain,
|
||||
},
|
||||
mkResourceVirtualEnvironmentCertificateNodeName: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Description: "The node name",
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
mkResourceVirtualEnvironmentCertificateOverwrite: &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Description: "Whether to overwrite an existing certificate",
|
||||
Optional: true,
|
||||
Default: dvResourceVirtualEnvironmentCertificateOverwrite,
|
||||
},
|
||||
mkResourceVirtualEnvironmentCertificatePrivateKey: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Description: "The PEM encoded private key",
|
||||
Required: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
},
|
||||
Create: resourceVirtualEnvironmentCertificateCreate,
|
||||
Read: resourceVirtualEnvironmentCertificateRead,
|
||||
Update: resourceVirtualEnvironmentCertificateUpdate,
|
||||
Delete: resourceVirtualEnvironmentCertificateDelete,
|
||||
}
|
||||
}
|
||||
|
||||
func resourceVirtualEnvironmentCertificateCreate(d *schema.ResourceData, m interface{}) error {
|
||||
err := resourceVirtualEnvironmentCertificateUpdate(d, m)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeName := d.Get(mkResourceVirtualEnvironmentCertificateNodeName).(string)
|
||||
|
||||
d.SetId(fmt.Sprintf("%s_certificate", nodeName))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceVirtualEnvironmentCertificateGetUpdateBody(d *schema.ResourceData, m interface{}) (*proxmox.VirtualEnvironmentCertificateUpdateRequestBody, error) {
|
||||
certificate := d.Get(mkResourceVirtualEnvironmentCertificateCertificate).(string)
|
||||
certificateChain := d.Get(mkResourceVirtualEnvironmentCertificateCertificateChain).(string)
|
||||
overwrite := proxmox.CustomBool(d.Get(mkResourceVirtualEnvironmentCertificateOverwrite).(bool))
|
||||
privateKey := d.Get(mkResourceVirtualEnvironmentCertificatePrivateKey).(string)
|
||||
|
||||
combinedCertificates := strings.TrimSpace(certificate) + "\n"
|
||||
|
||||
if certificateChain != "" {
|
||||
combinedCertificates += strings.TrimSpace(certificateChain) + "\n"
|
||||
}
|
||||
|
||||
force := overwrite
|
||||
|
||||
if d.Id() != "" {
|
||||
force = proxmox.CustomBool(true)
|
||||
}
|
||||
|
||||
restart := proxmox.CustomBool(true)
|
||||
|
||||
body := &proxmox.VirtualEnvironmentCertificateUpdateRequestBody{
|
||||
Certificates: combinedCertificates,
|
||||
Force: &force,
|
||||
PrivateKey: &privateKey,
|
||||
Restart: &restart,
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func resourceVirtualEnvironmentCertificateRead(d *schema.ResourceData, m interface{}) error {
|
||||
config := m.(providerConfiguration)
|
||||
veClient, err := config.GetVEClient()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeName := d.Get(mkResourceVirtualEnvironmentCertificateNodeName).(string)
|
||||
list, err := veClient.ListCertificates(nodeName)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set(mkResourceVirtualEnvironmentCertificateCertificate, "")
|
||||
d.Set(mkResourceVirtualEnvironmentCertificateCertificateChain, "")
|
||||
|
||||
certificateChain := d.Get(mkResourceVirtualEnvironmentCertificateCertificateChain).(string)
|
||||
|
||||
for _, c := range *list {
|
||||
if c.FileName != nil && *c.FileName == "pveproxy-ssl.pem" {
|
||||
if c.Certificates != nil {
|
||||
newCertificate := ""
|
||||
newCertificateChain := ""
|
||||
|
||||
if certificateChain != "" {
|
||||
certificates := strings.Split(strings.TrimSpace(*c.Certificates), "\n")
|
||||
newCertificate = certificates[0] + "\n"
|
||||
|
||||
if len(certificates) > 1 {
|
||||
newCertificateChain = strings.Join(certificates[1:], "\n") + "\n"
|
||||
}
|
||||
} else {
|
||||
newCertificate = *c.Certificates
|
||||
}
|
||||
|
||||
d.Set(mkResourceVirtualEnvironmentCertificateCertificate, newCertificate)
|
||||
d.Set(mkResourceVirtualEnvironmentCertificateCertificateChain, newCertificateChain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceVirtualEnvironmentCertificateUpdate(d *schema.ResourceData, m interface{}) error {
|
||||
config := m.(providerConfiguration)
|
||||
veClient, err := config.GetVEClient()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeName := d.Get(mkResourceVirtualEnvironmentCertificateNodeName).(string)
|
||||
|
||||
body, err := resourceVirtualEnvironmentCertificateGetUpdateBody(d, m)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = veClient.UpdateCertificate(nodeName, body)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return resourceVirtualEnvironmentCertificateRead(d, m)
|
||||
}
|
||||
|
||||
func resourceVirtualEnvironmentCertificateDelete(d *schema.ResourceData, m interface{}) error {
|
||||
config := m.(providerConfiguration)
|
||||
veClient, err := config.GetVEClient()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeName := d.Get(mkResourceVirtualEnvironmentCertificateNodeName).(string)
|
||||
restart := proxmox.CustomBool(true)
|
||||
|
||||
err = veClient.DeleteCertificate(nodeName, &proxmox.VirtualEnvironmentCertificateDeleteRequestBody{
|
||||
Restart: &restart,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
47
proxmoxtf/resource_virtual_environment_certificate_test.go
Normal file
47
proxmoxtf/resource_virtual_environment_certificate_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package proxmoxtf
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// TestResourceVirtualEnvironmentCertificateInstantiation tests whether the ResourceVirtualEnvironmentCertificate instance can be instantiated.
|
||||
func TestResourceVirtualEnvironmentCertificateInstantiation(t *testing.T) {
|
||||
s := resourceVirtualEnvironmentCertificate()
|
||||
|
||||
if s == nil {
|
||||
t.Fatalf("Cannot instantiate resourceVirtualEnvironmentCertificate")
|
||||
}
|
||||
}
|
||||
|
||||
// TestResourceVirtualEnvironmentCertificateSchema tests the resourceVirtualEnvironmentCertificate schema.
|
||||
func TestResourceVirtualEnvironmentCertificateSchema(t *testing.T) {
|
||||
s := resourceVirtualEnvironmentCertificate()
|
||||
|
||||
testRequiredArguments(t, s, []string{
|
||||
mkResourceVirtualEnvironmentCertificateCertificate,
|
||||
mkResourceVirtualEnvironmentCertificateNodeName,
|
||||
mkResourceVirtualEnvironmentCertificatePrivateKey,
|
||||
})
|
||||
|
||||
testOptionalArguments(t, s, []string{
|
||||
mkResourceVirtualEnvironmentCertificateCertificateChain,
|
||||
})
|
||||
|
||||
testSchemaValueTypes(t, s, []string{
|
||||
mkResourceVirtualEnvironmentCertificateCertificate,
|
||||
mkResourceVirtualEnvironmentCertificateCertificateChain,
|
||||
mkResourceVirtualEnvironmentCertificateNodeName,
|
||||
mkResourceVirtualEnvironmentCertificatePrivateKey,
|
||||
}, []schema.ValueType{
|
||||
schema.TypeString,
|
||||
schema.TypeString,
|
||||
schema.TypeString,
|
||||
schema.TypeString,
|
||||
})
|
||||
}
|
@ -349,6 +349,7 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
Description: "The SSH password",
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Sensitive: true,
|
||||
Default: dvResourceVirtualEnvironmentVMCloudInitUserAccountPassword,
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
return strings.ReplaceAll(old, "*", "") == ""
|
||||
|
Loading…
Reference in New Issue
Block a user