在 Compute Engine 上部署 Active Directory 林

Last reviewed 2023-05-10 UTC

本文档介绍了如何按照在 Google Cloud 上运行 Active Directory 的最佳实践中所述的最佳实践在 Compute Engine 上部署 Active Directory 林。

本指南适用于管理员和 DevOps 工程师。它假定您熟悉 Active Directory,并且基本了解 Google Cloud 网络和安全性。

架构

部署包含两个项目:

此架构允许您执行以下操作:

  • 在单独的项目中部署其他 Windows 工作负载,让它们使用共享 VPC 网络和 Active Directory 林。
  • 将 Active Directory 林与现有本地林集成以实现资源林模式

准备工作

要按照本指南中的说明进行操作,请确保满足以下条件:

  • 两个子网的子网 CIDR 范围:

    • 网域控制器子网。此子网包含网域控制器。在管理防火墙规则或分析网络日志时,为网域控制器使用专用子网有助于区分网域控制器流量与其他服务器流量。

      建议使用大小为 /28/29 的子网 CIDR 范围。

    • 资源子网。此子网包含服务器和管理工作站。 使用足够大的子网 CIDR 范围,以容纳您计划部署的所有服务器。

    确保您的子网不与任何本地子网重叠,并留出足够的增长空间。

  • Active Directory 林根网域的 DNS 域名和 NetBIOS 域名。如需详细了解如何选择名称,请参阅 Microsoft 命名惯例

部署共享网络

在本部分中,您将创建一个新项目,并使用该项目部署共享 VPC 网络。稍后,您将使用此网络部署 Active Directory 网域控制器。

创建项目

现在,您可以创建一个新项目并使用它来部署共享 VPC 网络。

  1. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  2. 确保您的 Google Cloud 项目已启用结算功能

  3. 启用 Compute Engine and Cloud DNS API。

    启用 API

如需获得部署共享网络所需的权限,请让您的管理员为您授予项目或父级文件夹的以下 IAM 角色:

如需详细了解如何授予角色,请参阅管理访问权限

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

删除默认 VPC

默认情况下,Compute Engine 会在您创建的每个新项目中创建默认网络。此网络采用自动模式进行配置,这意味着系统为每个区域预先分配一个子网,并自动分配 CIDR 范围。

在本部分中,您需要将此 VPC 网络替换为包含两个子网并使用自定义 CIDR 范围的自定义模式网络。

  1. Google Cloud 控制台中,打开 Cloud Shell

    激活 Cloud Shell

  2. 启动 PowerShell:

    pwsh
    
  3. 配置 gcloud CLI 以使用新项目:

    gcloud config set project PROJECT_ID
    

    PROJECT_ID 替换为您的项目 ID。

  4. 删除与默认 VPC 关联的所有防火墙规则:

    $ProjectId = gcloud config get-value core/project
    & gcloud compute firewall-rules list `
      --filter "network=default" `
      --format "value(name)" |
      % { gcloud compute firewall-rules delete --quiet $_ --project $ProjectId }
    
  5. 删除默认 VPC:

    & gcloud compute networks list --format "value(name)" |
      % { gcloud compute networks delete $_ --quiet }
    

创建一个自定义模式 VPC 网络

现在,您可以在 VPC 宿主项目中创建自定义模式 VPC 网络。

  1. 在 PowerShell 中,初始化以下变量:

    $VpcName = "VPC_NAME"
    $Region = "REGION"
    $SubnetRangeDomainControllers = "DC_CIDR"
    $SubnetRangeResources = "RESOURCES_CIDR"
    

    请替换以下内容:

    • VPC_NAME:VPC 的名称。
    • REGION:要在其中部署 Active Directory 网域控制器的区域。
    • DC_CIDR:用于网域控制器子网的子网范围。
    • RESOURCES_CIDR:资源子网的子网范围。

    示例:

    $VpcName = "ad"
    $Region = "us-central1"
    $SubnetRangeDomainControllers = "10.0.0.0/28"
    $SubnetRangeResources = "10.0.1.0/24"
    
  2. 创建 VPC 并将其配置为用作共享 VPC 网络:

    $ProjectId = gcloud config get-value core/project
    & gcloud compute networks create $VpcName --subnet-mode custom
    & gcloud compute shared-vpc enable $ProjectId
    
  3. 创建子网并启用专用 Google 访问通道,以便 Windows 可以在没有连接互联网的情况下激活

    & gcloud compute networks subnets create domain-controllers `
      --network $VpcName `
      --range $SubnetRangeDomainControllers `
      --region $Region `
      --enable-private-ip-google-access
    
    & gcloud compute networks subnets create resources `
      --network $VpcName `
      --range $SubnetRangeResources `
      --region $Region `
      --enable-private-ip-google-access
    

部署子网和防火墙规则

现在,您可以创建防火墙规则以允许在 VPC 内进行 Active Directory 通信。

  1. 允许通过 Cloud IAP TCP 转发与所有虚拟机实例建立 RDP 连接:

    & gcloud compute firewall-rules create allow-rdp-ingress-from-iap `
      --direction INGRESS `
      --action allow `
      --rules tcp:3389 `
      --enable-logging `
      --source-ranges 35.235.240.0/20 `
      --network $VpcName `
      --priority 10000
    
  2. 允许从 Cloud DNS 到网域控制器的 DNS 查询。

    & gcloud compute firewall-rules create allow-dns-ingress-from-clouddns `
      --direction INGRESS `
      --action=allow `
      --rules udp:53,tcp:53 `
      --enable-logging `
      --source-ranges 35.199.192.0/19 `
      --target-tags ad-domaincontroller `
      --network $VpcName `
      --priority 10000
    

    要使专用 DNS 转发可用区正常工作,必须使用此防火墙规则。

  3. 允许在网域控制器之间复制 Active Directory:

    & gcloud compute firewall-rules create allow-replication-between-addc `
      --direction INGRESS `
      --action allow `
      --rules "icmp,tcp:53,udp:53,tcp:88,udp:88,udp:123,tcp:135,tcp:389,udp:389,tcp:445,udp:445,tcp:49152-65535" `
      --enable-logging `
      --source-tags ad-domaincontroller `
      --target-tags ad-domaincontroller `
      --network $VpcName `
      --priority 10000
    
  4. 允许 Active Directory 从资源子网中的虚拟机登录网域控制器:

    & gcloud compute firewall-rules create allow-logon-ingress-to-addc `
      --direction INGRESS `
      --action allow `
      --rules "icmp,tcp:53,udp:53,tcp:88,udp:88,udp:123,tcp:135,tcp:389,udp:389,tcp:445,udp:445,tcp:464,udp:464,tcp:3268,udp:3268,tcp:9389,tcp:49152-65535" `
      --enable-logging `
      --source-ranges $SubnetRangeResources `
      --target-tags ad-domaincontroller `
      --network $VpcName `
      --priority 10000
    
  5. 如果您打算配置安全 LDAP,请允许从资源子网中的虚拟机到网域控制器的安全 LDAP 连接:

    & gcloud compute firewall-rules create allow-ldaps-ingress-to-addc `
      --direction INGRESS `
      --action allow `
      --rules tcp:636 `
      --enable-logging `
      --source-ranges $SubnetRangeResources `
      --target-tags ad-domaincontroller `
      --network $VpcName `
      --priority 10000
    

    只有在您计划配置安全 LDAP 时,才需要此防火墙规则。

  6. (可选)创建记录所有失败访问尝试的防火墙规则。这些日志可用于诊断连接问题,但可能会产生大量日志数据。

    & gcloud compute firewall-rules create deny-ingress-from-all `
      --direction INGRESS `
      --action deny `
      --rules tcp:0-65535,udp:0-65535 `
      --enable-logging `
      --source-ranges 0.0.0.0/0 `
      --network $VpcName `
      --priority 65000
    

部署 Active Directory 林

在本部分中,您将创建一个新的服务项目,并将其关联到您之前创建的共享 VPC 宿主项目。然后,使用服务项目部署具有两个网域控制器的新 Active Directory 林。

创建项目

现在,您可以创建一个新项目并使用它来部署 Active Directory 域控制器虚拟机。

  1. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  2. 确保您的 Google Cloud 项目已启用结算功能

  3. 启用 Compute Engine and Secret Manager API。

    启用 API

如需获得部署 Active Directory 林所需的权限,请让您的管理员为您授予项目的以下 IAM 角色:

如需详细了解如何授予角色,请参阅管理访问权限

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

准备配置

下一步是准备 Active Directory 部署的配置。

  1. 如果您之前关闭了 PowerShell 会话,请打开 Cloud Shell

    激活 Cloud Shell

  2. 启动 PowerShell:

    pwsh
    
  3. 配置 gcloud CLI 以使用新项目:

    gcloud config set project DC_PROJECT_ID
    

    DC_PROJECT_ID 替换为您的项目 ID。

  4. 使用 PowerShell 创建以下变量:

    $AdDnsDomain = "DNS_DOMAIN"
    $AdNetbiosDomain = "NETBIOS_DOMAIN"
    $VpcProjectId = "VPCHOST_PROJECT_ID"
    $VpcName = "VPC_NAME"
    $Region = "REGION"
    $Zones = "REGION-a", "REGION-b"
    

    请替换以下内容:

    • DNS_DOMAIN:Active Directory 林的林根域名,例如 cloud.example.com
    • NETBIOS_DOMAIN:林根网域的 NetBIOS 域名,例如 CLOUD
    • VPCHOST_PROJECT_ID:您之前创建的 VPC 宿主项目的 ID。
    • VPC_NAME:您之前创建的共享 VPC 网络的名称。
    • REGION:要在其中部署 Active Directory 网域控制器的区域。请注意,可用区的名称基于您指定的区域的名称。您可以随时扩展 VPC 和网域以覆盖其他区域。

    示例:

    $AdDnsDomain = "cloud.example.com"
    $AdNetbiosDomain = "CLOUD"
    $VpcProjectId = "vpc-project-123"
    $VpcName = "ad"
    $Region = "us-west1"
    $Zones = "us-west1-a", "us-west1-b"
    

创建专用 DNS 转发可用区

现在,您可以为网域控制器预留两个静态 IP 地址,并创建一个专用 DNS 转发可用区,以将 Active Directory 网域的所有 DNS 查询转发到这些 IP 地址。

  1. 将项目连接到共享 VPC 网络:

    $ProjectId = gcloud config get-value core/project
    & gcloud compute shared-vpc associated-projects add $ProjectId --host-project $VpcProjectId
    
  2. 在网域控制器子网中预留两个静态内部 IP 地址:

    $AddressOfDc1 = gcloud compute addresses create dc-1 `
      --region $Region `
      --subnet "projects/$VpcProjectId/regions/$Region/subnetworks/domain-controllers" `
      --format value`(address`)
    $AddressOfDc2 = gcloud compute addresses create dc-2 `
      --region $Region `
      --subnet "projects/$VpcProjectId/regions/$Region/subnetworks/domain-controllers" `
      --format value`(address`)
    
  3. 在 VPC 宿主项目中创建 Cloud DNS 专用转发可用区,并将可用区配置为将 DNS 查询转发到两个预留的 IP 地址:

    & gcloud dns managed-zones create $AdDnsDomain.Replace(".", "-") `
      --project $VpcProjectId `
      --dns-name $AdDnsDomain `
      --description "Active Directory forwarding zone" `
      --networks $VpcName `
      --visibility private `
      --forwarding-targets "$AddressOfDc1,$AddressOfDc2"
    

创建 DSRM 密码

现在,您可以定义 Directory Service Restore Mode (DSRM) 密码,并将其存储在 Secret Manager 中。然后,向网域控制器虚拟机授予对此 Secret 的临时访问权限,以便他们可以使用它来部署 Active Directory 林。

  1. 生成随机密码并将其存储在 Secret Manager Secret 中:

    # Generate a random password.
    $DsrmPassword = [Guid]::NewGuid().ToString()+"-"+[Guid]::NewGuid().ToString()
    
    $TempFile = New-TemporaryFile
    Set-Content $TempFile "$DsrmPassword" -NoNewLine
    & gcloud secrets create ad-password --data-file $TempFile
    Remove-Item $TempFile
    
  2. 为网域控制器虚拟机实例创建服务账号:

    $DcServiceAccount = gcloud iam service-accounts create ad-domaincontroller `
      --display-name "AD Domain Controller" `
      --format "value(email)"
    
  3. 授予服务账号读取下一个小时内的 Secret 的权限:

    $Expiry = [DateTime]::UtcNow.AddHours(1).ToString("o")
    & gcloud secrets add-iam-policy-binding ad-password `
      --member=serviceAccount:$($DcServiceAccount) `
      --role=roles/secretmanager.secretAccessor `
      --condition="title=Expires after 1h,expression=request.time < timestamp('$Expiry')"
    

部署网域控制器

现在,您可以部署两个虚拟机实例并创建新的 Active Directory 林和网域。要最大限度地减少手动步骤,请使用启动脚本

  1. 在 PowerShell 中运行以下命令以生成启动脚本:

    '
    $ErrorActionPreference = "Stop"
    
    #
    # Only run the script if the VM is not a domain controller already.
    #
    if ((Get-CimInstance -ClassName Win32_OperatingSystem).ProductType -eq 2) {
        exit
    }
    
    #
    # Read configuration from metadata.
    #
    Import-Module "${Env:ProgramFiles}\Google\Compute Engine\sysprep\gce_base.psm1"
    
    $ActiveDirectoryDnsDomain     = Get-MetaData -Property "attributes/ActiveDirectoryDnsDomain" -instance_only
    $ActiveDirectoryNetbiosDomain = Get-MetaData -Property "attributes/ActiveDirectoryNetbiosDomain" -instance_only
    $ActiveDirectoryFirstDc       = Get-MetaData -Property "attributes/ActiveDirectoryFirstDc" -instance_only
    $ProjectId                    = Get-MetaData -Property "project-id" -project_only
    $Hostname                     = Get-MetaData -Property "hostname" -instance_only
    $AccessToken                  = (Get-MetaData -Property "service-accounts/default/token" | ConvertFrom-Json).access_token
    
    #
    # Read the DSRM password from secret manager.
    #
    $Secret = (Invoke-RestMethod `
        -Headers @{
            "Metadata-Flavor" = "Google";
            "x-goog-user-project" = $ProjectId;
            "Authorization" = "Bearer $AccessToken"} `
        -Uri "https://secretmanager.googleapis.com/v1/projects/$ProjectId/secrets/ad-password/versions/latest:access")
    $DsrmPassword = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Secret.payload.data))
    $DsrmPassword = ConvertTo-SecureString -AsPlainText $DsrmPassword -force
    
    #
    # Promote.
    #
    Write-Host "Setting administrator password..."
    Set-LocalUser -Name Administrator -Password $DsrmPassword
    
    if ($ActiveDirectoryFirstDc -eq $env:COMPUTERNAME) {
        Write-Host "Creating a new forest $ActiveDirectoryDnsDomain ($ActiveDirectoryNetbiosDomain)..."
        Install-ADDSForest `
            -DomainName $ActiveDirectoryDnsDomain `
            -DomainNetbiosName $DomainNetbiosName `
            -SafeModeAdministratorPassword $DsrmPassword `
            -DomainMode Win2008R2 `
            -ForestMode Win2008R2 `
            -InstallDns `
            -CreateDnsDelegation:$False `
            -NoRebootOnCompletion:$True `
            -Confirm:$false
    }
    else {
        do {
            Write-Host "Waiting for domain to become available..."
            Start-Sleep -s 60
            & ipconfig /flushdns | Out-Null
            & nltest /dsgetdc:$ActiveDirectoryDnsDomain | Out-Null
        } while ($LASTEXITCODE -ne 0)
    
        Write-Host "Adding DC to $ActiveDirectoryDnsDomain ($ActiveDirectoryNetbiosDomain)..."
        Install-ADDSDomainController `
            -DomainName $ActiveDirectoryDnsDomain `
            -SafeModeAdministratorPassword $DsrmPassword `
            -InstallDns `
            -Credential (New-Object System.Management.Automation.PSCredential ("Administrator@$ActiveDirectoryDnsDomain", $DsrmPassword)) `
            -NoRebootOnCompletion:$true  `
            -Confirm:$false
    }
    
    #
    # Configure DNS.
    #
    Write-Host "Configuring DNS settings..."
    Get-Netadapter| Disable-NetAdapterBinding -ComponentID ms_tcpip6
    Set-DnsClientServerAddress  `
        -InterfaceIndex (Get-NetAdapter -Name Ethernet).InterfaceIndex `
        -ServerAddresses 127.0.0.1
    
    #
    # Enable LSA protection.
    #
    New-ItemProperty `
        -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" `
        -Name "RunAsPPL" `
        -Value 1 `
        -PropertyType DWord
    
    Write-Host "Restarting to apply all settings..."
    Restart-Computer
    ' | Out-File dc-startup.ps1 -Encoding ASCII
    

    该脚本将执行以下操作:

    • 从 Secret Manager 读取 DSRM 密码。
    • 将虚拟机升级为网域控制器。
    • 配置 DNS 设置,以使每个网域控制器使用环回地址作为 DNS 服务器。
    • 停用 IPv6。
    • 启用 LSA 保护
  2. 为第一个网域控制器创建一个虚拟机实例:

    $Subnet = "projects/$VpcProjectId/regions/$Region/subnetworks/domain-controllers"
    $Metadata = `
      "ActiveDirectoryDnsDomain=$AdDnsDomain",
      "ActiveDirectoryNetbiosDomain=$AdNetbiosDomain",
      "ActiveDirectoryFirstDc=dc-1",
      "sysprep-specialize-script-ps1=Install-WindowsFeature AD-Domain-Services; Install-WindowsFeature DNS",
      "disable-account-manager=true" -join ","
    
    & gcloud compute instances create dc-1  `
      --image-family windows-2022 `
      --image-project windows-cloud `
      --machine-type n2-standard-8 `
      --tags ad-domaincontroller `
      --metadata "$Metadata" `
      --metadata-from-file windows-startup-script-ps1=dc-startup.ps1 `
      --no-address `
      --network-interface "no-address,private-network-ip=$AddressOfDc1,subnet=$Subnet" `
      --service-account $DcServiceAccount `
      --scopes cloud-platform `
      --zone $Zones[0] `
      --shielded-integrity-monitoring `
      --shielded-secure-boot `
      --shielded-vtpm `
      --deletion-protection
    

    此命令执行以下操作:

    • 创建安全强化型 Windows Server 2022 虚拟机。
    • ad-domaincontroller 服务账号分配给虚拟机,以便它可以访问 DSRM 密码。
    • 配置客机代理以停用账号管理器。如需详细了解如何配置客机代理,请参阅启用和停用 Windows 实例功能
    • 在 sysprep 专用阶段中,让虚拟机安装 Windows 功能 AD-Domain-ServicesDNS
    • 让虚拟机运行您之前创建的启动脚本。
  3. 为第二个网域控制器创建另一个虚拟机实例,并将其放置在其他可用区中:

    & gcloud compute instances create dc-2  `
      --image-family windows-2022 `
      --image-project windows-cloud `
      --machine-type n2-standard-8 `
      --tags ad-domaincontroller `
      --metadata "$Metadata" `
      --metadata-from-file windows-startup-script-ps1=dc-startup.ps1 `
      --no-address `
      --network-interface "no-address,private-network-ip=$AddressOfDc2,subnet=$Subnet" `
      --service-account $DcServiceAccount `
      --scopes cloud-platform `
      --zone $Zones[1] `
      --shielded-integrity-monitoring `
      --shielded-secure-boot `
      --shielded-vtpm `
      --deletion-protection
    
  4. 通过查看第一个网域控制器的串行端口输出来监控其初始化过程:

    & gcloud compute instances tail-serial-port-output dc-1 --zone $Zones[0]
    

    等待大约 10 分钟,直到您看到消息 Restarting to apply all settings...,然后按 Ctrl+C

  5. 通过查看第二个网域控制器的串行端口输出来监控其初始化过程:

    & gcloud compute instances tail-serial-port-output dc-2 --zone $Zones[1]
    

    等待大约 10 分钟,直到您看到消息 Restarting to apply all settings...,然后按 Ctrl+C

Active Directory 林和网域现在可以使用了。

连接到网域控制器

现在,您可以通过连接到其中一个网域控制器来自定义 Active Directory 林。

  1. 在 PowerShell 中,访问 Administrator 用户的密码:

    gcloud secrets versions access latest --secret ad-password
    
  2. 使用 RDP 连接到 dc-1,然后以 Administrator 用户身份登录。

    由于虚拟机实例没有公共 IP 地址,因此您必须通过 Identity-Aware Proxy TCP 转发进行连接。

后续步骤