Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add fqdn parameter for r/csr #196

Merged
merged 1 commit into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/resources/csr.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ external or internal CA.
- `country` (String) ISO 3166 country code where company is legally registered
- `domain_id` (String) Domain Id or Name for which the CSRs should be generated
- `email` (String) Contact email address
- `fqdn` (String) FQDN of the resource
- `key_size` (Number) Certificate public key size. One among: 2048, 3072, 4096
- `locality` (String) The city or locality where company is legally registered
- `organization` (String) The name under which your company is known. The listed organization must be the legal registrant of the domain name in the certificate request.
- `organization_unit` (String) Organization with which the certificate is associated
- `resource` (String) Resources for which the CSRs are to be generated. One among: SDDC_MANAGER, VCENTER, NSX_MANAGER, NSXT_MANAGER, VROPS, VRSLCM, VXRAIL_MANAGER
- `resource` (String) Resources for which the CSRs are to be generated. One among: SDDC_MANAGER, PSC, VCENTER, NSX_MANAGER, NSXT_MANAGER, VROPS, VRSLCM, VXRAIL_MANAGER
- `state` (String) Full name (do not abbreviate) of the state, province, region, or territory where your company is legally registered.

### Optional
Expand Down
45 changes: 4 additions & 41 deletions internal/certificates/certificate_operations.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,20 @@
// Copyright 2023 Broadcom. All Rights Reserved.
// Copyright 2023-2024 Broadcom. All Rights Reserved.
// SPDX-License-Identifier: MPL-2.0

package certificates

import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/vmware/terraform-provider-vcf/internal/api_client"
"github.com/vmware/terraform-provider-vcf/internal/constants"
validationutils "github.com/vmware/terraform-provider-vcf/internal/validation"
"github.com/vmware/vcf-sdk-go/client"
vcfclient "github.com/vmware/vcf-sdk-go/client"
"github.com/vmware/vcf-sdk-go/client/certificates"
"github.com/vmware/vcf-sdk-go/client/domains"
"github.com/vmware/vcf-sdk-go/models"
"strings"
"time"
)

func GetFqdnOfResourceTypeInDomain(ctx context.Context, domainId, resourceType string, apiClient *client.VcfClient) (*string, error) {
if apiClient == nil || len(resourceType) < 1 || len(domainId) < 1 {
return nil, nil
}

endpointsParams := domains.NewGetDomainEndpointsParamsWithContext(ctx).
WithTimeout(constants.DefaultVcfApiCallTimeout).WithID(domainId)

endpointsResult, err := apiClient.Domains.GetDomainEndpoints(endpointsParams)
if err != nil {
return nil, err
}

for _, endpoint := range endpointsResult.Payload.Elements {
if resourceType == *endpoint.Type {
result := *endpoint.URL
if strings.Contains(result, "https://") {
result = strings.ReplaceAll(result, "https://", "")
}
return &result, nil
}
}
return nil, nil
}

func ValidateResourceCertificates(ctx context.Context, client *vcfclient.VcfClient,
domainId string, resourceCertificateSpecs []*models.ResourceCertificateSpec) diag.Diagnostics {
validateResourceCertificatesParams := certificates.NewValidateResourceCertificatesParams().
Expand All @@ -66,7 +37,7 @@ func ValidateResourceCertificates(ctx context.Context, client *vcfclient.VcfClie
return validationutils.ConvertCertificateValidationsResultToDiag(validationResponse)
}
validationId := validationResponse.ValidationID
// Wait for certificate validation to fisnish
// Wait for certificate validation to finish
if !validationutils.HasCertificateValidationFinished(validationResponse) {
for {
getResourceCertificatesValidationResultParams := certificates.NewGetResourceCertificatesValidationByIDParams().
Expand Down Expand Up @@ -95,15 +66,7 @@ func ValidateResourceCertificates(ctx context.Context, client *vcfclient.VcfClie
}

func GetCertificateForResourceInDomain(ctx context.Context, client *vcfclient.VcfClient,
domainId, resourceType string) (*models.Certificate, error) {
resourceFqdn, err := GetFqdnOfResourceTypeInDomain(ctx, domainId, resourceType, client)
if err != nil {
return nil, err
}
if resourceFqdn == nil {
return nil, fmt.Errorf("could not determine FQDN for resourceType %s in domain %s", resourceType, domainId)
}

domainId, resourceFqdn string) (*models.Certificate, error) {
viewCertificatesParams := certificates.NewGetCertificatesByDomainParamsWithContext(ctx).
WithTimeout(constants.DefaultVcfApiCallTimeout)
viewCertificatesParams.ID = domainId
Expand All @@ -115,7 +78,7 @@ func GetCertificateForResourceInDomain(ctx context.Context, client *vcfclient.Vc

allCertsForDomain := certificatesResponse.Payload.Elements
for _, cert := range allCertsForDomain {
if cert.IssuedTo != nil && *cert.IssuedTo == *resourceFqdn {
if cert.IssuedTo != nil && *cert.IssuedTo == resourceFqdn {
return cert, nil
}
}
Expand Down
9 changes: 9 additions & 0 deletions internal/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ const (

// VcfTestComputeClusterName the display name of the compute cluster that will contain the edge nodes.
VcfTestComputeClusterName = "VCF_TEST_COMPUTE_CLUSTER_NAME"

// VcfTestVcenterFqdn the FQDN of the vcenter server.
VcfTestVcenterFqdn = "VCF_TEST_VCENTER_FQDN"

// VcfTestSddcManagerFqdn the FQDN of the SDDC manager.
VcfTestSddcManagerFqdn = "VCF_TEST_SDDC_MANAGER_FQDN"

// VcfTestNsxManagerFqdn the FQDN of the NSX manager.
VcfTestNsxManagerFqdn = "VCF_TEST_NSX_MANAGER_FQDN"
)

func GetIso3166CountryCodes() []string {
Expand Down
23 changes: 8 additions & 15 deletions internal/provider/resource_certificate.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 Broadcom. All Rights Reserved.
// Copyright 2023-2024 Broadcom. All Rights Reserved.
// SPDX-License-Identifier: MPL-2.0

package provider
Expand Down Expand Up @@ -60,31 +60,24 @@ func resourceResourceCertificateCreate(ctx context.Context, data *schema.Resourc

csrID := data.Get("csr_id").(string)
csrIdComponents := strings.Split(csrID, ":")
if len(csrIdComponents) != 4 {
if len(csrIdComponents) != 5 {
return diag.FromErr(fmt.Errorf("CSR ID invalid"))
}

domainID := csrIdComponents[1]
resourceType := csrIdComponents[2]
resourceFqdn := csrIdComponents[3]
caType := data.Get("ca_id").(string)

resourceFqdn, err := certificates.GetFqdnOfResourceTypeInDomain(ctx, domainID, resourceType, apiClient)
if err != nil {
return diag.FromErr(err)
}
if resourceFqdn == nil {
return diag.FromErr(fmt.Errorf("could not determine FQDN for resourceType %s in domain %s", resourceType, domainID))
}

err = certificates.GenerateCertificateForResource(ctx, vcfClient, &domainID, &resourceType, resourceFqdn, &caType)
err := certificates.GenerateCertificateForResource(ctx, vcfClient, &domainID, &resourceType, &resourceFqdn, &caType)
if err != nil {
return diag.FromErr(err)
}

certificateOperationSpec := &models.CertificateOperationSpec{
OperationType: resource_utils.ToStringPointer("INSTALL"),
Resources: []*models.Resource{{
Fqdn: *resourceFqdn,
Fqdn: resourceFqdn,
Type: &resourceType,
}},
}
Expand Down Expand Up @@ -119,14 +112,14 @@ func resourceResourceCertificateRead(ctx context.Context, data *schema.ResourceD

csrID := data.Get("csr_id").(string)
csrIdComponents := strings.Split(csrID, ":")
if len(csrIdComponents) != 4 {
if len(csrIdComponents) != 5 {
return diag.FromErr(fmt.Errorf("CSR ID invalid"))
}

domainID := csrIdComponents[1]
resourceType := csrIdComponents[2]
resourceFqdn := csrIdComponents[3]

cert, err := certificates.GetCertificateForResourceInDomain(ctx, apiClient, domainID, resourceType)
cert, err := certificates.GetCertificateForResourceInDomain(ctx, apiClient, domainID, resourceFqdn)
if err != nil {
return diag.FromErr(err)
}
Expand Down
97 changes: 91 additions & 6 deletions internal/provider/resource_certificate_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 Broadcom. All Rights Reserved.
// Copyright 2023-2024 Broadcom. All Rights Reserved.
// SPDX-License-Identifier: MPL-2.0

package provider
Expand All @@ -11,8 +11,8 @@ import (
"testing"
)

func TestAccResourceVcfResourceCertificate(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
func TestAccResourceVcfResourceCertificate_vCenter(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccVcfCertificateAuthorityPreCheck(t)
Expand All @@ -24,7 +24,9 @@ func TestAccResourceVcfResourceCertificate(t *testing.T) {
os.Getenv(constants.VcfTestDomainDataSourceId),
os.Getenv(constants.VcfTestMsftCaServerUrl),
os.Getenv(constants.VcfTestMsftCaUser),
os.Getenv(constants.VcfTestMsftCaSecret)),
os.Getenv(constants.VcfTestMsftCaSecret),
"VCENTER",
os.Getenv(constants.VcfTestVcenterFqdn)),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.issued_by"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.issued_to"),
Expand All @@ -49,7 +51,87 @@ func TestAccResourceVcfResourceCertificate(t *testing.T) {
})
}

func testAccVcfResourceCertificate(domainID, msftCaServerUrl, msftCaUser, msftCaSecret string) string {
func TestAccResourceVcfResourceCertificate_sddcManager(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccVcfCertificateAuthorityPreCheck(t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccVcfResourceCertificate(
os.Getenv(constants.VcfTestDomainDataSourceId),
os.Getenv(constants.VcfTestMsftCaServerUrl),
os.Getenv(constants.VcfTestMsftCaUser),
os.Getenv(constants.VcfTestMsftCaSecret),
"SDDC_MANAGER",
os.Getenv(constants.VcfTestSddcManagerFqdn)),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.issued_by"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.issued_to"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.expiration_status"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.certificate_error"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.key_size"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.not_after"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.not_before"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.pem_encoded"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.public_key"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.public_key_algorithm"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.serial_number"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.signature_algorithm"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.subject"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.subject_alternative_name.#"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.thumbprint"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.thumbprint_algorithm"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.version"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.number_of_days_to_expire")),
},
},
})
}

func TestAccResourceVcfResourceCertificate_nsx(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccVcfCertificateAuthorityPreCheck(t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccVcfResourceCertificate(
os.Getenv(constants.VcfTestDomainDataSourceId),
os.Getenv(constants.VcfTestMsftCaServerUrl),
os.Getenv(constants.VcfTestMsftCaUser),
os.Getenv(constants.VcfTestMsftCaSecret),
"NSXT_MANAGER",
os.Getenv(constants.VcfTestNsxManagerFqdn)),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.issued_by"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.issued_to"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.expiration_status"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.certificate_error"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.key_size"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.not_after"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.not_before"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.pem_encoded"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.public_key"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.public_key_algorithm"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.serial_number"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.signature_algorithm"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.subject"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.subject_alternative_name.#"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.thumbprint"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.thumbprint_algorithm"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.version"),
resource.TestCheckResourceAttrSet("vcf_certificate.vcenter_cert", "certificate.0.number_of_days_to_expire")),
},
},
})
}

func testAccVcfResourceCertificate(domainID, msftCaServerUrl, msftCaUser, msftCaSecret, resource, fqdn string) string {
return fmt.Sprintf(`
resource "vcf_certificate_authority" "ca" {
microsoft {
Expand All @@ -69,7 +151,8 @@ func testAccVcfResourceCertificate(domainID, msftCaServerUrl, msftCaUser, msftCa
state = "Sofia-grad"
organization = "VMware Inc."
organization_unit = "VCF"
resource = "VCENTER"
resource = %q
fqdn = %q
}
Expand All @@ -82,5 +165,7 @@ func testAccVcfResourceCertificate(domainID, msftCaServerUrl, msftCaUser, msftCa
msftCaSecret,
msftCaServerUrl,
domainID,
resource,
fqdn,
)
}
32 changes: 15 additions & 17 deletions internal/provider/resource_csr.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 Broadcom. All Rights Reserved.
// Copyright 2023-2024 Broadcom. All Rights Reserved.
// SPDX-License-Identifier: MPL-2.0

package provider
Expand Down Expand Up @@ -81,11 +81,16 @@ func ResourceCsr() *schema.Resource {
ValidateFunc: validation.StringIsNotEmpty,
},
"resource": {
Type: schema.TypeString,
Required: true,
// TODO when migrating to 5.x.x support check if these are still accurate
Description: "Resources for which the CSRs are to be generated. One among: SDDC_MANAGER, VCENTER, NSX_MANAGER, NSXT_MANAGER, VROPS, VRSLCM, VXRAIL_MANAGER",
ValidateFunc: validation.StringInSlice([]string{"SDDC_MANAGER", "VCENTER", "NSX_MANAGER", "NSXT_MANAGER", "VROPS", "VRSLCM", "VXRAIL_MANAGER"}, false),
Type: schema.TypeString,
Required: true,
Description: "Resources for which the CSRs are to be generated. One among: SDDC_MANAGER, PSC, VCENTER, NSX_MANAGER, NSXT_MANAGER, VROPS, VRSLCM, VXRAIL_MANAGER",
ValidateFunc: validation.StringInSlice([]string{"SDDC_MANAGER", "PSC", "VCENTER", "NSX_MANAGER", "NSXT_MANAGER", "VROPS", "VRSLCM", "VXRAIL_MANAGER"}, false),
},
"fqdn": {
Type: schema.TypeString,
Required: true,
Description: "FQDN of the resource",
ValidateFunc: validation.NoZeroValues,
},
"csr": {
Type: schema.TypeList,
Expand All @@ -103,14 +108,7 @@ func resourceCsrCreate(ctx context.Context, data *schema.ResourceData, meta inte

domainId := data.Get("domain_id").(string)
resourceType := data.Get("resource").(string)

resourceFqdn, err := certificates.GetFqdnOfResourceTypeInDomain(ctx, domainId, resourceType, apiClient)
if err != nil {
return diag.FromErr(err)
}
if resourceFqdn == nil {
return diag.FromErr(fmt.Errorf("could not determine FQDN for resourceType %s in domain %s", resourceType, domainId))
}
resourceFqdn := data.Get("fqdn").(string)

country := data.Get("country").(string)
email := data.Get("email").(string)
Expand All @@ -135,7 +133,7 @@ func resourceCsrCreate(ctx context.Context, data *schema.ResourceData, meta inte
CSRGenerationSpec: csrGenerationSpec,
Resources: []*models.Resource{
{
Fqdn: *resourceFqdn,
Fqdn: resourceFqdn,
Type: &resourceType,
},
},
Expand All @@ -158,7 +156,7 @@ func resourceCsrCreate(ctx context.Context, data *schema.ResourceData, meta inte
if err != nil {
return diag.FromErr(err)
}
data.SetId("csr:" + domainId + ":" + resourceType + ":" + taskId)
data.SetId(fmt.Sprintf("csr:%s:%s:%s:%s", domainId, resourceType, resourceFqdn, taskId))

getCsrsParams := certificatesSdk.NewGetCSRsParamsWithContext(ctx).
WithTimeout(constants.DefaultVcfApiCallTimeout).
Expand All @@ -168,7 +166,7 @@ func resourceCsrCreate(ctx context.Context, data *schema.ResourceData, meta inte
return diag.FromErr(err)
}

csr := getCsrByResourceFqdn(*resourceFqdn, getCsrResponse.Payload.Elements)
csr := getCsrByResourceFqdn(resourceFqdn, getCsrResponse.Payload.Elements)
flattenedCsr := certificates.FlattenCsr(csr)
_ = data.Set("csr", []interface{}{flattenedCsr})

Expand Down
Loading