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 $_
}