normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

API Management and Service Fabric Collaboration for Global Scale Applications

As you know, you can achieve Microservice architecture by using Service Fabric, but you might want to need request routing features for your applications for multi languages, cross devices or others. In such a case, you can use API Management for it. In this article, you can learn how to setup API Management with Service Fabric.

Edit ServiceManifest.xml of your Serviec Fabric project

At first, make a REST API application and deploy it into your Service Fabric cluster. Note to edit "ServiceManifest.xml" file in your Service Fabric project not to specify actual port like below. This setup is needed to collaborate API Management and Service Fabric.

<Resources>
  <Endpoints>
    <Endpoint Protocol="http" Name="ServiceEndpoint" Type="Input" />
  </Endpoints>
</Resources>

Download certificate file to access Service Fabric cluster

You probably created the certificate automatically when you made your Service Fabric cluster. Go to your Service Fabric cluster, choose "security" tab and pick up the certificate thumbprint like below.
f:id:waritohutsu:20180415080735p:plain

Next, download the certificate file as pfx into your machine. Go to KeyVault, choose "certificate" tab, select your certificate and choose "Download in PFX/PEM format" like below.
f:id:waritohutsu:20180415081024p:plain

Save thumbprint and pfx file to use ARM Template in later section.

Deploy new API Management instance by using ARM Template

Download apim.json and apim.parameters.json ARM Templates from service-fabric-api-management/apim.json at master · Azure-Samples/service-fabric-api-management · GitHub. And add '"validateCertificateChain": false into apim.json' if you will use self-signed certificate file like below .

            "apiVersion": "2017-03-01",
            "type": "Microsoft.ApiManagement/service/backends",
            "name": "[concat(parameters('apimInstanceName'), '/', parameters('service_fabric_backend_name'))]",
            "dependsOn": [
                "[resourceId('Microsoft.ApiManagement/service', parameters('apimInstanceName'))]",
                "[resourceId('Microsoft.ApiManagement/service/certificates', parameters('apimInstanceName'), parameters('serviceFabricCertificateName'))]"
            ],
            "properties": {
                "description": "My Service Fabric backend",
                "url": "fabric:/fake/service",
                "protocol": "http",
                "resourceId": "[parameters('clusterHttpManagementEndpoint')]",
                "tls":{
                    "validateCertificateChain": false
                },
                "properties": {
                    "serviceFabricCluster": {
                        "managementEndpoints": [
                            "[parameters('clusterHttpManagementEndpoint')]"
                        ],
                        "clientCertificateThumbprint": "[parameters('serviceFabricCertificateThumbprint')]",
                        "serverCertificateThumbprints": [
                            "[parameters('serviceFabricCertificateThumbprint')]"
                        ],
                        "maxPartitionResolutionRetries": 5
                    }
                }
            }
        },

Update apim.parameters.json like below.

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "apimInstanceName": {
            "value": "sfapim01"
        },
        "subnetName": {
            "value": "API-Subnet"
        },
        "apimPublisherEmail": {
            "value": "mymail@address.com"
        },
        "apimSku": {
            "value": "Developer"
        },
        "serviceFabricCertificateName": {
            "value": "Daichi Isami"
        },
        "serviceFabricCertificate": {
            "value": "base64 encoded string of your pfx file. don't insert breaklines"
        },
        "certificatePassword": {
            "value": ""
        },
        "serviceFabricCertificateThumbprint": {
            "value": "your Cluster certificates thumbprint"
        },
        "url_path": {
            "value": "/api/values"
        },
        "clusterHttpManagementEndpoint": {
            "value": "https://'your cluster name'.westus.cloudapp.azure.com:19080"
        },
        "inbound_policy":{
            "value": "<policies>\r\n  <inbound>\r\n    <base />\r\n    <set-backend-service backend-id=\"servicefabric\" sf-service-instance-name=\"fabric:/SFApiApp/Web1\" sf-resolve-condition=\"@((int)context.Response.StatusCode != 200)\" />\r\n  </inbound>\r\n  <backend>\r\n    <base />\r\n  </backend>\r\n  <outbound>\r\n    <base />\r\n  </outbound>\r\n  <on-error>\r\n    <base />\r\n  </on-error>\r\n</policies>"
        },
        "policies_policy_name": {
            "value": "policy"
        },
        "apis_service_fabric_app_name": {
            "value": "service-fabric-app"
        },
        "apim_service_fabric_product_name": {
            "value": "service-fabric-api-product"
        },
        "service_fabric_backend_name": {
            "value": "servicefabric"
        },
        "apis_service_fabric_app_name_operation": {
            "value": "service-fabric-app-operation"
        },
        "vnetName": {
            "value": "VNet-sf-sample01-1709cluster"
        },
        "vnetVersion": {
            "value": "2017-03-01"
        },
        "networkSecurityGroupName": {
            "value": "apim-vnet-security-03"
        },
        "networkSecurityGroupVersion": {
            "value": "2017-03-01"
        }
    }

You can put blank for certificatePassword value if you created your certificate file automatically. Refer to commands for base64encode for your certificate below if you need.

$bytes = [System.IO.File]::ReadAllBytes("C:\temp\yourpfxfile.pfx")
$b64 = [System.Convert]::ToBase64String($bytes);
$b64 

It should takes 30 or 40 minutes to complete this deployment.

Access your Service Fabric application via API Management

Go to "Developer Portal" of your API Management, choose "Service Fabric App" among APIs and click "Try it" button. Now, you can send requests to your API application via API Management like below.
f:id:waritohutsu:20180415082448p:plain

Tips No.1: Troubleshoot - "Service Fabric exception when trying to resolve partition: A Security error has occurred, failed to verify remote certificate"

You might get error messages below if you use self-signed certificate file.

service-fabric-backend (1371 ms)
{
    "message": "Service Fabric exception when trying to resolve partition: A Security error has occurred, failed to verify remote certificate.",
    "serviceName": {},
    "resourceId": "https://sf-sample01-1709cluster.westus.cloudapp.azure.com:19080",
    "managementEndpoint": [
        "https://sf-sample01-1709cluster.westus.cloudapp.azure.com:19080"
    ]
}

You should forget to update apim.json. Refer to " Deploy new API Management instance by using ARM Template" section in this article.

Tips No.2: Don't use “Client certificates” for API Management

As you know, Service Fabric uses multiple certificates for itself. Note that use "Cluster certificates" not "Client certificates" for API Management.
f:id:waritohutsu:20180415110457p:plain