0

We need to have a Function App created for accessing Office 365 instance. The access is using Certificate authentication. Hence we are uploading the certificate into Azure Key Vault and need to import the Certificate from Key Vault.

We are using ARM Templates for the Azure Resource Deployment. We are trying to create Azure Key Vault Certificate as mentioned in the link

https://erwinstaal.nl/posts/using-an-arm-template-to-deploy-your-ssl-certificate-stored-in-keyvault-on-an-web-app/

upload .pfx certificate through azure devops pipeline

As mentioned in the above pages, we are able to create new secrets in Key Vault. But, we do not see the imported certificate in the list of Certificates (when checked in the Azure Portal UI) and also, we are not able to Import the Certificates in the Function App. Is this not supported in the current ARM Template Key Vault commandlet? How can this be fixed?

Silly John
  • 1,584
  • 2
  • 16
  • 34
  • If the answer was helpful, Please [Accept it as an Answer](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work), so that others who encounter the same issue can find this solution and fix their problem. – Ansuman Bal Jan 28 '22 at 09:38

1 Answers1

2

As mentioned in the above pages, we are able to create new secrets in Key Vault. But, we do not see the imported certificate in the list of Certificates (when checked in the Azure Portal UI)

This is because ARM Template doesn't have a property to upload a certificate so instead it stores a base64 encoded value of the PFX certificate in the Secret in a application/x-pkcs12 like below :

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
      "keyVault": {
        "type": "string",
        "defaultValue" :"funccertimporttestkv"
      },
      "TestCedential_1": {
        "type": "secureString",
        "defaultValue":"MIIKYAIBAzCCChwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXhp4XPejOrOIgc9/6dkfBBSgxY73wtbf+G3N7KTYP1LKKHS0YwICB9A="
      },
      "TestCedentialName_1": {
        "type": "string",
        "defaultValue": "funcAppValidationCert"
      }
    },
    "variables": {
    },
    "resources": [
      {
        "type": "Microsoft.KeyVault/vaults/secrets",
        "name": "[concat(parameters('keyVault'), '/', parameters('TestCedentialName_1'))]",
        "apiVersion": "2015-06-01",
        "properties": {
          "contentType": "application/x-pkcs12",
          "value": "[parameters('TestCedential_1')]"
        }
      }
    ],
    "outputs": {}
  }

enter image description here


we are not able to Import the Certificates in the Function App. Is this not supported in the current ARM Template Key Vault commandlet? How can this be fixed?

If you are using a template like below :

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "envName": {
            "defaultValue": "qa",
            "type": "String"
        },
        "certificateName": {
            "type": "string",
            "defaultValue": "funcAppValidationCert"
        },
        "domainName": {
            "type": "string",
            "defaultValue": "localhost"
        },
        "keyvaultName": {
            "type": "string",
            "defaultValue": "funccertimporttestkv"
        },
        "password": {
            "type": "string",
            "defaultValue": "Password@1234"
        }
    },
    "variables":{
        "functionStorageAccountName" :"[concat('storaccfn',parameters('envName'),resourceGroup().location)]",
        "appServicePlanName" :"[concat('plan-myapp-',parameters('envName'),resourceGroup().location)]",
        "sitesFunctionAppName" :"[concat('func-ans-',parameters('envName'),resourceGroup().location)]"
    },
    "resources": [ 
        {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2021-04-01",
            "name": "[variables('functionStorageAccountName')]",
            "location": "[resourceGroup().location]",
            "sku": {
                "name": "Standard_LRS",
                "tier": "Standard"
            },
            "kind": "Storage",
            "properties": {
                "supportsHttpsTrafficOnly": true
            }
        },
        {
            "type": "Microsoft.Web/serverfarms",
            "apiVersion": "2018-02-01",
            "name": "[variables('appServicePlanName')]",
            "location": "[resourceGroup().location]",
            "sku": {
                "name": "S1",
                "tier": "Standard",
                "size": "S1",
                "family": "S",
                "capacity": 1
            },
            "kind": "app",
            "properties": {
                "perSiteScaling": false,
                "maximumElasticWorkerCount": 1,
                "isSpot": false,
                "reserved": false,
                "isXenon": false,
                "hyperV": false,
                "targetWorkerCount": 0,
                "targetWorkerSizeId": 0
            }
        },
        {
            "type": "Microsoft.Web/sites",
            "apiVersion": "2018-11-01",
            "name": "[variables('sitesFunctionAppName')]",
            "location": "[resourceGroup().location]",
            "dependsOn": [
                "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
        "[resourceId('Microsoft.Storage/storageAccounts', variables('functionStorageAccountName'))]"
            ],
            "kind": "functionapp",
    "identity": {
        "type": "SystemAssigned"
    },
            "properties": {
                "enabled": true,
                "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
                "httpsOnly": true,
                "siteConfig": {
            "appSettings":[
                {
                    "name": "AzureWebJobsStorage",
                    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('functionStorageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('functionStorageAccountName')),'2017-06-01').keys[0].value)]"
                },
                {
                    "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
                    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('functionStorageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('functionStorageAccountName')),'2017-06-01').keys[0].value)]"
                },
                {
                    "name": "WEBSITE_CONTENTSHARE",
                    "value": "[toLower(variables('sitesFunctionAppName'))]"
                },
                {
                    "name": "FUNCTIONS_EXTENSION_VERSION",
                    "value": "~3"
                },
                {
                    "name": "FUNCTIONS_WORKER_RUNTIME",
                    "value": "dotnet"
                },
                {
                    "name": "WEBSITE_RUN_FROM_PACKAGE",
                    "value": "1"
                },
                {
                    "name": "WEBSITE_TIME_ZONE",
                    "value": "UTC"
                }
            ]
                }
            }
        },
        {
            "type": "Microsoft.Web/sites/hostNameBindings",
            "apiVersion": "2016-08-01",
            "name": "[concat(variables('sitesFunctionAppName'), '/', parameters('domainName'))]",
            "location": "[resourceGroup().location]",
            "dependsOn": [
                "[resourceId('Microsoft.Web/certificates', parameters('certificateName'))]",
                 "[resourceId('Microsoft.Web/sites', variables('sitesFunctionAppName'))]"
            ],
            "properties": {
                "siteName": "[variables('sitesFunctionAppName')]",
                "hostNameType": "Verified",
                "sslState": "SniEnabled",
                "thumbprint": "[reference(resourceId('Microsoft.Web/certificates', parameters('certificateName'))).Thumbprint]"
            }
        },
        {
            "type": "Microsoft.Web/certificates",
            "name": "[parameters('certificateName')]",
            "apiVersion": "2016-03-01",
            "location": "[resourceGroup().location]",
            "properties": {
                "keyVaultId": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyvaultName'))]",
                "keyVaultSecretName": "[parameters('certificateName')]",
                "password": "[parameters('password')]",
                "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
            },
            "dependsOn":[
                    "[resourceId('Microsoft.Web/sites', variables('sitesFunctionAppName'))]"
            ]
        }
     ]
 }

And facing a Problem of Bad Request which says not able to access the keyvault like below:

enter image description here

Then Add Microsoft.Azure.CertificateRegistration (i.e. ObjectId : ed47c2a1-bd23-4341-b39c-f4fd69138dd3) , Microsoft Azure App Service (Internal) (i.e. ObjectId : 505e3754-d8a9-4f8b-97b6-c3e48ac7a543) & Microsoft Azure App Service (i.e. ObjectId : f8daea97-62e7-4026-becf-13c2ea98e8b4) in access policy for keyvault.

enter image description here


And If you get the below after solving the above then please check if you have converted the certificate value to a proper base64 encoded value.

enter image description here

Then you can refer this SO thread to properly provide a base64 value of the certificate.


Output:

After successful deployment you can see this TLS/SSL settings :

enter image description here

Ansuman Bal
  • 9,705
  • 2
  • 10
  • 27