2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Azure Databricks閉域網にVPNでアクセスしてみた

Last updated at Posted at 2023-03-02

システム構成

image.png

概要

DatabricksをVNETインジェクションで構成し、公衆ネットワーク アクセスを許可せずに内部のプライベートエンドポイント経由でVPNを使用してアクセスを行います。

サブネットは、①VPN作成時に必要なGatewaySubnet、②③はDNS Private Resolverに必要なinboundとoutboundに使用、④はdatabricksに必要なプライベートエンドポイントポイントを置くためにあります。

VPNからポイント対サイトで資格証明書を持っているクライアントPCからのみアクセス出来るようにします。

まとめると、特定の証明書をインストールしたPCからVPNを起動するとDatabricksにアクセス出来る手順を以下に記載させて頂きます。

構築

今回画面操作で構築すると時間が掛かるのでBicepでデプロイを行います。
以下に解説の記事を書いています。

Databricksのデプロイ

databricksのARMはMicrosoftが公開しているものがあるので、Bicepにデコンパイルします。

以下デコンパイルして修正したものになります。
ローカル環境でbicepファイルを作成し内容をコピーします。

DatabricksDeploy.bicep
//secure cluster connectivity (SCC) を設定
var  disablePublicIp = true
var  location = 'japaneast'
var  nsgName = 'databricks-nsg'
var  pricingTier = 'premium'
var  privateSubnetCidr = '10.179.0.0/18'
var  privateSubnetName = 'private-subnet'
//公共アクセスを無効化
var  publicNetworkAccess = 'Disabled'
var  publicSubnetCidr = '10.179.64.0/18'
var  privateEndpointSubnetCidr = '10.179.128.0/24'
var  publicSubnetName = 'public-subnet'
var  requiredNsgRules = 'NoAzureDatabricksRules'
var  vnetCidr = '10.179.0.0/16'
var  vnetName = 'databricks-vnet'
var  workspaceName = 'default'
var managedResourceGroupName = 'databricks-rg-${workspaceName}-${uniqueString(workspaceName, resourceGroup().id)}'
var PrivateEndpointSubnetName = 'default'
var private_endpoint_name_ui_api = '${workspaceName}-pvtEndpoint-ui-api'
var private_endpoint_name_browser = '${workspaceName}-pvtEndpoint-broweser'
var privateDnsZoneName = 'privatelink.azuredatabricks.net'

resource nsg 'Microsoft.Network/networkSecurityGroups@2021-03-01' = {
  name: nsgName
  location: location
  properties: {
    securityRules: [
      {
        name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-worker-inbound'
        properties: {
          description: 'Required for worker nodes communication within a cluster.'
          protocol: '*'
          sourcePortRange: '*'
          destinationPortRange: '*'
          sourceAddressPrefix: 'VirtualNetwork'
          destinationAddressPrefix: 'VirtualNetwork'
          access: 'Allow'
          priority: 100
          direction: 'Inbound'
        }
      }
      {
        name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-databricks-webapp'
        properties: {
          description: 'Required for workers communication with Databricks Webapp.'
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '443'
          sourceAddressPrefix: 'VirtualNetwork'
          destinationAddressPrefix: 'AzureDatabricks'
          access: 'Allow'
          priority: 100
          direction: 'Outbound'
        }
      }
      {
        name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-sql'
        properties: {
          description: 'Required for workers communication with Azure SQL services.'
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '3306'
          sourceAddressPrefix: 'VirtualNetwork'
          destinationAddressPrefix: 'Sql'
          access: 'Allow'
          priority: 101
          direction: 'Outbound'
        }
      }
      {
        name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-storage'
        properties: {
          description: 'Required for workers communication with Azure Storage services.'
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '443'
          sourceAddressPrefix: 'VirtualNetwork'
          destinationAddressPrefix: 'Storage'
          access: 'Allow'
          priority: 102
          direction: 'Outbound'
        }
      }
      {
        name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-worker-outbound'
        properties: {
          description: 'Required for worker nodes communication within a cluster.'
          protocol: '*'
          sourcePortRange: '*'
          destinationPortRange: '*'
          sourceAddressPrefix: 'VirtualNetwork'
          destinationAddressPrefix: 'VirtualNetwork'
          access: 'Allow'
          priority: 103
          direction: 'Outbound'
        }
      }
      {
        name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-eventhub'
        properties: {
          description: 'Required for worker communication with Azure Eventhub services.'
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '9093'
          sourceAddressPrefix: 'VirtualNetwork'
          destinationAddressPrefix: 'EventHub'
          access: 'Allow'
          priority: 104
          direction: 'Outbound'
        }
      }
    ]
  }
}

resource vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        vnetCidr
      ]
    }
    subnets: [
      {
        name: publicSubnetName
        properties: {
          addressPrefix: publicSubnetCidr
          networkSecurityGroup: {
            id: nsg.id
          }
          delegations: [
            {
              name: 'databricks-del-public'
              properties: {
                serviceName: 'Microsoft.Databricks/workspaces'
              }
            }
          ]
        }
      }
      {
        name: privateSubnetName
        properties: {
          addressPrefix: privateSubnetCidr
          networkSecurityGroup: {
            id: nsg.id
          }
          delegations: [
            {
              name: 'databricks-del-private'
              properties: {
                serviceName: 'Microsoft.Databricks/workspaces'
              }
            }
          ]
        }
      }
      {
        name: PrivateEndpointSubnetName
        properties: {
          addressPrefix: privateEndpointSubnetCidr
          privateEndpointNetworkPolicies: 'Disabled'
        }
      }
    ]
  }
}

resource workspace 'Microsoft.Databricks/workspaces@2021-04-01-preview' = {
  name: workspaceName
  location: location
  sku: {
    name: pricingTier
  }
  properties: {
    managedResourceGroupId: subscriptionResourceId('Microsoft.Resources/resourceGroups', managedResourceGroupName)
    parameters: {
      customVirtualNetworkId: {
        value: vnet.id
      }
      customPublicSubnetName: {
        value: publicSubnetName
      }
      customPrivateSubnetName: {
        value: privateSubnetName
      }
      enableNoPublicIp: {
        value: disablePublicIp
      }
    }
    publicNetworkAccess: publicNetworkAccess
    requiredNsgRules: requiredNsgRules
  }
}

resource pe_ui 'Microsoft.Network/privateEndpoints@2021-08-01' = {
  name: private_endpoint_name_ui_api
  location: location
  properties: {
    subnet: {
      id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, PrivateEndpointSubnetName)
    }
    privateLinkServiceConnections: [
      {
        name: private_endpoint_name_ui_api
        properties: {
          privateLinkServiceId: '${resourceGroup().id}/providers/Microsoft.Databricks/workspaces/${workspaceName}'
          groupIds: [
            'databricks_ui_api'
          ]
        }
      }
    ]
  }
  dependsOn: [
    workspace
  ] 
}


resource pe_browser 'Microsoft.Network/privateEndpoints@2021-08-01' = {
  name: private_endpoint_name_browser 
  location: location
  properties: {
    subnet: {
      id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, PrivateEndpointSubnetName)
    }
    privateLinkServiceConnections: [
      {
        name: private_endpoint_name_browser 
        properties: {
          privateLinkServiceId: '${resourceGroup().id}/providers/Microsoft.Databricks/workspaces/${workspaceName}'
          groupIds: [
            'browser_authentication'
          ]
        }
      }
    ]
  }
  dependsOn: [
    pe_ui
  ] 
}





resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = {
  name: privateDnsZoneName
  location: 'global'
  dependsOn: [
    pe_ui
  ]
}

resource privateDnsZoneName_privateDnsZoneName_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = {
  parent: privateDnsZone
  name: '${privateDnsZoneName}-link'
  location: 'global'
  properties: {
    registrationEnabled: false
    virtualNetwork: {
      id: vnet.id
    }
  }
}



resource privateEndpoints_test2_name_default 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2022-05-01' = {
  name: '${pe_ui.name}/default'
  properties: {
    privateDnsZoneConfigs: [
      {
        name: 'privatelink_azuredatabricks_net'
        properties: {
          privateDnsZoneId: privateDnsZone.id
        }
      }
    ]
  }
  dependsOn: [
    pe_ui
  ]
}

resource privateEndpoints_jwits_test_pvtEndpoint_name_mydnsgroupname 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2022-05-01' = {
  name: '${pe_browser.name}/default2'
  properties: {
    privateDnsZoneConfigs: [
      {
        name: 'config1'
        properties: {
          privateDnsZoneId: privateDnsZone.id
        }
      }
    ]
  }
  dependsOn: [
    pe_browser
  ]
}

az loginした後に

az deployment group create --resource-group デプロイリソースグループ --template-file DatabricksDeploy.bicepのファイルパス

を実行します。

デプロイの進捗はリソースグループのデプロイから確認が出来ます。
image.png

リソースの展開を確認。
image.png

公共からのアクセスを無効にしているため、アクセス出来ないことが確認できます。
image.png

VPNのデプロイ

次にVirtualNetworkGateway(VPN)をデプロイしていきます。

証明書発行

PowerShellで下記コマンドからルート証明書を生成して、ウインドウを閉じないままにしておきます。

$cert = New-SelfSignedCertificate -Type Custom -KeySpec Signature `
-Subject "CN=P2SRootCert" -KeyExportPolicy Exportable `
-HashAlgorithm sha256 -KeyLength 2048 `
-CertStoreLocation "Cert:\CurrentUser\My" -KeyUsageProperty Sign -KeyUsage CertSign

実行後、検索欄で「certmgr.msc」を検索してクリックします。

image.png

「個人」→「証明書」をクリックし、生成された証明書を確認します。
image.png

先程のPowerShellを実行した画面で下記コマンドを実行します。

New-SelfSignedCertificate -Type Custom -DnsName P2SChildCert -KeySpec Signature `
-Subject "CN=P2SChildCert" -KeyExportPolicy Exportable `
-HashAlgorithm sha256 -KeyLength 2048 `
-CertStoreLocation "Cert:\CurrentUser\My" `
-Signer $cert -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2")

更新コマンドをクリックし、クライアント証明書が生成されているのを確認します。
image.png

PS2RootCertを右クリックし、「すべてのタスク」→「エクスポート」をクリックします。

image.png

「次へ」をクリックします。
image.png

「いいえ」を選択します。
image.png

「Base64エンコード」を選択します。
image.png

出力先のパスを任意で選択します。
cert.png

image.png

エクスポートされたファイルをテキストエディターで開きます。
image.png

-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
を除く文字列を下記にあるVpnDeploy.bicepのvpn_certification変数にセットします。

image.png

セット後、下記のVpnDeploy.bicepをデプロイします。
完了までに時間が掛かるので注意が必要です。

VpnDeploy.bicep
//生成したルート証明書
var vpn_certification = ''

var vnet_name = 'databricks-vnet'
var location = 'japaneast'
var gateway_subnet_cidr = '10.179.255.0/24'
var vpn_gateway_cidr = '172.16.1.0/24'
var vpn_certification_name = 'クライアントルート証明書'

resource vnet 'Microsoft.Network/virtualNetworks@2022-07-01' existing = {
  name: vnet_name
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2021-08-01' = {
  name: 'GatewaySubnet'
  parent: vnet
  properties: {
    addressPrefix: gateway_subnet_cidr
    delegations: []
  }

}

resource public 'Microsoft.Network/publicIPAddresses@2022-07-01' = {
  name: 'gateway_ip'
  location: location
}

resource gateway 'Microsoft.Network/virtualNetworkGateways@2020-07-01' = {
  name: 'vpn'
  location: location
  properties: {
    gatewayType: 'vpn'
    vpnGatewayGeneration: 'Generation1'
    vpnType: 'RouteBased'
    sku: {
      name: 'VpnGw1'
      tier: 'VpnGw1'
    }
    ipConfigurations: [
      {
        name: 'GatewayConfig'
        properties: {
          subnet: {
            id: '${vnet.id}/subnets/GatewaySubnet'
          }
          publicIPAddress: {
            id: public.id
          }
        }
      }
    ]
    vpnClientConfiguration: {
      vpnClientAddressPool: {
        addressPrefixes: [
          vpn_gateway_cidr
        ]
      }
      vpnClientProtocols: [
        'IkeV2'
      ]
      vpnAuthenticationTypes: [
        'Certificate'
      ]
      vpnClientRootCertificates: [
        {
          name: vpn_certification_name
          properties: {
            publicCertData: vpn_certification
          }
        }
      ]
    }
  }
  dependsOn: [
    public
    subnet
  ]
}

VPN設定

デプロイ完了後に、「vpn」という名前の仮想ゲートウェイをクリックします。

image.png

左欄から「ポイント対サイトの構成」をクリックし、「VPNクライアントのダウンロード」をクリックします。

image.png

ダウンロードして解凍すると以下ファイルが含まれています。
image.png

VpnSettings.xmlので囲まれている部分を以下のVPN接続情報にセットして作成します。

image.png

image.png

image.png

image.png

image.png

これでVPNに接続出来ている状態になりました。
image.png

DNS Private Resolverのデプロイ

最後にdatabricksがDNSを解決出来るように、DNS Private Resolverをデプロイします。

まずリソース一覧から「privatelink.azuredatabricks.net」をクリックします。
image.png

画像では「adb-5113875134185442.2」、「10.179.128.4」となっていますが、この部分はdatabricksデプロイ時にランダムで割り当てられます。

image.png

下記のResolverDeploy.bicepのDomainName変数に「adb-5113875134185442.2.」、targetDNSのingressに「10.179.128.4」を例としてセットします。

※ドメイン後ろに.を追加してそれぞれの環境で確認した値をセットしてください。

image.png

以下ファイルを変数セット後デプロイします。

ResolverDeploy.bicep
//Databricksドメイン設定
var DomainName = ''
//DatabricksのプライベートIp設定
var targetDNS = [
  {
    ipaddress: ''
    port: 53
  }
]


var resolverVNETName = 'databricks-vnet'
var dnsResolverName = 'dnsResolver'
var location = 'japaneast'
var inboundSubnet = 'inbound'
var inboundAddressPrefix = '10.179.129.0/24'
var outboundSubnet = 'outbound'
var outboundAddressPrefix = '10.179.130.0/24'
var resolvervnetlink = 'vnetlink'
var forwardingRulesetName = 'forwardingRule'
var forwardingRuleName = 'routing_databricks'

resource vnet 'Microsoft.Network/virtualNetworks@2022-07-01' existing = {
  name: resolverVNETName
}

resource subnet1 'Microsoft.Network/virtualNetworks/subnets@2021-08-01' = {
  name: inboundSubnet
  parent: vnet
  properties: {
    addressPrefix: inboundAddressPrefix
    delegations: [
      {
        name: 'Microsoft.Network.dnsResolvers'
        properties: {
          serviceName: 'Microsoft.Network/dnsResolvers'
        }
        type: 'Microsoft.Network/virtualNetworks/subnets/delegations'
      }
    ]
  }
  dependsOn: [
    vnet
  ]
}

resource subnet2 'Microsoft.Network/virtualNetworks/subnets@2021-08-01' = {
  name: outboundSubnet
  parent: vnet
  properties: {
    addressPrefix: outboundAddressPrefix
    delegations: [
      {
        name: 'Microsoft.Network.dnsResolvers'
        properties: {
          serviceName: 'Microsoft.Network/dnsResolvers'
        }
        type: 'Microsoft.Network/virtualNetworks/subnets/delegations'
      }
    ]
  }
  dependsOn: [
    vnet
    subnet1
  ]
}

resource resolver 'Microsoft.Network/dnsResolvers@2022-07-01' = {
  name: dnsResolverName
  location: location
  properties: {
    virtualNetwork: {
      id: vnet.id
    }
  }
  dependsOn: [
    vnet
    subnet1
    subnet2
  ]
}

resource inEndpoint 'Microsoft.Network/dnsResolvers/inboundEndpoints@2022-07-01' = {
  parent: resolver
  name: inboundSubnet
  location: location
  properties: {
    ipConfigurations: [
      {
        privateIpAllocationMethod: 'Dynamic'
        subnet: {
          id: '${vnet.id}/subnets/${inboundSubnet}'
        }
      }
    ]
  }
  dependsOn: [
    vnet
    subnet1
    subnet2
  ]
}

resource outEndpoint 'Microsoft.Network/dnsResolvers/outboundEndpoints@2022-07-01' = {
  parent: resolver
  name: outboundSubnet
  location: location
  properties: {
    subnet: {
      id: '${vnet.id}/subnets/${outboundSubnet}'
    }
  }
  dependsOn: [
    vnet
    subnet1
    subnet2
  ]
}

resource fwruleSet 'Microsoft.Network/dnsForwardingRulesets@2022-07-01' = {
  name: forwardingRulesetName
  location: location
  properties: {
    dnsResolverOutboundEndpoints: [
      {
        id: outEndpoint.id
      }
    ]
  }
  dependsOn: [
    vnet
    subnet1
    subnet2
  ]
}

resource resolverLink 'Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks@2022-07-01' = {
  parent: fwruleSet
  name: resolvervnetlink
  properties: {
    virtualNetwork: {
      id: vnet.id
    }
  }
  dependsOn: [
    vnet
    subnet1
    subnet2
  ]
}

resource fwRules 'Microsoft.Network/dnsForwardingRulesets/forwardingRules@2022-07-01' = {
  parent: fwruleSet
  name: forwardingRuleName
  properties: {
    domainName: DomainName
    targetDnsServers: targetDNS
  }
  dependsOn: [
    vnet
    subnet1
    subnet2
  ]
}

DNS設定

問い合わせ先のDNS設定を行います。
ネットワークからdatabricks_vnetを右クリックして「プロパティ」を選択します。
image.png

「ネットワーク」から「インターネットプロトコルバージョン4」を選択し、「プロパティ」をクリックします。
image.png

下記の優先DNSにデプロイしたDNS Private Resolverの受信エンドポイントのIPを以下に記載します。
image.png

Databricks確認

デプロイ完了後、「defafult」のDatabricksをクリックし、画面からURLを選択します。

image.png

image.png

image.png

無事ログイン出来ることを確認。
image.png

クラスターも無事作成出来ました。
image.png

参考にしたサイト様

これで以上となります。
見て下さりありがとうございました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?