Azure’s Private Link enables you to securely access Azure PaaS and Partner resources over a private endpoint (PE) in your own virtual network (VNET). The private access is resource specific as opposed to service specific and protects against data exfiltration in that connectivity can be initiated in only a single direction.
In addition to being able to connect to PaaS resources, you can also securely connect to Azure Virtual Machines (IaaS) that are fronted by a Standard Internal Load Balancer as shown in the figure below: The Private Link Service (PLS) as shown in the Provider Network performs Destination NAT which prevents IP overlapping issues between the Consumer and Provider VNETs in Azure. From the perspective of the Provider Network, the source IP is going to be the NAT-ted IP (192.168.0.5 from the figure above). The Provider can determine the original source of the connection by looking at the TCP Proxy V2 header. Details for this is outside the scope of this article but more information on how one can get the source IP can be found here.
If you want to connect from a private/managed subnet to an on-premise server or a server in another VNET as shown in the figure below which shows connectivity from Azure Data Factory (ADF) Managed Virtual Network to an on-premise SQL Server
This highlighted elements in the diagram below will be implemented in the Forwarding Solution
- Download code from this repository locally:
git clone https://github.com/sajitsasi/adf-pipeline.git cd adf-pipeline
- Get the IP and Port of the Destination host to which you want traffic
forwarded to. For example, you have an SQL server installed with
IP 10.100.3.4, then the values would be:
DEST_IP="10.100.3.4" DEST_PORT="1433"
- Resource Group:
az-adf-fwd-rg
- Azure Region:
East US
- Forwarding VNET Name:
az-adf-fwd-vnet
- Forwarding VNET Address Space:
10.100.0.0/20
- Subnets in Forwarding VNET:
- Name:
adf-fwd-fe-subnet
Address Space:10.100.0.0/24
- Name:
adf-fwd-be-subnet
Address Space:10.100.1.0/24
- Name:
adf-fwd-pls-subnet
Address Space:10.100.2.0/24
- Name:
adf-fwd-vm-subnet
Address Space:10.100.3.0/24
- Name:
adf-fwd-bast-subnet
Address Space:10.100.4.0/24
(optional)
- Name:
- NSG for blocking external traffic (optional):
adf-fwd-vm-nsg
- Bastion VM for external access (optional):
bastionvm
- Standard Internal Load Balancer:
ADFFwdILB
- Forwarding VM name:
fwdvm[#]
- Forwarding VM NIC:
fwdvm[#]nic[RANDOM #]
- Backend/Destination server IPs and services:
The following table shows the configuration that will be passed to the
port forwarding VM. The
FE Port
references the port on which the port forwarding VM listens while theBE Port
references the port on which the destination server listens.Server Service FE Port BE Port 10.100.3.4 SQL 1433 1433 10.100.3.4 File Share 445 445
az login
az account list --all
az account set --subscription <subscription_id>
az group create --name az-adf-fwd-rg --location eastus
az network vnet create \
-g az-adf-fwd-rg \
-n az-adf-fwd-vnet \
--address-prefixes 10.100.0.0/20 \
--subnet-name adf-fwd-fe-subnet \
--subnet-prefixes 10.100.0.0/24 \
--location eastus
az network vnet subnet create \
-g az-adf-fwd-rg \
--vnet-name az-adf-fwd-vnet \
-n adf-fwd-be-subnet \
--address-prefix 10.100.1.0/24
az network vnet subnet create \
-g az-adf-fwd-rg \
--vnet-name az-adf-fwd-vnet \
-n adf-fwd-pls-subnet \
--address-prefix 10.100.2.0/24
az network vnet subnet update \
-g az-adf-fwd-rg \
-n pls-subnet \
--vnet-name az-adf-fwd-vnet \
--disable-private-link-service-network-policies true
az network vnet subnet create \
-g az-adf-fwd-rg \
--vnet-name az-adf-fwd-vnet \
-n adf-fwd-vm-subnet \
--address-prefix 10.100.3.0/24
az network vnet subnet create \
-g az-adf-fwd-rg \
--vnet-name az-adf-fwd-vnet \
-n adf-fwd-bast-subnet \
--address-prefix 10.100.4.0/24
az network nsg create -g az--adf-fwd-rg --name adf-fwd-vm-nsg
ALLOWED_IP_ADDRESS="$(curl ifconfig.me)/32"
az network nsg rule create \
-g az-adf-fwd-rg \
--nsg-name adf-fwd-vm-nsg \
--name AllowSSH \
--direction inbound \
--source-address-prefix ${ALLOWED_IP_ADDRESS} \
--destination-port-range 22 \
--access allow \
--priority 500 \
--protocol Tcp
az network vnet subnet update \
-g az-adf-fwd-rg \
-n adf-fwd-bast-subnet \
--vnet-name az-adf-fwd-vnet \
--network-security-group adf-fwd-vm-nsg
az vm create \
-g az-adf-fwd-rg \
--image UbuntuLTS \
--admin-user azureuser \
--generate-ssh-keys \
--vnet-name az-adf-fwd-vnet \
--subnet adf-fwd-bast-subnet
az network lb create \
-g az-adf-fwd-rg \
--name ADFFWDILB \
--sku standard \
--vnet-name az-adf-fwd-vnet \
--subnet adf-fwd-fe-subnet \
--frontend-ip-name FrontEnd \
--backend-pool-name bepool
az network lb probe create \
-g az-adf-fwd-rg \
--lb-name ADFFWDILB \
--name SSHProbe \
--protocol tcp \
--port 22
az network lb rule create \
-g az-adf-fwd-rg \
--lb-name ADFFWDILB \
--name OnPremSQL \
--protocol tcp \
--frontend-port 1433 \
--backend-port 1433 \
--frontend-ip-name FrontEnd \
--backend-pool-name bepool \
--probe-name SSHProbe
az network lb rule create \
-g az-adf-fwd-rg \
--lb-name ADFFWDILB \
--name OnPremSQL \
--protocol tcp \
--frontend-port 445 \
--backend-port 445 \
--frontend-ip-name FrontEnd \
--backend-pool-name bepool \
--probe-name SSHProbe
FWD_ILB=$(az network lb show -g az-adf-fwd-rg -n ADFFWDILB --query frontendIpConfigurations[0].id -o tsv)
PLS_ID=$(
az network private-link-service create \
-g az-adf-fwd-rg \
-n pls2fwdilb \
--vnet-name az-adf-fwd-vnet \
--subnet adf-fwd-pls-subnet \
--lb-frontend-ip-configs ${FWD_ILB} \
-l eastus \
--query id \
-o tsv)
NIC1_NAME=fwdvm1nic${RANDOM}
az network nic create \
-g az-adf-fwd-rg \
-n ${NIC_NAME} \
--vnet-name az-adf-fwd-vnet \
--subnet adf-fwd-be-subnet
Note: Make sure you're running this from where the cloud_init.yaml file exists
az vm create \
-g az-adf-fwd-rg \
--name natvm1 \
--image UbuntuLTS \
--admin-user azureuser \
--generate-ssh-keys \
--nics ${NIC1_NAME} \
--public-ip-address "" \
--custom-data ./cloud_init.yaml
az network nic ip-config address-pool add \
--address-pool bepool \
--ip-config-name ipconfig1 \
--nic-name ${NIC1_NAME} \
-g az-adf-fwd-rg \
--lb-name ADFFWDILB
These are variables to use when wanting to connect to the PLS, or the Bastion VM
echo "PLS Resource ID is ${PLS_ID}"
echo "Bastion Public IP is: $(az vm show -d -g az-adf-fwd-rg -n bastionvm --query publicIps -o tsv)"
Follow instructions in this link to install a SQL Server VM. Note:
- Get the Private IP address of the VM
- Verify that it is accessible from the Forwarding VM created above
- In our example, the SQL Server has Private IP
10.100.3.4
Run command on remote FWD VM to create forwarding rule to destination IP
and port ($DEST_IP
and $DEST_PORT
from Prerequisites).
az vm run-command invoke --command-id RunShellScript -g az-adf-fwd-rg -n fwdvm1 --scripts "/usr/local/bin/ip_fwd.sh -i eth0 -f 1433 -a 10.100.3.4 -b 1433"
az vm run-command invoke --command-id RunShellScript -g az-adf-fwd-rg -n fwdvm1 --scripts "/usr/local/bin/ip_fwd.sh -i eth0 -f 445 -a 10.100.3.4 -b 445"
This will setup connectivity from ADF to the Private Link Service created in the Azure subscription
1. Go to the Azure Portal
-
Fill in the appropriate information in the Basics tab
-
Choose "Configure Git Later" in the Git Configuration tab as shown below:
-
Choose "Enable Managed Virtual Network on the default AutoResolveIntengrationRuntime" in the Networking tab as shown below:
-
Click on "Review + Create" and then click on "Create" when done
4. Now go to Azure ADF
5. Choose your AAD, Subscription, and enter your Data Factory Name that you just created and click on Continue
When entering the Fully Qualified Domain Names (FQDN), understand that the values need to be entered for ALL services you want ADF to access. The FQDN is local to the ADF VNET and doesn't need to match any actual FQDN that you might have assigned to your servers. The different FQDNs of the multiple servers all translate to a single Private Endpoint IP in the local ADF VNET which is connected to the PLS created earlier. Click on "Create" once everything is entered.