parts/k8s/kuberneteswindowssetup.ps1 (358 lines of code) (raw):

<# .SYNOPSIS Provisions VM as a Kubernetes agent. .DESCRIPTION Provisions VM as a Kubernetes agent. The parameters passed in are required, and will vary per-deployment. Notes on modifying this file: - This file extension is PS1, but it is actually used as a template from pkg/engine/template_generator.go - All of the lines that have braces in them will be modified. Please do not change them here, change them in the Go sources - Single quotes are forbidden, they are reserved to delineate the different members for the ARM template concat() call #> [CmdletBinding(DefaultParameterSetName="Standard")] param( [string] [ValidateNotNullOrEmpty()] $MasterIP, [parameter()] [ValidateNotNullOrEmpty()] $KubeDnsServiceIp, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $MasterFQDNPrefix, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $Location, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $AgentKey, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $AADClientId, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $AADClientSecret, # base64 [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $NetworkAPIVersion, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $TargetEnvironment, [string] $UserAssignedClientID ) # These globals will not change between nodes in the same cluster, so they are not # passed as powershell parameters ## SSH public keys to add to authorized_keys $global:SSHKeys = @( {{ GetSshPublicKeysPowerShell }} ) ## Certificates generated by aks-engine $global:CACertificate = "{{WrapAsParameter "caCertificate"}}" $global:AgentCertificate = "{{WrapAsParameter "clientCertificate"}}" ## Download sources provided by aks-engine $global:KubeBinariesPackageSASURL = "{{WrapAsParameter "kubeBinariesSASURL"}}" $global:WindowsKubeBinariesURL = "{{WrapAsParameter "windowsKubeBinariesURL"}}" $global:KubeBinariesVersion = "{{WrapAsParameter "kubeBinariesVersion"}}" $global:ContainerdUrl = "{{WrapAsParameter "windowsContainerdURL"}}" $global:ContainerdSdnPluginUrl = "{{WrapAsParameter "windowsSdnPluginURL"}}" ## Docker Version $global:DockerVersion = "{{WrapAsParameter "windowsDockerVersion"}}" ## ContainerD Usage $global:ContainerRuntime = "{{WrapAsParameter "containerRuntime"}}" $global:DefaultContainerdRuntimeHandler = "{{WrapAsParameter "defaultContainerdRuntimeHandler"}}" $global:HypervRuntimeHandlers = "{{WrapAsParameter "hypervRuntimeHandlers"}}" ## VM configuration passed by Azure $global:WindowsTelemetryGUID = "{{WrapAsParameter "windowsTelemetryGUID"}}" {{if eq GetIdentitySystem "adfs"}} $global:TenantId = "adfs" {{else}} $global:TenantId = "{{WrapAsVariable "tenantID"}}" {{end}} $global:SubscriptionId = "{{WrapAsVariable "subscriptionId"}}" $global:ResourceGroup = "{{WrapAsVariable "resourceGroup"}}" $global:VmType = "{{WrapAsVariable "vmType"}}" $global:SubnetName = "{{WrapAsVariable "subnetName"}}" $global:MasterSubnet = "{{GetWindowsMasterSubnetARMParam}}" $global:SecurityGroupName = "{{WrapAsVariable "nsgName"}}" $global:VNetName = "{{WrapAsVariable "virtualNetworkName"}}" $global:RouteTableName = "{{WrapAsVariable "routeTableName"}}" $global:PrimaryAvailabilitySetName = "{{WrapAsVariable "primaryAvailabilitySetName"}}" $global:PrimaryScaleSetName = "{{WrapAsVariable "primaryScaleSetName"}}" $global:KubeClusterCIDR = "{{WrapAsParameter "kubeClusterCidr"}}" $global:KubeServiceCIDR = "{{WrapAsParameter "kubeServiceCidr"}}" $global:VNetCIDR = "{{WrapAsParameter "vnetCidr"}}" $global:KubeletNodeLabels = "{{GetAgentKubernetesLabels . "',variables('labelResourceGroup'),'"}}" $global:KubeletConfigArgs = @( {{GetKubeletConfigKeyValsPsh .KubernetesConfig }} ) $global:KubeproxyFeatureGates = @( {{GetKubeProxyFeatureGatesPsh}} ) $global:UseManagedIdentityExtension = "{{WrapAsVariable "useManagedIdentityExtension"}}" $global:UseInstanceMetadata = "{{WrapAsVariable "useInstanceMetadata"}}" $global:LoadBalancerSku = "{{WrapAsVariable "loadBalancerSku"}}" $global:ExcludeMasterFromStandardLB = "{{WrapAsVariable "excludeMasterFromStandardLB"}}" # Windows defaults, not changed by aks-engine $global:CacheDir = "c:\akse-cache" $global:KubeDir = "c:\k" $global:HNSModule = [Io.path]::Combine("$global:KubeDir", "hns.v2.psm1") $global:KubeDnsSearchPath = "svc.cluster.local" $global:CNIPath = [Io.path]::Combine("$global:KubeDir", "cni") $global:NetworkMode = "L2Bridge" $global:CNIConfig = [Io.path]::Combine($global:CNIPath, "config", "`$global:NetworkMode.conf") $global:CNIConfigPath = [Io.path]::Combine("$global:CNIPath", "config") $global:AzureCNIDir = [Io.path]::Combine("$global:KubeDir", "azurecni") $global:AzureCNIBinDir = [Io.path]::Combine("$global:AzureCNIDir", "bin") $global:AzureCNIConfDir = [Io.path]::Combine("$global:AzureCNIDir", "netconf") # Azure cni configuration # $global:NetworkPolicy = "{{WrapAsParameter "networkPolicy"}}" # BUG: unused $global:NetworkPlugin = "{{WrapAsParameter "networkPlugin"}}" $global:VNetCNIPluginsURL = "{{WrapAsParameter "vnetCniWindowsPluginsURL"}}" $global:IsDualStackEnabled = {{if IsIPv6DualStackFeatureEnabled}}$true{{else}}$false{{end}} # CSI Proxy settings $global:EnableCsiProxy = [System.Convert]::ToBoolean("{{WrapAsVariable "windowsEnableCSIProxy" }}"); $global:CsiProxyUrl = "{{WrapAsVariable "windowsCSIProxyURL" }}"; # Hosts Config Agent settings $global:EnableHostsConfigAgent = [System.Convert]::ToBoolean("{{WrapAsVariable "enableHostsConfigAgent" }}"); $global:ProvisioningScriptsPackageUrl = "{{WrapAsVariable "windowsProvisioningScriptsPackageURL" }}"; # PauseImage $global:WindowsPauseImageURL = "{{WrapAsVariable "windowsPauseImageURL" }}"; $global:AlwaysPullWindowsPauseImage = [System.Convert]::ToBoolean("{{WrapAsVariable "alwaysPullWindowsPauseImage" }}"); # Secure Windows TLS protocols $global:WindowsSecureTLSEnabled = [System.Convert]::ToBoolean("{{WrapAsVariable "windowsSecureTLSEnabled" }}"); # Base64 representation of ZIP archive $zippedFiles = "{{ GetKubernetesWindowsAgentFunctions }}" # Extract ZIP from script [io.file]::WriteAllBytes("scripts.zip", [System.Convert]::FromBase64String($zippedFiles)) Expand-Archive scripts.zip -DestinationPath "C:\\AzureData\\" # Dot-source scripts with functions that are called in this script . c:\AzureData\k8s\kuberneteswindowsfunctions.ps1 . c:\AzureData\k8s\windowsconfigfunc.ps1 . c:\AzureData\k8s\windowskubeletfunc.ps1 . c:\AzureData\k8s\windowscnifunc.ps1 . c:\AzureData\k8s\windowsazurecnifunc.ps1 . c:\AzureData\k8s\windowscsiproxyfunc.ps1 . c:\AzureData\k8s\windowsinstallopensshfunc.ps1 . c:\AzureData\k8s\windowscontainerdfunc.ps1 . c:\AzureData\k8s\windowshostsconfigagentfunc.ps1 $global:KubeClusterConfigPath = "c:\k\kubeclusterconfig.json" try { # Set to false for debugging. This will output the start script to # c:\AzureData\CustomDataSetupScript.log, and then you can RDP # to the windows machine, and run the script manually to watch # the output. if ($true) { Write-Log ".\CustomDataSetupScript.ps1 -MasterIP $MasterIP -KubeDnsServiceIp $KubeDnsServiceIp -MasterFQDNPrefix $MasterFQDNPrefix -Location $Location -AgentKey $AgentKey -AADClientId $AADClientId -AADClientSecret $AADClientSecret -NetworkAPIVersion $NetworkAPIVersion -TargetEnvironment $TargetEnvironment" Write-Log "Provisioning $global:DockerServiceName... with IP $MasterIP" # Install OpenSSH if SSH enabled $sshEnabled = [System.Convert]::ToBoolean("{{ WindowsSSHEnabled }}") if ( $sshEnabled ) { Write-Log "Install OpenSSH" Install-OpenSSH -SSHKeys $SSHKeys } Write-Log "Apply telemetry data setting" Set-TelemetrySetting -WindowsTelemetryGUID $global:WindowsTelemetryGUID Write-Log "Resize os drive if possible" Resize-OSDrive Write-Log "Initialize data disks" Initialize-DataDisks Write-Log "Create required data directories as needed" Initialize-DataDirectories New-Item -ItemType Directory -Path "c:\k" -Force | Out-Null icacls.exe "c:\k" /inheritance:r icacls.exe "c:\k" /grant:r SYSTEM:`(OI`)`(CI`)`(F`) icacls.exe "c:\k" /grant:r BUILTIN\Administrators:`(OI`)`(CI`)`(F`) icacls.exe "c:\k" /grant:r BUILTIN\Users:`(OI`)`(CI`)`(RX`) Write-Log "c:\k permissions: " icacls.exe "c:\k" Get-ProvisioningScripts Write-KubeClusterConfig -MasterIP $MasterIP -KubeDnsServiceIp $KubeDnsServiceIp Write-Log "Download kubelet binaries and unzip" Get-KubePackage -KubeBinariesSASURL $global:KubeBinariesPackageSASURL # The custom package has a few files that are nessary for future steps (nssm.exe) # this is a temporary work around to get the binaries until we depreciate # custom package and nssm.exe as defined in #3851. if ($global:WindowsKubeBinariesURL){ Write-Log "Overwriting kube node binaries from $global:WindowsKubeBinariesURL" Get-KubeBinaries -KubeBinariesURL $global:WindowsKubeBinariesURL } Write-Log "Installing ContainerD" $cniBinPath = $global:AzureCNIBinDir $cniConfigPath = $global:AzureCNIConfDir if ($global:NetworkPlugin -eq "kubenet") { $cniBinPath = $global:CNIPath $cniConfigPath = $global:CNIConfigPath } Install-Containerd -ContainerdUrl $global:ContainerdUrl -CNIBinDir $cniBinPath -CNIConfDir $cniConfigPath -KubeDir $global:KubeDir Write-Log "Write Azure cloud provider config" Write-AzureConfig ` -KubeDir $global:KubeDir ` -AADClientId $AADClientId ` -AADClientSecret $([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($AADClientSecret))) ` -TenantId $global:TenantId ` -SubscriptionId $global:SubscriptionId ` -ResourceGroup $global:ResourceGroup ` -Location $Location ` -VmType $global:VmType ` -SubnetName $global:SubnetName ` -SecurityGroupName $global:SecurityGroupName ` -VNetName $global:VNetName ` -RouteTableName $global:RouteTableName ` -PrimaryAvailabilitySetName $global:PrimaryAvailabilitySetName ` -PrimaryScaleSetName $global:PrimaryScaleSetName ` -UseManagedIdentityExtension $global:UseManagedIdentityExtension ` -UserAssignedClientID $UserAssignedClientID ` -UseInstanceMetadata $global:UseInstanceMetadata ` -LoadBalancerSku $global:LoadBalancerSku ` -ExcludeMasterFromStandardLB $global:ExcludeMasterFromStandardLB ` -TargetEnvironment $TargetEnvironment {{if IsCustomCloudProfile}} $azureStackConfigFile = [io.path]::Combine($global:KubeDir, "azurestackcloud.json") $envJSON = "{{ GetBase64EncodedEnvironmentJSON }}" [io.file]::WriteAllBytes($azureStackConfigFile, [System.Convert]::FromBase64String($envJSON)) {{end}} Write-Log "Write ca root" Write-CACert -CACertificate $global:CACertificate ` -KubeDir $global:KubeDir if ($global:EnableCsiProxy) { New-CsiProxyService -CsiProxyPackageUrl $global:CsiProxyUrl -KubeDir $global:KubeDir } Write-Log "Write kube config" Write-KubeConfig -CACertificate $global:CACertificate ` -KubeDir $global:KubeDir ` -MasterFQDNPrefix $MasterFQDNPrefix ` -MasterIP $MasterIP ` -AgentKey $AgentKey ` -AgentCertificate $global:AgentCertificate if ($global:EnableHostsConfigAgent) { Write-Log "Starting hosts config agent" New-HostsConfigService } Write-Log "Create the Pause Container kubletwin/pause" New-InfraContainer -KubeDir $global:KubeDir if (-not (Test-ContainerImageExists -Image "kubletwin/pause")) { Write-Log "Could not find container with name kubletwin/pause" $o = ctr -n k8s.io image list Write-Log $o throw "kubletwin/pause container does not exist!" } Write-Log "Configuring networking with NetworkPlugin:$global:NetworkPlugin" # Configure network policy. Get-HnsPsm1 -HNSModule $global:HNSModule Import-Module $global:HNSModule if ($global:NetworkPlugin -eq "azure") { Write-Log "Installing Azure VNet plugins" Install-VnetPlugins -AzureCNIConfDir $global:AzureCNIConfDir ` -AzureCNIBinDir $global:AzureCNIBinDir ` -VNetCNIPluginsURL $global:VNetCNIPluginsURL Set-AzureCNIConfig -AzureCNIConfDir $global:AzureCNIConfDir ` -KubeDnsSearchPath $global:KubeDnsSearchPath ` -KubeClusterCIDR $global:KubeClusterCIDR ` -MasterSubnet $global:MasterSubnet ` -KubeServiceCIDR $global:KubeServiceCIDR ` -VNetCIDR $global:VNetCIDR ` {{- /* Azure Stack has discrete Azure CNI config requirements */}} -IsAzureStack {{if IsAzureStackCloud}}$true{{else}}$false{{end}} ` -IsDualStackEnabled $global:IsDualStackEnabled if ($TargetEnvironment -ieq "AzureStackCloud") { GenerateAzureStackCNIConfig ` -TenantId $global:TenantId ` -SubscriptionId $global:SubscriptionId ` -ResourceGroup $global:ResourceGroup ` -AADClientId $AADClientId ` -KubeDir $global:KubeDir ` -AADClientSecret $([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($AADClientSecret))) ` -NetworkAPIVersion $NetworkAPIVersion ` -AzureEnvironmentFilePath $([io.path]::Combine($global:KubeDir, "azurestackcloud.json")) ` -IdentitySystem "{{ GetIdentitySystem }}" } } elseif ($global:NetworkPlugin -eq "kubenet") { Write-Log "Fetching additional files needed for kubenet" # TODO: CNI may need to move to c:\program files\containerd\cni\bin with ContainerD Install-SdnBridge -Url $global:ContainerdSdnPluginUrl -CNIPath $global:CNIPath } New-ExternalHnsNetwork -IsDualStackEnabled $global:IsDualStackEnabled Install-KubernetesServices ` -KubeDir $global:KubeDir Get-LogCollectionScripts Write-Log "Disable Internet Explorer compat mode and set homepage" Set-Explorer # if multple LB policies are included for same endpoint then HNS hangs. # this fix forces an error Write-Host "Enable a HNS fix in 2021-2C+" Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\hns\State" -Name HNSControlFlag -Value 1 -Type DWORD if ($global:WindowsSecureTLSEnabled) { Write-Host "Enable secure TLS protocols" . C:\k\windowssecuretls.ps1 Enable-SecureTls } Write-Log "Adjust pagefile size" Adjust-PageFileSize Write-Log "Start preProvisioning script" PREPROVISION_EXTENSION Write-Log "Update service failure actions" Update-ServiceFailureActions Adjust-DynamicPortRange Register-LogsCleanupScriptTask Register-NodeResetScriptTask Update-DefenderPreferences {{if IsAzureStackCloud}} {{if UseCloudControllerManager}} # Retrieve SSL cert of ARM Endpoint and find unique Azure Stack root cert $azsConfigFile = [io.path]::Combine($global:KubeDir, "azurestackcloud.json") if (-not (Test-Path -Path $azsConfigFile)) { throw "$azsConfigFile does not exist" } $azsJson = Get-Content -Raw -Path $azsConfigFile | ConvertFrom-Json if ([string]::IsNullOrEmpty($azsJson.resourceManagerEndpoint)) { throw "resourceManagerEndpoint is empty, cannot get Azure Stack ARM uri" } $azsARMUri = [System.Uri]$azsJson.resourceManagerEndpoint $webRequest = [Net.WebRequest]::Create($azsARMUri.AbsoluteUri) try { $webRequest.GetResponse() } catch {} if (($null -eq $webRequest.ServicePoint) -Or ($null -eq $webRequest.ServicePoint.Certificate)) { throw "SSL Certificate of ARM endpoint is null" } $sslCert = $webRequest.ServicePoint.Certificate $sslCertChain = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Chain $sslCertChain.build($sslCert) $sslRootCert = @($sslCertChain.ChainElements.Certificate)[-1] $azsRootCert = Get-ChildItem -Path Cert:\LocalMachine\Root | Where-Object {$_.Thumbprint -eq $sslRootCert.Thumbprint} if ($null -eq $azsRootCert) { throw "azsRootCert is null, cannot find Azure Stack root cert" } elseif ($azsRootCert.Count -ne 1) { throw "azsRootCert is not unique, cannot find Azure Stack root cert" } # Export the Azure Stack root cert for use in cloud node manager container setup. $azsRootCertFilePath = [io.path]::Combine($global:KubeDir, "azsroot.cer") Export-Certificate -Cert $azsRootCert -FilePath $azsRootCertFilePath -Type CERT # Copy certoc tool for use in cloud node manager container setup. [Environment]::SystemDirectory $certocSourcePath = [io.path]::Combine([Environment]::SystemDirectory, "certoc.exe") if (-not (Test-Path -Path $certocSourcePath)) { throw "$certocSourcePath does not exist, cannot export Azure Stack root cert" } Copy-Item -Path $certocSourcePath -Destination $global:KubeDir # Create add cert script $addRootCertFile = [io.path]::Combine($global:KubeDir, "addazsroot.bat") if ($null -eq $azsRootCert) { throw "$azsRootCertFilePath is null, cannot create add cert script" } [io.file]::WriteAllText($addRootCertFile, "${global:KubeDir}\certoc.exe -addstore root ${azsRootCertFilePath}") {{end}} {{end}} if (Test-Path $CacheDir) { Write-Log "Removing aks-engine-azurestack bits cache directory" Remove-Item $CacheDir -Recurse -Force } Write-Log "Setup Complete, reboot computer" Restart-Computer } else { # keep for debugging purposes Write-Log ".\CustomDataSetupScript.ps1 -MasterIP $MasterIP -KubeDnsServiceIp $KubeDnsServiceIp -MasterFQDNPrefix $MasterFQDNPrefix -Location $Location -AgentKey $AgentKey -AADClientId $AADClientId -AADClientSecret $AADClientSecret -NetworkAPIVersion $NetworkAPIVersion -TargetEnvironment $TargetEnvironment" } } catch { Write-Error $_ throw $_ }