From c21a840a6b2c8d32e2426423e3282975c5341980 Mon Sep 17 00:00:00 2001 From: joranm Date: Tue, 18 Dec 2018 18:22:59 +0100 Subject: [PATCH 1/5] Added Service Fabric Reverse Proxy Certificate and Endpoint in Nodetype --- .../resource_arm_service_fabric_cluster.go | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/azurerm/resource_arm_service_fabric_cluster.go b/azurerm/resource_arm_service_fabric_cluster.go index 50686d889797..7086155eacd8 100644 --- a/azurerm/resource_arm_service_fabric_cluster.go +++ b/azurerm/resource_arm_service_fabric_cluster.go @@ -100,6 +100,28 @@ func resourceArmServiceFabricCluster() *schema.Resource { }, }, + "reverse_proxy_certificate": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "thumbprint": { + Type: schema.TypeString, + Required: true, + }, + "thumbprint_secondary": { + Type: schema.TypeString, + Optional: true, + }, + "x509_store_name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "client_certificate_thumbprint": { Type: schema.TypeList, Optional: true, @@ -200,6 +222,10 @@ func resourceArmServiceFabricCluster() *schema.Resource { Required: true, ForceNew: true, }, + "reverse_proxy_endpoint_port": { + Type: schema.TypeInt, + Optional: true, + }, "durability_level": { Type: schema.TypeString, Optional: true, @@ -291,6 +317,9 @@ func resourceArmServiceFabricClusterCreate(d *schema.ResourceData, meta interfac certificateRaw := d.Get("certificate").([]interface{}) certificate := expandServiceFabricClusterCertificate(certificateRaw) + reverseProxyCertificateRaw := d.Get("reverse_proxy_certificate").([]interface{}) + reverseProxyCertificate := expandServiceFabricClusterReverseProxyCertificate(reverseProxyCertificateRaw) + clientCertificateThumbprintRaw := d.Get("client_certificate_thumbprint").([]interface{}) clientCertificateThumbprints := expandServiceFabricClusterClientCertificateThumbprints(clientCertificateThumbprintRaw) @@ -309,6 +338,7 @@ func resourceArmServiceFabricClusterCreate(d *schema.ResourceData, meta interfac ClusterProperties: &servicefabric.ClusterProperties{ AddOnFeatures: addOnFeatures, Certificate: certificate, + ReverseProxyCertificate: reverseProxyCertificate, ClientCertificateThumbprints: clientCertificateThumbprints, DiagnosticsStorageAccountConfig: diagnostics, FabricSettings: fabricSettings, @@ -365,6 +395,9 @@ func resourceArmServiceFabricClusterUpdate(d *schema.ResourceData, meta interfac certificateRaw := d.Get("certificate").([]interface{}) certificate := expandServiceFabricClusterCertificate(certificateRaw) + reverseProxyCertificateRaw := d.Get("reverse_proxy_certificate").([]interface{}) + reverseProxyCertificate := expandServiceFabricClusterReverseProxyCertificate(reverseProxyCertificateRaw) + clientCertificateThumbprintsRaw := d.Get("client_certificate_thumbprint").([]interface{}) clientCertificateThumbprints := expandServiceFabricClusterClientCertificateThumbprints(clientCertificateThumbprintsRaw) @@ -378,6 +411,7 @@ func resourceArmServiceFabricClusterUpdate(d *schema.ResourceData, meta interfac ClusterPropertiesUpdateParameters: &servicefabric.ClusterPropertiesUpdateParameters{ AddOnFeatures: addOnFeatures, Certificate: certificate, + ReverseProxyCertificate: reverseProxyCertificate, ClientCertificateThumbprints: clientCertificateThumbprints, FabricSettings: fabricSettings, NodeTypes: nodeTypes, @@ -450,6 +484,11 @@ func resourceArmServiceFabricClusterRead(d *schema.ResourceData, meta interface{ return fmt.Errorf("Error setting `certificate`: %+v", err) } + reverseProxyCertificate := flattenServiceFabricClusterReverseProxyCertificate(props.ReverseProxyCertificate) + if err := d.Set("reverse_proxy_certificate", reverseProxyCertificate); err != nil { + return fmt.Errorf("Error setting `reverse_proxy_certificate`: %+v", err) + } + clientCertificateThumbprints := flattenServiceFabricClusterClientCertificateThumbprints(props.ClientCertificateThumbprints) if err := d.Set("client_certificate_thumbprint", clientCertificateThumbprints); err != nil { return fmt.Errorf("Error setting `client_certificate_thumbprint`: %+v", err) @@ -564,6 +603,49 @@ func flattenServiceFabricClusterCertificate(input *servicefabric.CertificateDesc return results } +func expandServiceFabricClusterReverseProxyCertificate(input []interface{}) *servicefabric.CertificateDescription { + if len(input) == 0 { + return nil + } + + v := input[0].(map[string]interface{}) + + thumbprint := v["thumbprint"].(string) + x509StoreName := v["x509_store_name"].(string) + + result := servicefabric.CertificateDescription{ + Thumbprint: utils.String(thumbprint), + X509StoreName: servicefabric.X509StoreName(x509StoreName), + } + + if thumb, ok := v["thumbprint_secondary"]; ok { + result.ThumbprintSecondary = utils.String(thumb.(string)) + } + + return &result +} + +func flattenServiceFabricClusterReverseProxyCertificate(input *servicefabric.CertificateDescription) []interface{} { + results := make([]interface{}, 0) + + if v := input; v != nil { + output := make(map[string]interface{}) + + if thumbprint := input.Thumbprint; thumbprint != nil { + output["thumbprint"] = *thumbprint + } + + if thumbprint := input.ThumbprintSecondary; thumbprint != nil { + output["thumbprint_secondary"] = *thumbprint + } + + output["x509_store_name"] = string(input.X509StoreName) + results = append(results, output) + } + + return results +} + func expandServiceFabricClusterClientCertificateThumbprints(input []interface{}) *[]servicefabric.ClientCertificateThumbprint { results := make([]servicefabric.ClientCertificateThumbprint, 0) @@ -730,6 +812,7 @@ func expandServiceFabricClusterNodeTypes(input []interface{}) *[]servicefabric.N instanceCount := node["instance_count"].(int) clientEndpointPort := node["client_endpoint_port"].(int) httpEndpointPort := node["http_endpoint_port"].(int) + reverseProxyEndpointPort := node["reverse_proxy_endpoint_port"].(int) isPrimary := node["is_primary"].(bool) durabilityLevel := node["durability_level"].(string) @@ -739,6 +822,7 @@ func expandServiceFabricClusterNodeTypes(input []interface{}) *[]servicefabric.N IsPrimary: utils.Bool(isPrimary), ClientConnectionEndpointPort: utils.Int32(int32(clientEndpointPort)), HTTPGatewayEndpointPort: utils.Int32(int32(httpEndpointPort)), + ReverseProxyEndpointPort: utils.Int32(int32(reverseProxyEndpointPort)), DurabilityLevel: servicefabric.DurabilityLevel(durabilityLevel), } @@ -804,6 +888,10 @@ func flattenServiceFabricClusterNodeTypes(input *[]servicefabric.NodeTypeDescrip output["http_endpoint_port"] = *port } + if port := v.ReverseProxyEndpointPort; port != nil { + output["reverse_proxy_endpoint_port"] = *port + } + output["durability_level"] = string(v.DurabilityLevel) applicationPorts := make([]interface{}, 0) From cf4b78efd3815aec77ecdf851d6382894af404e5 Mon Sep 17 00:00:00 2001 From: joranm Date: Wed, 19 Dec 2018 18:27:22 +0100 Subject: [PATCH 2/5] Added tests for the sfc reverse proxy and nodetype proxy endpoint --- ...esource_arm_service_fabric_cluster_test.go | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/azurerm/resource_arm_service_fabric_cluster_test.go b/azurerm/resource_arm_service_fabric_cluster_test.go index fd8c6ae44474..34845eb140aa 100644 --- a/azurerm/resource_arm_service_fabric_cluster_test.go +++ b/azurerm/resource_arm_service_fabric_cluster_test.go @@ -28,6 +28,7 @@ func TestAccAzureRMServiceFabricCluster_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "management_endpoint", "http://example:80"), resource.TestCheckResourceAttr(resourceName, "add_on_features.#", "0"), resource.TestCheckResourceAttr(resourceName, "certificate.#", "0"), + resource.TestCheckResourceAttr(resourceName, "reverse_proxy_certificate.#", "0"), resource.TestCheckResourceAttr(resourceName, "client_certificate_thumbprint.#", "0"), resource.TestCheckResourceAttr(resourceName, "diagnostics_config.#", "0"), resource.TestCheckResourceAttr(resourceName, "node_type.#", "1"), @@ -164,6 +165,41 @@ func TestAccAzureRMServiceFabricCluster_certificate(t *testing.T) { }) } + +func TestAccAzureRMServiceFabricCluster_reverseProxyCertificate(t *testing.T) { + resourceName := "azurerm_service_fabric_cluster.test" + ri := acctest.RandInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMServiceFabricClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMServiceFabricCluster_certificates(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMServiceFabricClusterExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "certificate.#", "1"), + resource.TestCheckResourceAttr(resourceName, "certificate.0.thumbprint", "33:41:DB:6C:F2:AF:72:C6:11:DF:3B:E3:72:1A:65:3A:F1:D4:3E:CD:50:F5:84:F8:28:79:3D:BE:91:03:C3:EE"), + resource.TestCheckResourceAttr(resourceName, "certificate.0.x509_store_name", "My"), + resource.TestCheckResourceAttr(resourceName, "reverse_proxy_certificate.#", "1"), + resource.TestCheckResourceAttr(resourceName, "reverse_proxy_certificate.0.thumbprint", "33:41:DB:6C:F2:AF:72:C6:11:DF:3B:E3:72:1A:65:3A:F1:D4:3E:CD:50:F5:84:F8:28:79:3D:BE:91:03:C3:EE"), + resource.TestCheckResourceAttr(resourceName, "reverse_proxy_certificate.0.x509_store_name", "My"), + resource.TestCheckResourceAttr(resourceName, "fabric_settings.0.name", "Security"), + resource.TestCheckResourceAttr(resourceName, "fabric_settings.0.parameters.ClusterProtectionLevel", "EncryptAndSign"), + resource.TestCheckResourceAttr(resourceName, "management_endpoint", "https://example:80"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAzureRMServiceFabricCluster_clientCertificateThumbprint(t *testing.T) { resourceName := "azurerm_service_fabric_cluster.test" ri := acctest.RandInt() @@ -626,6 +662,52 @@ resource "azurerm_service_fabric_cluster" "test" { `, rInt, location, rInt) } +func testAccAzureRMServiceFabricCluster_reverseProxyCertificates(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_service_fabric_cluster" "test" { + name = "acctest-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + reliability_level = "Bronze" + upgrade_mode = "Automatic" + vm_image = "Windows" + management_endpoint = "https://example:80" + + certificate { + thumbprint = "33:41:DB:6C:F2:AF:72:C6:11:DF:3B:E3:72:1A:65:3A:F1:D4:3E:CD:50:F5:84:F8:28:79:3D:BE:91:03:C3:EE" + x509_store_name = "My" + } + + reverse_proxy_certificate { + thumbprint = "33:41:DB:6C:F2:AF:72:C6:11:DF:3B:E3:72:1A:65:3A:F1:D4:3E:CD:50:F5:84:F8:28:79:3D:BE:91:03:C3:EE" + x509_store_name = "My" + } + + fabric_settings { + name = "Security" + + parameters { + "ClusterProtectionLevel" = "EncryptAndSign" + } + } + + node_type { + name = "first" + instance_count = 3 + is_primary = true + client_endpoint_port = 2020 + http_endpoint_port = 80 + reverse_proxy_endpoint_port = 19081 + } +} +`, rInt, location, rInt) +} + func testAccAzureRMServiceFabricCluster_clientCertificateThumbprint(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { From 5fe90ad78b7341f9a5ab829aabc635ea444a191a Mon Sep 17 00:00:00 2001 From: joranm Date: Wed, 19 Dec 2018 18:42:49 +0100 Subject: [PATCH 3/5] Removed double linespace --- azurerm/resource_arm_service_fabric_cluster_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/azurerm/resource_arm_service_fabric_cluster_test.go b/azurerm/resource_arm_service_fabric_cluster_test.go index 34845eb140aa..4623666624dc 100644 --- a/azurerm/resource_arm_service_fabric_cluster_test.go +++ b/azurerm/resource_arm_service_fabric_cluster_test.go @@ -165,7 +165,6 @@ func TestAccAzureRMServiceFabricCluster_certificate(t *testing.T) { }) } - func TestAccAzureRMServiceFabricCluster_reverseProxyCertificate(t *testing.T) { resourceName := "azurerm_service_fabric_cluster.test" ri := acctest.RandInt() From 98b5cf4a0e31a6b2f647208c0e7ec00bb348b3b9 Mon Sep 17 00:00:00 2001 From: joranm Date: Wed, 19 Dec 2018 18:57:20 +0100 Subject: [PATCH 4/5] Updated reverse proxy test to call reverseproxyCertificate test --- azurerm/resource_arm_service_fabric_cluster_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_service_fabric_cluster_test.go b/azurerm/resource_arm_service_fabric_cluster_test.go index 4623666624dc..f33aae608b88 100644 --- a/azurerm/resource_arm_service_fabric_cluster_test.go +++ b/azurerm/resource_arm_service_fabric_cluster_test.go @@ -176,7 +176,7 @@ func TestAccAzureRMServiceFabricCluster_reverseProxyCertificate(t *testing.T) { CheckDestroy: testCheckAzureRMServiceFabricClusterDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMServiceFabricCluster_certificates(ri, location), + Config: testAccAzureRMServiceFabricCluster_reverseProxyCertificates(ri, location), Check: resource.ComposeTestCheckFunc( testCheckAzureRMServiceFabricClusterExists(resourceName), resource.TestCheckResourceAttr(resourceName, "certificate.#", "1"), From 7323f11ff03751ce19dc7ea11dafd8ff0ed83c44 Mon Sep 17 00:00:00 2001 From: joranm Date: Tue, 25 Dec 2018 09:05:49 +0100 Subject: [PATCH 5/5] Added reverse_proxy attributes to the SFC docs --- .../docs/r/service_fabric_cluster.html.markdown | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/website/docs/r/service_fabric_cluster.html.markdown b/website/docs/r/service_fabric_cluster.html.markdown index 330febf18a8b..d4443e198d83 100644 --- a/website/docs/r/service_fabric_cluster.html.markdown +++ b/website/docs/r/service_fabric_cluster.html.markdown @@ -67,6 +67,8 @@ The following arguments are supported: * `certificate` - (Optional) A `certificate` block as defined below. +* `reverse_proxy_certificate` - (Optional) A `reverse_proxy_certificate` block as defined below. + * `client_certificate_thumbprint` - (Optional) One or two `client_certificate_thumbprint` blocks as defined below. -> **NOTE:** If Client Certificates are enabled then at a Certificate must be configured on the cluster. @@ -89,6 +91,16 @@ A `certificate` block supports the following: --- +A `reverse_proxy_certificate` block supports the following: + +* `thumbprint` - (Required) The Thumbprint of the Certificate. + +* `thumbprint_secondary` - (Required) The Secondary Thumbprint of the Certificate. + +* `x509_store_name` - (Required) The X509 Store where the Certificate Exists, such as `My`. + +--- + A `client_certificate_thumbprint` block supports the following: * `thumbprint` - (Required) The Thumbprint associated with the Client Certificate. @@ -137,6 +149,8 @@ A `node_type` block supports the following: * `ephemeral_ports` - (Optional) A `ephemeral_ports` block as defined below. +* `reverse_proxy_endpoint_port` - (Optional) The Port used for the Reverse Proxy Endpoint for this Node Type. Changing this will upgrade the cluster. + --- A `application_ports` block supports the following: