如何为 Azure Spring Apps 配置 Palo Alto

备注

基本、标准和企业计划将从 2025 年 3 月中旬开始弃用,停用期为 3 年。 建议转换到 Azure 容器应用。 有关详细信息,请参阅 Azure Spring Apps 停用公告

标准消耗和专用计划将于 2024 年 9 月 30 日开始弃用,并在六个月后完全关闭。 建议转换到 Azure 容器应用。

本文介绍如何将 Azure Spring Apps 与 Palo Alto 防火墙一起使用。

如果你的当前部署包含 Palo Alto 防火墙,则可以在 Azure Spring Apps 部署中省略 Azure 防火墙,并改为使用 Palo Alto,如本文中所述。

应将配置信息(如规则和地址通配符)保存在 Git 存储库的 CSV 文件中。 本文介绍如何使用自动化将这些文件应用于 Palo Alto。 若要了解要应用于 Palo Alto 的配置,请参阅在虚拟网络中运行 Azure Spring Apps 的客户责任

备注

在描述 REST API 的使用时,本文使用 PowerShell 变量语法来指示由你自行决定的名称和值。 请确保在所有步骤中使用相同的值。

在 Palo Alto 中配置 TLS/SSL 证书后,请根据以下示例中的所有 Palo Alto REST API 调用删除 -SkipCertificateCheck 参数。

不应将本文用作 Palo Alto REST API 的引用。 所有示例仅用于演示目的。 有关权威的 API 详细信息,请参阅 Palo Alto 文档中的 PAN-OS REST API

先决条件

配置 Palo Alto

首先,配置 Palo Alto VM 系列防火墙。 有关详细说明,请参阅部署来自 Azure 市场的 VM 系列防火墙(解决方案模板)。 这些说明将帮助你预配 VM 系列防火墙,并同时配置 TrustUnTrust 子网以及关联的网络接口卡。 要保持一致,应在引用体系结构中 Hub 虚拟网络的地址空间中创建此防火墙。

Azure 引用体系结构指南探讨了适用于在 Azure 上部署防火墙的几个技术设计模型。

本文的其余部分假定你具有以下两个预配置的网络区域:

  • Trust,包含连接到与 Azure Spring Apps 虚拟网络对等互连的虚拟网络的接口。
  • UnTrust,包含之前在 VM 系列部署指南中创建的公用 Internet 的接口。

准备 CSV 文件

接下来,创建三个 CSV 文件。

将第一个文件命名为 AzureSpringAppsServices.csv。 此文件应包含 Azure Spring Apps 的入口端口。 以下示例中的值仅用于演示目的。 有关所需的所有值,请参阅在虚拟网络中运行 Azure Spring Apps 的客户责任Azure 全球的必需网络规则部分。

name,protocol,port,tag
ASC_1194,udp,1194,AzureSpringApps
ASC_443,tcp,443,AzureSpringApps
ASC_9000,tcp,9000,AzureSpringApps
ASC_445,tcp,445,AzureSpringApps
ASC_123,udp,123,AzureSpringApps

将第二个文件命名为 AzureSpringAppsUrlCategories.csv。 此文件应包含应可用于来自 Azure Spring Apps 的出口的地址(有通配符)。 以下示例中的值仅用于演示目的。 有关最新值,请参阅在虚拟网络中运行 Azure Spring Apps 的客户责任Azure 全球的必需 FQDN/应用程序规则

name,description
*.azmk8s.io,
mcr.microsoft.com,
*.cdn.mscr.io,
*.data.mcr.microsoft.com,
management.chinacloudapi.cn,
*.partner.microsoftonline.cn,
*.microsoft.com,
packages.microsoft.com,
acs-mirror.azureedge.net,
mscrl.microsoft.com,
crl.microsoft.com,
crl3.digicert.com

将第三个文件命名为 AzureMonitorAddresses.csv。 如果使用的是 Azure Monitor,此文件应包含所有可用于指标和通过 Azure Monitor 进行监视的地址和 IP 范围。 以下示例中的值仅用于演示目的。 有关最新值,请参阅 Azure Monitor 使用的 IP 地址

name,type,address,tag
40.114.241.141,ip-netmask,40.114.241.141/32,AzureMonitor
104.45.136.42,ip-netmask,104.45.136.42/32,AzureMonitor
40.84.189.107,ip-netmask,40.84.189.107/32,AzureMonitor
168.63.242.221,ip-netmask,168.63.242.221/32,AzureMonitor
52.167.221.184,ip-netmask,52.167.221.184/32,AzureMonitor
live.applicationinsights.azure.com,fqdn,live.applicationinsights.azure.com,AzureMonitor
rt.applicationinsights.microsoft.com,fqdn,rt.applicationinsights.microsoft.com,AzureMonitor
rt.services.visualstudio.com,fqdn,rt.services.visualstudio.com,AzureMonitor

在 Palo Alto 中进行身份验证

接下来,需要在 Palo Alto 中进行身份验证并获取 API 密钥。 有关详细信息,请参阅 Palo Alto 文档中的获取 API 密钥

以下示例使用 PowerShell 进行身份验证并生成将在本文稍后使用的请求头:

$username=<username for PaloAlto>
$password=<password for PaloAlto>
$authResponse = irm "https://${PaloAltoIpAddress}/api/?type=keygen&user=${username}&password=${password}" -SkipCertificateCheck
$paloAltoHeaders = @{'X-PAN-KEY' = $authResponse.response.result.key; 'Content-Type' = 'application/json' }

删除现有服务组

如果之前尝试过配置,应重置这些配置并删除任何安全规则和服务组。

使用安全规则 REST API 删除安全规则,如下例所示:

$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Policies/SecurityRules?location=vsys&vsys=vsys1&name=${paloAltoSecurityPolicyName}"
Invoke-RestMethod -Method Delete -Uri $url -Headers $paloAltoHeaders -SkipCertificateCheck

删除服务组,如下例所示:

$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/ServiceGroups?location=vsys&vsys=vsys1&name=${paloAltoServiceGroupName}"
Invoke-RestMethod -Method Delete -Uri $url -Headers $paloAltoHeaders -SkipCertificateCheck

删除(在 AzureSpringAppsServices.csv 中定义的)各个 Palo Alto 服务,如下例所示:

Get-Content .\AzureSpringAppsServices.csv | ConvertFrom-Csv | select name | ForEach-Object {
    $url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/Services?location=vsys&vsys=vsys1&name=${_}"
    Invoke-RestMethod -Method Delete -Uri $url -Headers $paloAltoHeaders -SkipCertificateCheck
}

创建服务和服务组

若要根据之前创建的 AzureSpringAppsServices.csv 文件自动创建服务,请使用以下示例。

# Define a function to create and submit a Palo Alto service creation request
function New-PaloAltoService {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSCustomObject]
        $ServiceObject
    )
    PROCESS {
        $requestBody = @{
            'entry' = @{
                '@name'    = $ServiceObject.name
                'protocol' = @{
                    $ServiceObject.protocol = @{
                        'port'     = $ServiceObject.port
                        'override' = @{
                            'no' = @{}
                        }

                    }
                }
                'tag'      = @{
                    'member' = @($ServiceObject.tag)
                }
            }
        }

        # Some rules in the CSV may need to conain source ports or descriptions. If these are present, populate them in the request
        if ($ServiceObject.description) {
            $requestBody.entry.description = $ServiceObject.description
        }
        if ($ServiceObject.'source-port') {
            $requestBody.entry.protocol."$($ServiceObject.protocol)".'source-port' = $ServiceObject.'source-port'
        }

        # Send the request
        $name = $requestBody.entry.'@name'
        $url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/Services?location=vsys&vsys=vsys1&name=${name}"
         Invoke-RestMethod -Method Post -Uri $url  -SkipCertificateCheck -Headers $paloAltoHeaders -Body (ConvertTo-Json -WarningAction Ignore $requestBody -Depth 9) -Verbose
    }
}

# Now invoke that function for every row in AzureSpringAppsServices.csv
Get-Content ./AzureSpringAppsServices.csv | ConvertFrom-Csv | New-PaloAltoService

接下来,为这些服务创建服务组,如下例所示:

# Create a function to consume service definitions and submit a service group creation request
function New-PaloAltoServiceGroup {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSCustomObject[]]
        $RuleData,

        [Parameter(Mandatory = $true)]
        [string]
        $ServiceGroupName
    )
    begin {
        [array] $names = @()
    }

    process {
        $names += $RuleData.name
    }

    end {
        $requestBody = @{ 'entry' = [ordered] @{
                '@name'   = $ServiceGroupName
                'members' = @{ 'member' = $names }
                'tag'     = @{ 'member' = 'AzureSpringApps' }
            }
        }

        $url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/ServiceGroups?location=vsys&vsys=vsys1&name=${ServiceGroupName}"

        Invoke-RestMethod -Method Post -Uri $url  -SkipCertificateCheck -Headers $paloAltoHeaders -Body (ConvertTo-Json $requestBody) -Verbose
    }
}

# Run that function for all services in AzureSpringAppsServices.csv.
Get-Content ./AzureSpringAppsServices.csv | ConvertFrom-Csv | New-PaloAltoServiceGroup -ServiceGroupName 'AzureSpringApps_SG'

创建自定义 URL 类别

接下来,为服务组定义自定义 URL 类别以启用来自 Azure Spring Apps 的出口,如下例所示。

# Read Service entries from CSV to enter into Palo Alto
$csvImport = Get-Content ${PSScriptRoot}/AzureSpringAppsUrls.csv | ConvertFrom-Csv

# Convert name column of CSV to add to the Custom URL Group in Palo Alto
$requestBody = @{ 'entry' = [ordered] @{
        '@name' = 'AzureSpringApps_SG'
        'list'  = @{ 'member' = $csvImport.name }
        'type'  = 'URL List'
    }
} | ConvertTo-Json -Depth 9

$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/CustomURLCategories?location=vsys&vsys=vsys1&name=AzureSpringApps_SG"

try {
    $existingObject = Invoke-RestMethod -Method Get -Uri $url  -SkipCertificateCheck -Headers $paloAltoHeaders
    Invoke-RestMethod -Method Delete -Uri $url  -SkipCertificateCheck -Headers $paloAltoHeaders
}
catch {
}

Invoke-RestMethod -Method Post -Uri $url  -SkipCertificateCheck -Headers $paloAltoHeaders -Body $requestBody -Verbose

创建安全规则

接下来,创建一个 JSON 文件,以包含安全规则。 将文件命名为 SecurityRule.json 并添加以下内容。 TrustUnTrust 两个区域的名称与之前在配置 Palo Alto 部分中描述的区域名称相匹配。 service/member 条目包含在前面步骤中创建的服务组的名称。

{
    "entry": [
        {
            "@name": "AzureSpringAppsRule",
            "@location": "vsys",
            "@vsys": "vsys1",
            "to": {
                "member": [
                    "UnTrust"
                ]
            },
            "from": {
                "member": [
                    "Trust"
                ]
            },
            "source-user": {
                "member": [
                    "any"
                ]
            },
            "application": {
                "member": [
                    "any"
                ]
            },
            "service": {
                "member": [
                    "AzureSpringApps_SG"
                ]
            },
            "hip-profiles": {
                "member": [
                    "any"
                ]
            },
            "action": "allow",
            "category": {
                "member": [
                    "any"
                ]
            },
            "source": {
                "member": [
                    "any"
                ]
            },
            "destination": {
                "member": [
                    "any"
                ]
            }
        }
    ]
}

现在,将此规则应用于 Palo Alto,如下例所示。

$url = "https://${PaloAltoIpAddress}/restapi/v9.1/Policies/SecurityRules?location=vsys&vsys=vsys1&name=AzureSpringAppsRule"

# Delete the rule if it already exists
try {
    $getResult = Invoke-RestMethod -Headers $paloAltoHeaders -Method Get -SkipCertificateCheck -Uri $url -Verbose
    if ($getResult.'@status' -eq 'success') {
        Invoke-RestMethod -Method Delete  -Headers $paloAltoHeaders -SkipCertificateCheck -Uri $url
    }
}
catch {}

# Create the rule from the JSON file
Invoke-WebRequest -Uri $url -Method Post -Headers $paloAltoHeaders -Body (Get-Content SecurityRule.json) -SkipCertificateCheck

创建 Azure Monitor 地址

接下来,使用 AzureMonitorAddresses.csv 文件在 Palo Alto 中定义地址对象。 以下示例代码展示了如何自动执行此任务。

Get-Content ./AzureMonitorAddresses.csv | ConvertFrom-Csv | ForEach-Object {
    $requestBody = @{ 'entry' = [ordered]@{
            '@name' = $_.name
            $_.type = $_.address
            'tag'   = @{ 'member' = @($_.tag) }
        }
    }

    $name = $requestBody.entry.'@name'
    $url = "https://${PaloAltoIpAddress}/restapi/v9.1/Objects/Addresses?location=vsys&vsys=vsys1&name=${name}"

    # Delete the address if it already exists
    try {
        Invoke-RestMethod -Method Delete -Uri $url  -SkipCertificateCheck -Headers $paloAltoHeaders
    }
    catch {
    }

    # Create the address
    Invoke-RestMethod -Method Post -Uri $url  -SkipCertificateCheck -Headers $paloAltoHeaders -Body (ConvertTo-Json -WarningAction Ignore $requestBody -Depth 3) -Verbose
}

将更改提交到 Palo Alto

必须提交上述一些更改,以便它们变为活动状态。 可使用以下 REST API 调用执行此操作。

$url = "https://${PaloAltoIpAddress}/api/?type=commit&cmd=<commit></commit>"
Invoke-RestMethod -Method Get -Uri $url  -SkipCertificateCheck -Headers $paloAltoHeaders

为 Azure Spring Apps 子网配置安全规则

接下来,添加网络安全规则以允许来自 Palo Alto 的流量访问 Azure Spring Apps。 以下示例引用由引用体系结构创建的分支网络安全组 (NSG):nsg-spokeappnsg-spokeruntime

在 PowerShell 窗口中运行以下 Azure CLI 命令,为每个 NSG 创建必要的网络安全规则,其中 $PaloAltoAddressPrefix 是 Palo Alto 的专用 IP 的无类别域际路由选择 (CIDR) 地址。

az network nsg rule create `
    --resource-group $ResourceGroupName `
    --name 'allow-palo-alto' `
    --nsg-name 'nsg-spokeapp' `
    --access Allow `
    --source-address-prefixes $PaloAltoAddressPrefix `
    --priority 1000
az network nsg rule create `
    --resource-group $ResourceGroupName `
    --name 'allow-palo-alto' `
    --nsg-name 'nsg-spokeruntime' `
    --access Allow `
    --source-address-prefixes $PaloAltoAddressPrefix `
    --priority 1000

配置下一个跃点

配置 Palo Alto 后,请将 Azure Spring Apps 配置为将 Palo Alto 作为其下一个跃点,用于出站 Internet 访问。 可在 PowerShell 窗口中使用以下 Azure CLI 命令来进行此配置。 请确保为以下变量提供值:

  • $AppResourceGroupName:包含 Azure Spring Apps 的资源组的名称。
  • $AzureSpringAppsServiceSubnetRouteTableName:Azure Spring Apps 服务/运行时子网路由表的名称。 在引用体系结构中,这设置为 rt-spokeruntime
  • $AzureSpringAppsAppSubnetRouteTableName:Azure Spring Apps 应用子网路由表的名称。 在引用体系结构中,这设置为 rt-spokeapp
az network route-table route create `
    --resource-group ${AppResourceGroupName} `
    --name default `
    --route-table-name ${AzureSpringAppsServiceSubnetRouteTableName} `
    --address-prefix 0.0.0.0/0 `
    --next-hop-type VirtualAppliance `
    --next-hop-ip-address ${PaloAltoIpAddress} `
    --verbose

az network route-table route create `
    --resource-group ${AppResourceGroupName} `
    --name default `
    --route-table-name ${AzureSpringAppsAppSubnetRouteTableName} `
    --address-prefix 0.0.0.0/0 `
    --next-hop-type VirtualAppliance `
    --next-hop-ip-address ${PaloAltoIpAddress} `
    --verbose

现在配置已完成。

后续步骤