استخدام Azure Key Vault لتمرير قيمة معلمة آمنة أثناء التوزيع

بدلاً من وضع قيمة آمنة (مثل كلمة المرور) مباشرةً في القالب أو ملف المعلمة، يمكنك استرداد القيمة من Azure Key Vault أثناء النشر. يمكنك استرداد القيمة من خلال الرجوع إلى خزنة المفاتيح والسر في ملف المعلمة. لا يتم عرض القيمة مطلقاً لأنك تشير فقط إلى معرف مخزن المفاتيح الخاص بها.

هام

تركز هذه المقالة على كيفية تمرير قيمة حساسة كمعامل قالب. عندما يتم تمرير السر كمعامل، يمكن أن يوجد مخزن المفاتيح في اشتراك مختلف عن مجموعة الموارد التي تقوم بالنشر إليها.

لا تتناول هذه المقالة كيفية تعيين خاصية جهاز ظاهري على عنوان URL لشهادة في مخزن مفاتيح. للحصول على نموذج البدء السريع لهذا السيناريو، راجع تثبيت شهادة من Azure Key Vault على جهاز ظاهري.

نشر خزائن المفاتيح والأسرار

للوصول إلى مخزن المفاتيح أثناء نشر النموذج، قم بتعيين enabledForTemplateDeployment في خزنة المفاتيح على true.

إذا كان لديك خزنة مفاتيح بالفعل، فتأكد من أنها تسمح بنشر القالب.

az keyvault update  --name ExampleVault --enabled-for-template-deployment true

لإنشاء خزنة مفاتيح جديدة وإضافة سر، استخدم:

az group create --name ExampleGroup --location centralus
az keyvault create \
  --name ExampleVault \
  --resource-group ExampleGroup \
  --location centralus \
  --enabled-for-template-deployment true
az keyvault secret set --vault-name ExampleVault --name "ExamplePassword" --value "hVFkk965BuUv"

بصفتك مالك خزينة المفاتيح، يمكنك الوصول تلقائياً لإنشاء أسرار. إذا كنت تريد السماح لمستخدم آخر بإنشاء أسرار، فاستخدم:

az keyvault set-policy \
  --upn <user-principal-name> \
  --name ExampleVault \
  --secret-permissions set delete get list

لن تكون نُهج الوصول ضرورية إذا كان المستخدم ينشر نموذجاً يسترد سرًّا. أضف مستخدماً إلى نُهج الوصول فقط إذا احتاج المستخدم للعمل مباشرةً مع الأسرار. يتم تحديد أذونات النشر في القسم التالي.

لمزيد من المعلومات حول إنشاء خزائن المفاتيح وإضافة الأسرار، راجع:

منح حق الوصول للنشر للأسرار

يجب أن يكون لدى المستخدم الذي ينشر القالب إذن Microsoft.KeyVault/vaults/deploy/action لنطاق مجموعة الموارد وخزنة المفاتيح. من خلال التحقق من هذا الوصول، يمنع Azure Resource Manager أي مستخدم غير معتمد من الوصول إلى السر عن طريق تمرير معرّف المورد لمخزن المفاتيح. يمكنك منح الوصول إلى النشر للمستخدمين دون منح حق الوصول للكتابة إلى الأسرار.

يمنح كل من دور Owner وContributor هذا الوصول. إذا أنشأت خزينة المفاتيح، فأنت المالك ولديك الإذن.

للمستخدمين الآخرين، امنح الإذن Microsoft.KeyVault/vaults/deploy/action. يوضح الإجراء التالي كيفية إنشاء دور بأدنى حد من الإذن، وتعيينه لمستخدم.

  1. إنشاء ملف JSON لتعريف دور مخصص:

    {
      "Name": "Key Vault resource manager template deployment operator",
      "IsCustom": true,
      "Description": "Lets you deploy a resource manager template with the access to the secrets in the Key Vault.",
      "Actions": [
        "Microsoft.KeyVault/vaults/deploy/action"
      ],
      "NotActions": [],
      "DataActions": [],
      "NotDataActions": [],
      "AssignableScopes": [
        "/subscriptions/00000000-0000-0000-0000-000000000000"
      ]
    }
    

    استبدل "00000000-0000-0000-0000-000000000000" بمعرف الاشتراك.

  2. أنشئ الدور الجديد باستخدام ملف JSON:

    az role definition create --role-definition "<path-to-role-file>"
    az role assignment create \
      --role "Key Vault resource manager template deployment operator" \
      --scope /subscriptions/<Subscription-id>/resourceGroups/<resource-group-name> \
      --assignee <user-principal-name> \
      --resource-group ExampleGroup
    

    تقوم العينات بتعيين الدور المخصص للمستخدم على مستوى مجموعة الموارد.

عند استخدام خزنة مفاتيح مع نموذج لـ Managed Application، يجب منح حق الوصول إلى مدير خدمة Appliance Resource Provider. لمزيد من المعلومات، راجع الوصول إلى سر Key Vault عند نشر تطبيقات Azure المُدارة.

أسرار مرجعية بمعرّف ثابت

باستخدام هذا الأسلوب، يمكنك الرجوع إلى مخزن المفاتيح في ملف المعلمة، وليس النموذج. توضح الصورة التالية كيف يشير ملف المعلمة إلى السر ويمرر تلك القيمة إلى القالب.

رسم تخطيطي يوضح تكامل مخزن المفاتيح Resource Manager مع المعرف الثابت.

البرنامج التعليمي: دمج Azure Key Vault في نشر قالب إدارة الموارد يستخدم هذه الطريقة.

يقوم القالب التالي بنشر خادم SQL يتضمن كلمة مرور المسؤول. تم تعيين مَعلمة كلمة المرور على سلسلة آمنة. لكن النموذج لا يحدد مصدر هذه القيمة.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "sqlServerName": {
      "type": "string"
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    },
    "adminLogin": {
      "type": "string"
    },
    "adminPassword": {
      "type": "securestring"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Sql/servers",
      "apiVersion": "2021-11-01",
      "name": "[parameters('sqlServerName')]",
      "location": "[parameters('location')]",
      "properties": {
        "administratorLogin": "[parameters('adminLogin')]",
        "administratorLoginPassword": "[parameters('adminPassword')]",
        "version": "12.0"
      }
    }
  ]
}

الآن، قم بإنشاء ملف معلمة للقالب السابق. في ملف المعلمة، حدد معلمة تطابق اسم المعلمة في القالب. لقيمة المعلمة، قم بالإشارة إلى السر من خزنة المفاتيح. تشير إلى السر عن طريق تمرير معرّف المورد لخزنة المفاتيح واسم السر:

في ملف المعلمة التالي، يجب أن يكون سر مخزن المفاتيح موجوداً بالفعل، وأنك توفر قيمة ثابتة لمعرف المورد الخاص به.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminLogin": {
      "value": "exampleadmin"
    },
    "adminPassword": {
      "reference": {
        "keyVault": {
          "id": "/subscriptions/<subscription-id>/resourceGroups/<rg-name>/providers/Microsoft.KeyVault/vaults/<vault-name>"
        },
        "secretName": "ExamplePassword"
      }
    },
    "sqlServerName": {
      "value": "<your-server-name>"
    }
  }
}

إذا كنت بحاجة إلى استخدام إصدار من السر بخلاف الإصدار الحالي، فقم بتضمين الخاصية secretVersion.

"secretName": "ExamplePassword",
"secretVersion": "cd91b2b7e10e492ebb870a6ee0591b68"

انشر القالب وقم بتمرير ملف المعلمة:

az group create --name SqlGroup --location westus2
az deployment group create \
  --resource-group SqlGroup \
  --template-uri <template-file-URI> \
  --parameters <parameter-file>

أسرار مرجعية بمعرف ديناميكي

أظهر القسم السابق كيفية تمرير معرّف مورد ثابت لسر خزنة المفاتيح من المعلمة. في بعض السيناريوهات، تحتاج إلى الإشارة إلى سر مخزن مفاتيح يختلف بناءً على النشر الحالي. أو قد ترغب في تمرير قيم المعلمات إلى القالب بدلاً من إنشاء معلمة مرجعية في ملف المعلمة. يتمثل الحل في إنشاء معرف المورد ديناميكياً لسر مخزن المفاتيح باستخدام نموذج مرتبط.

لا يمكنك إنشاء معرف المورد ديناميكياً في ملف المعلمات لأن تعبيرات القوالب غير مسموح بها في ملف المعلمات.

في القالب الأصلي، يمكنك إضافة القالب المتداخل وتمرير معلمة تحتوي على معرف المورد الذي تم إنشاؤه ديناميكياً. توضح الصورة التالية كيف تشير معلمة في القالب المرتبط إلى السر.

رسم تخطيطي يوضح إنشاء المعرف الديناميكي للبيانات السرية لمخزن المفاتيح.

يُنشئ النموذج التالي معرّف مخزن المفاتيح ديناميكياً ويمرره كمعامل.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
      "location": {
        "type": "string",
        "defaultValue": "[resourceGroup().location]",
        "metadata": {
          "description": "The location where the resources will be deployed."
        }
      },
      "vaultName": {
        "type": "string",
        "metadata": {
          "description": "The name of the keyvault that contains the secret."
        }
      },
      "secretName": {
        "type": "string",
        "metadata": {
          "description": "The name of the secret."
        }
      },
      "vaultResourceGroupName": {
        "type": "string",
        "metadata": {
          "description": "The name of the resource group that contains the keyvault."
        }
      },
      "vaultSubscription": {
        "type": "string",
        "defaultValue": "[subscription().subscriptionId]",
        "metadata": {
          "description": "The name of the subscription that contains the keyvault."
        }
      }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-10-01",
      "name": "dynamicSecret",
      "properties": {
        "mode": "Incremental",
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "adminLogin": {
              "type": "string"
            },
            "adminPassword": {
              "type": "securestring"
            },
            "location": {
              "type": "string"
            }
          },
          "variables": {
            "sqlServerName": "[concat('sql-', uniqueString(resourceGroup().id, 'sql'))]"
          },
          "resources": [
            {
              "type": "Microsoft.Sql/servers",
              "apiVersion": "2021-11-01",
              "name": "[variables('sqlServerName')]",
              "location": "[parameters('location')]",
              "properties": {
                "administratorLogin": "[parameters('adminLogin')]",
                "administratorLoginPassword": "[parameters('adminPassword')]"
              }
            }
          ],
          "outputs": {
            "sqlFQDN": {
              "type": "string",
              "value": "[reference(variables('sqlServerName')).fullyQualifiedDomainName]"
            }
          }
        },
        "parameters": {
          "location": {
            "value": "[parameters('location')]"
          },
          "adminLogin": {
            "value": "ghuser"
          },
          "adminPassword": {
            "reference": {
              "keyVault": {
                "id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
              },
              "secretName": "[parameters('secretName')]"
            }
          }
        }
      }
    }
  ]
}

الخطوات التالية