mTLS 통과 수신기를 사용하여 Azure Application Gateway 배포

이 빠른 시작에서는 Azure Resource Manager(ARM) 템플릿과 API 버전 2025-03-01을 사용해 Azure Application Gateway에 상호 TLS(mTLS) 패스스루 를 배포하는 방법을 보여줍니다. 통과 모드에서 게이트웨이는 클라이언트 인증서를 요청하지만 유효성을 검사하지는 않습니다. 인증서 유효성 검사 및 정책 적용은 백 엔드에서 발생합니다.

주요 기능

  • mTLS 통과에 대한 수신기와 SSL 프로필을 연결합니다.
  • 게이트웨이에는 클라이언트 CA 인증서가 필요하지 않습니다.
  • verifyClientAuthMode 속성은 StrictPassthrough 값을 지원합니다.
  • 포털 지원: Azure 포털에서 직접 mTLS 패스스루를 구성할 수 있습니다.

비고

통과 구성에 대한 PowerShell 및 CLI 지원은 현재 사용할 수 없습니다. Azure 포털 또는 ARM 템플릿을 사용하여 mTLS 통과를 구성할 수 있습니다.

Azure 포털을 사용하여 mTLS 패스스루 구성

Azure 포털에서 Passthrough 클라이언트 인증 방법으로 SSL 프로필을 만들어 mTLS 통과를 직접 구성할 수 있습니다.

  1. Azure 포털에서 Application Gateway 리소스로 이동합니다.

  2. 설정에서 SSL 프로필을 선택합니다.

  3. + 추가를 선택하여 새 SSL 프로필을 만듭니다.

  4. SSL 프로필의 이름을 입력합니다.

  5. 클라이언트 인증 탭에서 통과를 선택합니다.

    통과 모드에서 클라이언트 인증서는 선택 사항이며 백 엔드 서버는 클라이언트 인증을 담당합니다.

 클라이언트 인증 방법에 대해 통과가 선택된 Azure 포털의 SSL 프로필 만들기 대화 상자를 보여 주는 스크린샷.

  1. 필요에 따라 SSL 정책 설정을 구성합니다.
  2. 추가를 선택하여 SSL 프로필을 만듭니다.
  3. SSL 프로필을 HTTPS 수신기와 연결합니다.

필수 조건

  • Azure 구독 및 리소스 그룹입니다.
  • Azure CLI 로컬로 설치됩니다.
  • SSL 인증서(Base64로 인코딩된 PFX) 및 암호입니다.
  • Linux VM 관리자용 SSH 키입니다(해당하는 경우).
  • 패스스루 속성에 대한 API 버전 2025-03-01 이상 사용.

mTLS 통과 수신기를 사용하여 Application Gateway 배포

이 템플릿은 다음과 같은 리소스를 만듭니다.

  • 두 개의 서브넷이 있는 가상 네트워크(하나는 Application Gateway에 위임됨)입니다.
  • 게이트웨이 프런트 엔드의 공용 IP 주소입니다.
  • 다음과 같은 Application Gateway(Standard_v2):
    • 클라이언트 인증서 통과에 대한 SSL 인증서 및 SSL 프로필입니다.
    • HTTPS 수신기 및 라우팅 규칙입니다.
    • 앱 서비스를 가리키는 백 엔드 풀입니다.

구성 세부 정보로 템플릿을 업데이트하고 유효한 SSL 인증서를 포함합니다.

매개 변수 파일: deploymentParameters.json

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "addressPrefix": {
            "value": "10.0.0.0/16"
        },
        "subnetPrefix": {
            "value": "10.0.0.0/24"
        },
        "skuName": {
            "value": "Standard_v2"
        },
        "capacity": {
            "value": 2
        },
        "adminUsername": {
            "value": "ubuntu"
        },
        "adminSSHKey": {
            "value": "<your-ssh-public-key>"
        },
        "certData": {
            "value": "<Base64-encoded-PFX-data>"
        },
        "certPassword": {
            "value": "<certificate-password>"
        }
    }
}

템플릿 파일: deploymentTemplate.json

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "addressPrefix": {
            "defaultValue": "10.0.0.0/16",
            "type": "String",
            "metadata": {
                "description": "Address prefix for the Virtual Network"
            }
        },
        "subnetPrefix": {
            "defaultValue": "10.0.0.0/24",
            "type": "String",
            "metadata": {
                "description": "Subnet prefix"
            }
        },
        "skuName": {
            "defaultValue": "Standard_Medium",
            "type": "String",
            "metadata": {
                "description": "Sku Name"
            }
        },
        "capacity": {
            "defaultValue": 2,
            "type": "Int",
            "metadata": {
                "description": "Number of instances"
            }
        },
        "adminUsername": {
            "type": "String"
        },
		"adminSSHKey": {
            "type": "securestring"
        },
        "certData": {
            "type": "String",
            "metadata": {
                "description": "ssl cert data"
            }
        },
        "certPassword": {
            "type": "SecureString",
            "metadata": {
                "description": "ssl cert password"
            }
        }
    },
    "variables": {
        "applicationGatewayName": "mtlsAppGw",
        "idName": "identity",
        "publicIPAddressName": "mtlsPip",
        "virtualNetworkName": "mtlsVnet",
        "subnetName": "appgwsubnet",
        "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
        "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
        "publicIPRef": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]",
        "applicationGatewayID": "[resourceId('Microsoft.Network/applicationGateways',variables('applicationGatewayName'))]",
        "apiVersion": "2025-03-01",
        "identityID": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities',variables('idName'))]",
        "backendSubnetId": "[concat(variables('vnetID'),'/subnets/backendsubnet')]"
    },
    "resources": [
        {
            "type": "Microsoft.Network/virtualNetworks",
            "name": "[variables('virtualNetworkName')]",
            "apiVersion": "2024-07-01",
            "location": "[resourceGroup().location]",
            "properties": {
                "addressSpace": {
                    "addressPrefixes": [
                        "[parameters('addressPrefix')]"
                    ]
                },
                "subnets": [
                    {
                        "name": "[variables('subnetName')]",
                        "properties": {
                            "addressPrefix": "[parameters('subnetPrefix')]",
                             "delegations": [
                                {
                                    "name": "Microsoft.Network/applicationGateways",
                                    "properties": {
                                        "serviceName": "Microsoft.Network/applicationGateways"
                                    }
                                }
                            ]
                        }
                    },
                    {
                        "name": "backendSubnet",
                        "properties": {
                            "addressPrefix": "10.0.2.0/24"
                        }
                    }
                ]
            }
        },
        {
            "type": "Microsoft.Network/publicIPAddresses",
            "sku": {
                "name": "Standard"
            },
            "name": "[variables('publicIPAddressName')]",
            "apiVersion": "2024-07-01",
            "location": "[resourceGroup().location]",
            "properties": {
                "publicIPAllocationMethod": "Static"
            }
        },
        {
            "type": "Microsoft.Network/applicationGateways",
            "name": "[variables('applicationGatewayName')]",
            "apiVersion": "[variables('apiVersion')]",
            "location": "[resourceGroup().location]",
            "properties": {
                "sku": {
                    "name": "Standard_v2",
                    "tier": "Standard_v2",
                    "capacity": 3
                },
                "sslCertificates": [
                    {
                        "name": "sslCert",
                        "properties": {
                            "data": "[parameters('certData')]",
                            "password": "[parameters('certPassword')]"
                        }
                    }
                ],
                "sslPolicy": {
                    "policyType": "Predefined",
                    "policyName": "AppGwSslPolicy20220101"
                },
                "sslProfiles": [
                    {
                        "name": "sslnotrustedcert",
                        "id": "[concat(resourceId('Microsoft.Network/applicationGateways',  variables('applicationGatewayName')), '/sslProfiles/sslnotrustedcert')]",
                        "properties": {
                            "clientAuthConfiguration": {
                                "VerifyClientCertIssuerDN": false,
                                "VerifyClientRevocation": "None",
                                "VerifyClientAuthMode": "Passthrough"
                            }
                        }
                    }                   
                ],
                "gatewayIPConfigurations": [
                    {
                        "name": "appGatewayIpConfig",
                        "properties": {
                            "subnet": {
                                "id": "[variables('subnetRef')]"
                            }
                        }
                    }
                ],
                "frontendIPConfigurations": [
                    {
                        "name": "appGatewayFrontendIP",
                        "properties": {
                            "PublicIPAddress": {
                                "id": "[variables('publicIPRef')]"
                            }
                        }
                    }
                ],
                "frontendPorts": [
                    {
                        "name": "port2",
                        "properties": {
                            "Port": 444
                        }
                    }
                ],
                "backendAddressPools": [
                    {
                        "name": "pool2",
                        "properties": {
                            "BackendAddresses": [
							  {
                                "fqdn": "headerappgw-hsa5gjh8fpfebcfd.westus-01.azurewebsites.net"
                              }
							]
                        }
                    }
                ],
                "backendHttpSettingsCollection": [
                    {
                        "name": "settings2",
                        "properties": {
                            "Port": 80,
                            "Protocol": "Http"
                        }
                    }
                ],
                "httpListeners": [
                    {
                        "name": "listener2",
                        "properties": {
                            "FrontendIPConfiguration": {
                                "Id": "[concat(variables('applicationGatewayID'), '/frontendIPConfigurations/appGatewayFrontendIP')]"
                            },
                            "FrontendPort": {
                                "Id": "[concat(variables('applicationGatewayID'), '/frontendPorts/port2')]"
                            },
                            "Protocol": "Https",
                            "SslCertificate": {
                                "Id": "[concat(variables('applicationGatewayID'), '/sslCertificates/sslCert')]"
                            },
                            "sslProfile": {
                                "id": "[concat(variables('applicationGatewayID'), '/sslProfiles/sslnotrustedcert')]"
                            }
                        }
                    }
                ],
                "requestRoutingRules": [
                    {
                        "Name": "rule2",
                        "properties": {
                            "RuleType": "Basic",
                            "priority": 2000,
                            "httpListener": {
                                "id": "[concat(variables('applicationGatewayID'), '/httpListeners/listener2')]"
                            },
                            "backendAddressPool": {
                                "id": "[concat(variables('applicationGatewayID'), '/backendAddressPools/pool2')]"
                            },
                            "backendHttpSettings": {
                                "id": "[concat(variables('applicationGatewayID'), '/backendHttpSettingsCollection/settings2')]"
                            }
                        }
                    }
                ]
            },
            "dependsOn": [
                "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
                "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
            ]
        }
    ]
}

템플릿 배포

다음 Azure CLI 명령을 실행하여 템플릿을 배포합니다.

az deployment group create \
  --resource-group <your-resource-group> \
  --template-file deploymentTemplate.json \
  --parameters @deploymentParameters.json

유효성 검사 및 테스트

배포 유효성 검사

  1. Azure Portal에서 Application Gateway 리소스로 이동합니다.

  2. JSON 보기를 선택하고 API 버전을 2025-03-01선택합니다.

  3. SSL 프로필에서 verifyClientAuthModePassthrough로 설정되어 있는지 확인합니다.

    "sslProfiles": [
        {
            "name": "sslnotrustedcert",
            "id": "<sample-subscription-id>",
            "etag": "W/\"851e4e20-d2b1-4338-9135-e0beac11aa0e\"",
            "properties": {
                "provisioningState": "Succeeded",
                "clientAuthConfiguration": {
                    "verifyClientCertIssuerDN": false,
                    "verifyClientRevocation": "None",
                    "verifyClientAuthMode": "Passthrough"
                },
                "httpListeners": [
                    {
                        "id": "<sample-subscription-id>"
                    }
                ]
            }
        }
    ]
    

백 엔드에 클라이언트 인증서 보내기

클라이언트 인증서를 백 엔드로 전달해야 하는 경우 다시 쓰기 규칙을 구성합니다. 자세한 내용은 Application Gateway를 사용하여 HTTP 헤더 및 URL 다시 쓰기를 참조하세요.

클라이언트가 인증서를 보내면 이 다시 쓰기를 통해 백 엔드 처리를 위해 클라이언트 인증서가 요청 헤더에 포함됩니다.

연결 테스트

클라이언트 인증서가 제공되지 않은 경우에도 연결이 설정되는지 확인합니다.

mTLS 통과 매개 변수

다음 표에서는 mTLS 통과 구성에 대한 매개 변수를 설명합니다.

이름 유형 Description
verifyClientCertIssuerDN Boolean 게이트웨이에서 클라이언트 인증서 발급자 이름을 확인할지 여부를 지정합니다.
verifyClientRevocation String 클라이언트 인증서 해지 확인 모드를 지정합니다.
verifyClientAuthMode String 클라이언트 인증서 모드를 지정합니다. 유효한 값은 StrictPassthrough입니다.

통과 모드: 게이트웨이는 클라이언트 인증서를 요청하지만 적용하지는 않습니다. 백 엔드는 인증서의 유효성을 검사하고 정책을 적용합니다.

보안 고려 사항

이 솔루션을 배포하고 관리할 때 조직의 보안 및 데이터 처리 모범 사례를 따릅니다.