From 182638767fed6c3687d8bc6d50fca8bb370758dd Mon Sep 17 00:00:00 2001 From: Rohit Upadhyay Date: Wed, 11 Oct 2023 15:39:43 +0530 Subject: [PATCH] Added ocsp attributes for ssl_key_cert and ssl_certificate rresources --- bigip/resource_bigip_ssl_certificate.go | 70 +++++++++++- bigip/resource_bigip_ssl_certificate_test.go | 34 ++++++ bigip/resource_bigip_ssl_key_cert.go | 64 ++++++++++- bigip/resource_bigip_ssl_key_cert_test.go | 35 ++++++ docs/resources/bigip_ssl_certificate.md | 6 + docs/resources/bigip_ssl_key_cert.md | 5 + .../github.com/f5devcentral/go-bigip/sys.go | 108 +++++++++--------- 7 files changed, 263 insertions(+), 59 deletions(-) diff --git a/bigip/resource_bigip_ssl_certificate.go b/bigip/resource_bigip_ssl_certificate.go index 0391dd753..d0fc14d80 100644 --- a/bigip/resource_bigip_ssl_certificate.go +++ b/bigip/resource_bigip_ssl_certificate.go @@ -39,7 +39,6 @@ func resourceBigipSslCertificate() *schema.Resource { //ForceNew: true, Description: "Content of certificate on Disk", }, - "partition": { Type: schema.TypeString, Optional: true, @@ -47,6 +46,21 @@ func resourceBigipSslCertificate() *schema.Resource { Description: "Partition of ssl certificate", ValidateFunc: validatePartitionName, }, + "monitoring_type": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the type of monitoring used", + }, + "issuer_cert": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the issuer certificate", + }, + "ocsp": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the OCSP responder", + }, "full_path": { Type: schema.TypeString, Optional: true, @@ -64,7 +78,19 @@ func resourceBigipSslCertificateCreate(ctx context.Context, d *schema.ResourceDa certPath := d.Get("content").(string) partition := d.Get("partition").(string) - err := client.UploadCertificate(name, certPath, partition) + cert := &bigip.Certificate{ + Name: name, + Partition: partition, + } + + if val, ok := d.GetOk("monitoring_type"); ok { + cert.CertValidationOptions = []string{val.(string)} + } + if val, ok := d.GetOk("issuer_cert"); ok { + cert.IssuerCert = val.(string) + } + + err := client.UploadCertificate(certPath, cert) if err != nil { return diag.FromErr(fmt.Errorf("error in Importing certificate (%s): %s", name, err)) } @@ -88,6 +114,17 @@ func resourceBigipSslCertificateCreate(ctx context.Context, d *schema.ResourceDa log.Printf("[ERROR]Sending Telemetry data failed:%v", err) } } + + if val, ok := d.GetOk("ocsp"); ok { + certValidState := &bigip.CertValidatorState{Name: val.(string)} + certValidRef := &bigip.CertValidatorReference{} + certValidRef.Items = append(certValidRef.Items, *certValidState) + cert.CertValidatorRef = certValidRef + err = client.UpdateCertificate(certPath, cert) + if err != nil { + log.Printf("[ERROR]Unable to add ocsp to the certificate:%v", err) + } + } return resourceBigipSslCertificateRead(ctx, d, meta) } @@ -119,6 +156,11 @@ func resourceBigipSslCertificateRead(ctx context.Context, d *schema.ResourceData _ = d.Set("name", certificate.Name) _ = d.Set("partition", certificate.Partition) _ = d.Set("full_path", certificate.FullPath) + _ = d.Set("issuer_cert", certificate.IssuerCert) + if certificate.CertValidationOptions != nil && len(certificate.CertValidationOptions) > 0 { + monitor_type := certificate.CertValidationOptions[0] + _ = d.Set("monitoring_type", monitor_type) + } return nil } @@ -129,10 +171,26 @@ func resourceBigipSslCertificateUpdate(ctx context.Context, d *schema.ResourceDa log.Println("[INFO] Certificate Name " + name) certpath := d.Get("content").(string) partition := d.Get("partition").(string) - /*if !strings.HasSuffix(name, ".crt") { - name = name + ".crt" - }*/ - err := client.UpdateCertificate(name, certpath, partition) + + cert := &bigip.Certificate{ + Name: name, + Partition: partition, + } + + if val, ok := d.GetOk("monitoring_type"); ok { + cert.CertValidationOptions = []string{val.(string)} + } + if val, ok := d.GetOk("issuer_cert"); ok { + cert.IssuerCert = val.(string) + } + if val, ok := d.GetOk("ocsp"); ok { + certValidState := &bigip.CertValidatorState{Name: val.(string)} + certValidRef := &bigip.CertValidatorReference{} + certValidRef.Items = append(certValidRef.Items, *certValidState) + cert.CertValidatorRef = certValidRef + } + + err := client.UpdateCertificate(certpath, cert) if err != nil { return diag.FromErr(fmt.Errorf("error in Importing certificate (%s): %s", name, err)) } diff --git a/bigip/resource_bigip_ssl_certificate_test.go b/bigip/resource_bigip_ssl_certificate_test.go index 46c08025e..7b634a648 100644 --- a/bigip/resource_bigip_ssl_certificate_test.go +++ b/bigip/resource_bigip_ssl_certificate_test.go @@ -28,6 +28,17 @@ resource "bigip_ssl_certificate" "test-cert" { } ` +var TestSslCertOCSPResource = ` +resource "bigip_ssl_certificate" "ssl-test-certificate-tc1" { + name = "test-certificate" + content = "${file("` + folder + `/../examples/mycertocspv2.crt")}" + partition = "Common" + monitoring_type = "ocsp" + issuer_cert = "/Common/MyCA" + ocsp = "/Common/testocsp1" +} +` + func TestAccBigipSslCertificateImportToBigip(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -88,6 +99,29 @@ func TestAccBigipSslCertificateTCs(t *testing.T) { }) } +func TestAccBigipSslCertificateOCSP(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAcctPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testChecksslcertificateDestroyed, + Steps: []resource.TestStep{ + { + Config: TestSslCertOCSPResource, + Check: resource.ComposeTestCheckFunc( + testChecksslcertificateExists("test-certificate", true), + resource.TestCheckResourceAttr("bigip_ssl_certificate.ssl-test-certificate-tc1", "name", "test-certificate"), + resource.TestCheckResourceAttr("bigip_ssl_certificate.ssl-test-certificate-tc1", "partition", "Common"), + resource.TestCheckResourceAttr("bigip_ssl_certificate.ssl-test-certificate-tc1", "monitoring_type", "ocsp"), + resource.TestCheckResourceAttr("bigip_ssl_certificate.ssl-test-certificate-tc1", "issuer_cert", "/Common/MyCA"), + resource.TestCheckResourceAttr("bigip_ssl_certificate.ssl-test-certificate-tc1", "ocsp", "/Common/testocsp1"), + ), + }, + }, + }) +} + func testChecksslcertificateExists(name string, exists bool) resource.TestCheckFunc { return func(s *terraform.State) error { client := testAccProvider.Meta().(*bigip.BigIP) diff --git a/bigip/resource_bigip_ssl_key_cert.go b/bigip/resource_bigip_ssl_key_cert.go index c25a4f481..e95d01cf0 100644 --- a/bigip/resource_bigip_ssl_key_cert.go +++ b/bigip/resource_bigip_ssl_key_cert.go @@ -58,6 +58,21 @@ func resourceBigipSSLKeyCert() *schema.Resource { Computed: true, Description: "Full Path Name of ssl certificate", }, + "cert_monitoring_type": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the type of monitoring used.", + }, + "issuer_cert": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the issuer certificate", + }, + "cert_ocsp": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the OCSP responder", + }, "passphrase": { Type: schema.TypeString, Optional: true, @@ -105,7 +120,19 @@ func resourceBigipSSLKeyCertCreate(ctx context.Context, d *schema.ResourceData, if err != nil { return diag.FromErr(fmt.Errorf("error while adding the ssl key: %v", err)) } - err = client.UploadCertificate(certName, certPath, partition) + + cert := &bigip.Certificate{ + Name: certName, + Partition: partition, + } + if val, ok := d.GetOk("cert_monitoring_type"); ok { + cert.CertValidationOptions = []string{val.(string)} + } + if val, ok := d.GetOk("issuer_cert"); ok { + cert.IssuerCert = val.(string) + } + + err = client.UploadCertificate(certPath, cert) if err != nil { return diag.FromErr(fmt.Errorf("error while uploading the ssl cert: %v", err)) } @@ -114,6 +141,17 @@ func resourceBigipSSLKeyCertCreate(ctx context.Context, d *schema.ResourceData, return diag.FromErr(fmt.Errorf("error while ending transaction: %d", err)) } + if val, ok := d.GetOk("cert_ocsp"); ok { + certValidState := &bigip.CertValidatorState{Name: val.(string)} + certValidRef := &bigip.CertValidatorReference{} + certValidRef.Items = append(certValidRef.Items, *certValidState) + cert.CertValidatorRef = certValidRef + err = client.UpdateCertificate(certPath, cert) + if err != nil { + log.Printf("[ERROR]Unable to add ocsp to the certificate:%v", err) + } + } + id := keyName + "_" + certName d.SetId(id) return resourceBigipSSLKeyCertRead(ctx, d, meta) @@ -147,6 +185,11 @@ func resourceBigipSSLKeyCertRead(ctx context.Context, d *schema.ResourceData, me d.Set("cert_name", certificate.Name) d.Set("cert_full_path", certificate.FullPath) d.Set("partition", key.Partition) + d.Set("issuer_cert", certificate.IssuerCert) + if certificate.CertValidationOptions != nil && len(certificate.CertValidationOptions) > 0 { + monitor_type := certificate.CertValidationOptions[0] + _ = d.Set("cert_monitoring_type", monitor_type) + } return nil } @@ -184,7 +227,24 @@ func resourceBigipSSLKeyCertUpdate(ctx context.Context, d *schema.ResourceData, return diag.FromErr(fmt.Errorf("error while trying to modify the ssl key (%s): %s", keyFullPath, err)) } - err = client.UpdateCertificate(certName, certPath, partition) + cert := &bigip.Certificate{ + Name: certName, + Partition: partition, + } + if val, ok := d.GetOk("cert_monitoring_type"); ok { + cert.CertValidationOptions = []string{val.(string)} + } + if val, ok := d.GetOk("issuer_cert"); ok { + cert.IssuerCert = val.(string) + } + if val, ok := d.GetOk("cert_ocsp"); ok { + certValidState := &bigip.CertValidatorState{Name: val.(string)} + certValidRef := &bigip.CertValidatorReference{} + certValidRef.Items = append(certValidRef.Items, *certValidState) + cert.CertValidatorRef = certValidRef + } + + err = client.UpdateCertificate(certPath, cert) if err != nil { return diag.FromErr(fmt.Errorf("error while updating the ssl certificate (%s): %s", certName, err)) } diff --git a/bigip/resource_bigip_ssl_key_cert_test.go b/bigip/resource_bigip_ssl_key_cert_test.go index 235811e3f..f1bf2b99d 100644 --- a/bigip/resource_bigip_ssl_key_cert_test.go +++ b/bigip/resource_bigip_ssl_key_cert_test.go @@ -42,6 +42,19 @@ resource "bigip_ltm_profile_server_ssl" "test-ServerSsl" { } ` +var sslProfileCertKeyOCSP = ` +resource "bigip_ssl_key_cert" "testkeycert" { + partition = "Common" + key_name = "ssl-test-key" + key_content = "${file("` + folder + `/../examples/mycertocspv2.pem")}" + cert_name = "ssl-test-cert" + cert_content = "${file("` + folder + `/../examples/mycertocspv2.crt")}" + cert_monitoring_type = "ocsp" + issuer_cert = "/Common/MyCA" + cert_ocsp = "/Common/testocsp1" +} +` + func TestAccBigipSSLCertKeyCreate(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -112,3 +125,25 @@ func TestAccBigipSSLCertKeyCreateCertKeyProfile(t *testing.T) { }, }) } + +func TestAccBigipSSLCertKeyCreateCertKeyProfileOCSP(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAcctPreCheck(t) + }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: sslProfileCertKeyOCSP, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("bigip_ssl_key_cert.testkeycert", "key_name", "ssl-test-key"), + resource.TestCheckResourceAttr("bigip_ssl_key_cert.testkeycert", "cert_name", "ssl-test-cert"), + resource.TestCheckResourceAttr("bigip_ssl_key_cert.testkeycert", "partition", "Common"), + resource.TestCheckResourceAttr("bigip_ssl_key_cert.testkeycert", "cert_monitoring_type", "ocsp"), + resource.TestCheckResourceAttr("bigip_ssl_key_cert.testkeycert", "issuer_cert", "/Common/MyCA"), + resource.TestCheckResourceAttr("bigip_ssl_key_cert.testkeycert", "cert_ocsp", "/Common/testocsp1"), + ), + }, + }, + }) +} diff --git a/docs/resources/bigip_ssl_certificate.md b/docs/resources/bigip_ssl_certificate.md index 2ea0fba54..f48032b85 100644 --- a/docs/resources/bigip_ssl_certificate.md +++ b/docs/resources/bigip_ssl_certificate.md @@ -33,3 +33,9 @@ resource "bigip_ssl_certificate" "test-cert" { * `content` - (Required) Content of certificate on Local Disk,path of SSL certificate will be provided to terraform `file` function * `partition` - Partition on to SSL Certificate to be imported. The parameter is not required when running terraform import operation. In such case the name must be provided in full_path format. + +* `monitoring_type` - Specifies the type of monitoring used. + +* `issuer_cert` - Specifies the issuer certificate. + +* `ocsp` - Specifies the OCSP responder. diff --git a/docs/resources/bigip_ssl_key_cert.md b/docs/resources/bigip_ssl_key_cert.md index 570cca38e..0b14d1d4f 100644 --- a/docs/resources/bigip_ssl_key_cert.md +++ b/docs/resources/bigip_ssl_key_cert.md @@ -42,6 +42,11 @@ resource "bigip_ssl_key_cert" "testkeycert" { * `passphrase` - (Optional,type `string`) Passphrase on the SSL key. +* `cert_monitoring_type` - (Optional,type `string`) Specifies the type of monitoring used. + +* `issuer_cert` - (Optional,type `string`) Specifies the issuer certificate. + +* `cert_ocsp` - (Optional,type `string`) Specifies the OCSP responder. ## Attribute Reference diff --git a/vendor/github.com/f5devcentral/go-bigip/sys.go b/vendor/github.com/f5devcentral/go-bigip/sys.go index a69f2ea8f..0a2f63c7f 100644 --- a/vendor/github.com/f5devcentral/go-bigip/sys.go +++ b/vendor/github.com/f5devcentral/go-bigip/sys.go @@ -320,38 +320,49 @@ type Certificates struct { // Certificate represents an SSL Certificate. type Certificate struct { - AppService string `json:"appService,omitempty"` - CachePath string `json:"cachePath,omitempty"` - CertificateKeyCurveName string `json:"certificateKeyCurveName,omitempty"` - CertificateKeySize int `json:"certificateKeySize,omitempty"` - CertValidationOptions string `json:"certValidationOptions,omitempty"` - Checksum string `json:"checksum,omitempty"` - CreatedBy string `json:"createdBy,omitempty"` - CreateTime string `json:"createTime,omitempty"` - Email string `json:"email,omitempty"` - ExpirationDate int64 `json:"expirationDate,omitempty"` - ExpirationString string `json:"expirationString,omitempty"` - Fingerprint string `json:"fingerprint,omitempty"` - FullPath string `json:"fullPath,omitempty"` - Generation int `json:"generation,omitempty"` - IsBundle string `json:"isBundle,omitempty"` - IsDynamic string `json:"isDynamic,omitempty"` - Issuer string `json:"issuer,omitempty"` - IssuerCert string `json:"issuerCert,omitempty"` - KeyType string `json:"keyType,omitempty"` - LastUpdateTime string `json:"lastUpdateTime,omitempty"` - Mode int `json:"mode,omitempty"` - Name string `json:"name,omitempty"` - Partition string `json:"partition,omitempty"` - Revision int `json:"revision,omitempty"` - SerialNumber string `json:"serialNumber,omitempty"` - Size uint64 `json:"size,omitempty"` - SourcePath string `json:"sourcePath,omitempty"` - Subject string `json:"subject,omitempty"` - SubjectAlternativeName string `json:"subjectAlternativeName,omitempty"` - SystemPath string `json:"systemPath,omitempty"` - UpdatedBy string `json:"updatedBy,omitempty"` - Version int `json:"version,omitempty"` + AppService string `json:"appService,omitempty"` + CachePath string `json:"cachePath,omitempty"` + CertificateKeyCurveName string `json:"certificateKeyCurveName,omitempty"` + CertificateKeySize int `json:"certificateKeySize,omitempty"` + CertValidationOptions []string `json:"certValidationOptions,omitempty"` + Checksum string `json:"checksum,omitempty"` + CreatedBy string `json:"createdBy,omitempty"` + CreateTime string `json:"createTime,omitempty"` + Email string `json:"email,omitempty"` + ExpirationDate int64 `json:"expirationDate,omitempty"` + ExpirationString string `json:"expirationString,omitempty"` + Fingerprint string `json:"fingerprint,omitempty"` + FullPath string `json:"fullPath,omitempty"` + Generation int `json:"generation,omitempty"` + IsBundle string `json:"isBundle,omitempty"` + IsDynamic string `json:"isDynamic,omitempty"` + Issuer string `json:"issuer,omitempty"` + IssuerCert string `json:"issuerCert,omitempty"` + KeyType string `json:"keyType,omitempty"` + LastUpdateTime string `json:"lastUpdateTime,omitempty"` + Mode int `json:"mode,omitempty"` + Name string `json:"name,omitempty"` + Partition string `json:"partition,omitempty"` + Revision int `json:"revision,omitempty"` + SerialNumber string `json:"serialNumber,omitempty"` + Size uint64 `json:"size,omitempty"` + SourcePath string `json:"sourcePath,omitempty"` + Subject string `json:"subject,omitempty"` + SubjectAlternativeName string `json:"subjectAlternativeName,omitempty"` + SystemPath string `json:"systemPath,omitempty"` + UpdatedBy string `json:"updatedBy,omitempty"` + Version int `json:"version,omitempty"` + CertValidatorRef *CertValidatorReference `json:"certValidatorsReference,omitempty"` +} + +type CertValidatorReference struct { + Items []CertValidatorState `json:"items,omitempty"` +} + +type CertValidatorState struct { + Name string `json:"name,omitempty"` + Partition string `json:"partition,omitempty"` + FullPath string `json:"fullPath,omitempty"` } // Keys represents a list of installed keys. @@ -429,25 +440,22 @@ func (b *BigIP) ModifyExternalDatagroupfile(dgName string, dataGroup *ExternalDG // ModifyCertificate installs a certificate. func (b *BigIP) ModifyCertificate(certName string, cert *Certificate) error { - return b.patch(cert, uriSys, uriFile, uriSslCert, certName) + return b.patch(cert, uriSys, uriFile, uriSslCert, certName, "?expandSubcollections=true") } // UploadCertificate copies a certificate local disk to BIGIP -func (b *BigIP) UploadCertificate(certname, certpath, partition string) error { +func (b *BigIP) UploadCertificate(certpath string, cert *Certificate) error { certbyte := []byte(certpath) - _, err := b.UploadBytes(certbyte, certname) + _, err := b.UploadBytes(certbyte, cert.Name) if err != nil { return err } - sourcepath := "file://" + REST_DOWNLOAD_PATH + "/" + certname + sourcepath := "file://" + REST_DOWNLOAD_PATH + "/" + cert.Name log.Printf("[DEBUG] sourcepath :%+v", sourcepath) - cert := Certificate{ - Name: certname, - SourcePath: sourcepath, - Partition: partition, - } + + cert.SourcePath = sourcepath log.Printf("cert: %+v\n", cert) - err = b.AddCertificate(&cert) + err = b.AddCertificate(cert) if err != nil { return err } @@ -474,20 +482,18 @@ func (b *BigIP) DeleteCertificate(name string) error { } // UpdateCertificate copies a certificate local disk to BIGIP -func (b *BigIP) UpdateCertificate(certname, certpath, partition string) error { +func (b *BigIP) UpdateCertificate(certpath string, cert *Certificate) error { certbyte := []byte(certpath) - _, err := b.UploadBytes(certbyte, certname) + _, err := b.UploadBytes(certbyte, cert.Name) if err != nil { return err } - sourcepath := "file://" + REST_DOWNLOAD_PATH + "/" + certname - cert := Certificate{ - Name: certname, - SourcePath: sourcepath, - } - certName := fmt.Sprintf("/%s/%s", partition, certname) + sourcepath := "file://" + REST_DOWNLOAD_PATH + "/" + cert.Name + + cert.SourcePath = sourcepath + certName := fmt.Sprintf("/%s/%s", cert.Partition, cert.Name) log.Printf("certName: %+v\n", certName) - err = b.ModifyCertificate(certName, &cert) + err = b.ModifyCertificate(certName, cert) if err != nil { return err }