docker registry template embedded (#451)
This commit is contained in:
Родитель
65a7a15145
Коммит
ae9b7e764d
|
@ -11,7 +11,6 @@ Make sure you take care of the following pre-requisites before you start the set
|
|||
- `Ubuntu Server 16.04-LTS` was syndicated from Azure Stack's Marketplace by the operator
|
||||
- `Custom Script Extensions for Linux 2.0` was syndicated from Azure Stack's Marketplace by the operator
|
||||
- You have access to a X.509 certificate in PFX format
|
||||
- You can execute [htpasswd](https://httpd.apache.org/docs/2.4/programs/htpasswd.html) to generate the authorized users credentials
|
||||
- You can [connect](https://docs.microsoft.com/en-us/azure-stack/user/azure-stack-powershell-configure-user) to the target Azure Stack instance using PowerShell
|
||||
|
||||
## Setup
|
||||
|
@ -20,112 +19,17 @@ The following section details the required steps to perform before you deploy th
|
|||
|
||||
Once you went through the details, you should be able to tweak the [setup script](setup.ps1) and adjust it to your needs.
|
||||
|
||||
### Basic Authentication using .htpasswd files
|
||||
|
||||
`htpasswd` is a small command-line utility that creates and updates text files (usually named `.htpasswd`) used to store user credentials for basic HTTP authentication.
|
||||
|
||||
An usage example is shown below (add flag `-c` to create file `.htpasswd`):
|
||||
|
||||
```bash
|
||||
htpasswd -Bb .htpasswd my-user my-password
|
||||
```
|
||||
|
||||
#### Anonymous access
|
||||
|
||||
To allow anonymous access to the registry, update the `docker run` command executed by the [CSE script](script.sh) **before** you start the [storage configuration](#storage-configuration) step.
|
||||
|
||||
Deleting the lines that set variables REGISTRY_AUTH, REGISTRY_AUTH_HTPASSWD_PATH AND REGISTRY_AUTH_HTPASSWD_REALM will disable basic authentication.
|
||||
|
||||
### Storage configuration
|
||||
|
||||
The template instructs the container registry to use the [Azure storage driver](https://docs.docker.com/registry/storage-drivers/azure/) to persist the container images in a local storage account blob container.
|
||||
|
||||
We will also store the `.htpasswd` file in the same storage account to keep it secure and readily available when you need to upgrade your registry or guest OS to a new version.
|
||||
### Key Vault configuration
|
||||
|
||||
You can use the PowerShell snipped below to automate the storage account setup process:
|
||||
The deployment template will instruct Azure Resource Manager to drop your certificate in the virtual machine's file system. User credentials should be stored as secrets in the same local Key Vault instance where the PFX certificate is stored.
|
||||
|
||||
```powershell
|
||||
# Set variables to match your environment
|
||||
$location = "your-location"
|
||||
$resourceGroup = "registry-rg"
|
||||
$saName = "registry"
|
||||
$saContainer = "images"
|
||||
$tokenIni = Get-Date
|
||||
$tokenEnd = $tokenIni.AddYears(1.0)
|
||||
### Basic Authorization
|
||||
|
||||
# Create resource group
|
||||
Write-Host "Creating resource group:" $resourceGroup
|
||||
New-AzureRmResourceGroup -Name $resourceGroup -Location $location | out-null
|
||||
|
||||
# Create storage account
|
||||
Write-Host "Creating storage account:" $saName
|
||||
$sa = New-AzureRmStorageAccount -ResourceGroupName $resourceGroup -AccountName $saName -Location $location -SkuName Premium_LRS -EnableHttpsTrafficOnly 1
|
||||
$saKey = (Get-AzureRmStorageAccountKey -ResourceGroupName $resourceGroup -AccountName $saName)[0].Value
|
||||
|
||||
# Create blob container
|
||||
Write-Host "Creating blob container:" $saContainer
|
||||
Set-AzureRmCurrentStorageAccount -ResourceGroupName $resourceGroup -AccountName $saName | out-null
|
||||
$container = New-AzureStorageContainer -Name $saContainer
|
||||
|
||||
# Upload the CSE script so the template can later fetch it during deployment
|
||||
Write-Host "Uploading configuration script"
|
||||
Set-AzureStorageBlobContent -Container $saContainer -File script.sh | out-null
|
||||
$cseToken = New-AzureStorageBlobSASToken -Container $saContainer -Blob "script.sh" -Permission r -StartTime $tokenIni -ExpiryTime $tokenEnd
|
||||
$cseUrl = $container.CloudBlobContainer.Uri.AbsoluteUri + "/script.sh" + $cseToken
|
||||
|
||||
# The CSE script needs the .htpasswd file to configure the container registry
|
||||
Write-Host "Uploading .htpasswd file"
|
||||
Set-AzureStorageBlobContent -Container $saContainer -File .htpasswd | out-null
|
||||
# Get htpasswd download URL
|
||||
$htpasswdToken = New-AzureStorageBlobSASToken -Container $saContainer -Blob .htpasswd -Permission r -StartTime $tokenIni -ExpiryTime $tokenEnd
|
||||
$htpasswdUrl = $container.CloudBlobContainer.Uri.AbsoluteUri + "/.htpasswd" + $htpasswdToken
|
||||
```
|
||||
|
||||
## Key Vault configuration
|
||||
|
||||
The deployment template will instruct Azure Resource Manager to drop your certificate in the virtual machine's file system.
|
||||
|
||||
The snippet below creates the Key Vault resource and uploads the .pfx certificate.
|
||||
|
||||
```powershell
|
||||
$kvName = "certs"
|
||||
$secretName = "registry"
|
||||
$pfxPath = "cert.pfx"
|
||||
$pfxPass = ""
|
||||
|
||||
# Create key vault enabled for deployment
|
||||
Write-Host "Creating key vault:" $kvName
|
||||
$kv = New-AzureRmKeyVault -ResourceGroupName $resourceGroup -VaultName $kvName -Location $location -Sku standard -EnabledForDeployment
|
||||
|
||||
# Serialize certificate
|
||||
$fileContentBytes = get-content $pfxPath -Encoding Byte
|
||||
$fileContentEncoded = [System.Convert]::ToBase64String($fileContentBytes)
|
||||
$jsonObject = @"
|
||||
{
|
||||
"data": "$filecontentencoded",
|
||||
"dataType" :"pfx",
|
||||
"password": "$pfxPass"
|
||||
}
|
||||
"@
|
||||
$jsonObjectBytes = [System.Text.Encoding]::UTF8.GetBytes($jsonObject)
|
||||
$jsonEncoded = [System.Convert]::ToBase64String($jsonObjectBytes)
|
||||
$secret = ConvertTo-SecureString -String $jsonEncoded -AsPlainText -Force
|
||||
|
||||
# Upload certificate as secret
|
||||
Write-Host "Storing certificate in key vault:" $pfxPath
|
||||
$kvSecret = Set-AzureKeyVaultSecret -VaultName $kvName -Name $secretName -SecretValue $secret
|
||||
```
|
||||
|
||||
### Certificate thumbprint
|
||||
|
||||
Your certificate thumbprint is a required parameter of the ARM template. The CSE script uses that information to find the certificate in the virtual machine' file system.
|
||||
|
||||
Run the following snipped to generate the certificate thumbprint:
|
||||
|
||||
```powershell
|
||||
Write-Host "Computing certificate thumbprint"
|
||||
$tp = Get-PfxCertificate -FilePath $pfxPath
|
||||
```
|
||||
User credentials should be stored as secrets in the same local Key Vault instance where the PFX certificate is stored. This can be achieved using the web UI or the SDK.
|
||||
|
||||
## Template deployment
|
||||
|
||||
|
@ -145,7 +49,7 @@ New-AzureRmResourceGroupDeployment `
|
|||
|
||||
### Upgrade
|
||||
|
||||
In order to upgrade the guest OS or the container registry itself, update [azuredeploy.json](azuredeploy.json) and/or [script.sh](script.sh) as needed and run once again `New-AzureRmResourceGroupDeployment` as previously indicated.
|
||||
In order to upgrade the guest OS or the container registry itself, update [azuredeploy.json](azuredeploy.json) as needed and run once again `New-AzureRmResourceGroupDeployment` as previously indicated.
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
|
@ -50,10 +50,29 @@
|
|||
"description": "The guest OS image version."
|
||||
}
|
||||
},
|
||||
"storageAccountName": {
|
||||
"pipName": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "An already existing storage account name."
|
||||
"description": "The public IP resource name."
|
||||
}
|
||||
},
|
||||
"pipDomainNameLabel": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "The public IP DNS label."
|
||||
}
|
||||
},
|
||||
"pipAllocationMethod": {
|
||||
"type": "string",
|
||||
"defaultValue": "dynamic",
|
||||
"metadata": {
|
||||
"description": "The public IP allocation method."
|
||||
}
|
||||
},
|
||||
"storageAccountResourceId": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "An already existing storage account resource identifier."
|
||||
}
|
||||
},
|
||||
"storageAccountContainer": {
|
||||
|
@ -62,31 +81,19 @@
|
|||
"description": "An already existing storage account container name."
|
||||
}
|
||||
},
|
||||
"storageAccountKey": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "The storage account access key."
|
||||
}
|
||||
},
|
||||
"domainNameLabel": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "The public IP DNS label."
|
||||
}
|
||||
},
|
||||
"keyVaultResourceId": {
|
||||
"pfxKeyVaultResourceId": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "The Key Vault resource identifier."
|
||||
}
|
||||
},
|
||||
"keyVaultSecretUrl": {
|
||||
"pfxKeyVaultSecretUrl": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Absolute URL to the Key Vault secret that stores the pfx certificate."
|
||||
}
|
||||
},
|
||||
"certificateThumbprint": {
|
||||
"pfxThumbprint": {
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "The certificate thumbprint."
|
||||
|
@ -100,41 +107,47 @@
|
|||
}
|
||||
},
|
||||
"registryReplicas": {
|
||||
"type": "int",
|
||||
"defaultValue": 20,
|
||||
"type": "string",
|
||||
"defaultValue": "20",
|
||||
"metadata": {
|
||||
"description": "Docker registry replicas."
|
||||
}
|
||||
},
|
||||
"cseLocation": {
|
||||
"type": "string",
|
||||
"servicePrincipalClientId": {
|
||||
"type": "securestring",
|
||||
"metadata": {
|
||||
"description": "Download URL of the script to be executed by the template custom script extension."
|
||||
"description": "Client ID with access to list and get secrets from the credentials Key Vault instance"
|
||||
}
|
||||
},
|
||||
"htpasswdLocation": {
|
||||
"type": "string",
|
||||
"servicePrincipalClientSecret": {
|
||||
"type": "securestring",
|
||||
"metadata": {
|
||||
"description": "Download URL of the .htpasswd file."
|
||||
"description": "Secret of the client with access to list and get secrets from the credentials Key Vault instance"
|
||||
}
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"vnetId": "[resourceId('Microsoft.Network/virtualNetworks', 'registry-vnet')]",
|
||||
"rgname": "[resourceGroup().name]",
|
||||
"nsgName": "[concat(variables('rgname'), '-nsg')]",
|
||||
"nicName": "[concat(variables('rgname'), '-nic')]",
|
||||
"vnetName": "[concat(variables('rgname'), '-vnet')]",
|
||||
"vnetId": "[resourceId('Microsoft.Network/virtualNetworks',variables('vnetName'))]",
|
||||
"subnetRef": "[concat(variables('vnetId'), '/subnets/default')]",
|
||||
"tenantId": "[subscription().tenantId]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"provisionScriptParameters": "[concat('ADMIN_USER_NAME=', parameters('adminUsername'),' REGISTRY_STORAGE_AZURE_ACCOUNTNAME=', parameters('storageAccountName'),' REGISTRY_STORAGE_AZURE_ACCOUNTKEY=', parameters('storageAccountKey'),' REGISTRY_STORAGE_AZURE_CONTAINER=', parameters('storageAccountContainer'),' CERT_THUMBPRINT=', parameters('certificateThumbprint'),' PIP_LABEL=', parameters('domainNameLabel'),' REGISTRY_TAG=', parameters('registryTag'),' REGISTRY_REPLICAS=', parameters('registryReplicas'))]"
|
||||
"provisionScriptParameters": "[concat('ADMIN_USER_NAME=', parameters('adminUsername'),' SA_RESOURCE_ID=', parameters('storageAccountResourceId'),' SA_CONTAINER=', parameters('storageAccountContainer'),' KV_RESOURCE_ID=', parameters('pfxKeyVaultResourceId'),' CERT_THUMBPRINT=', parameters('pfxThumbprint'),' PIP_LABEL=', parameters('pipDomainNameLabel'),' REGISTRY_TAG=', parameters('registryTag'),' SPN_CLIENT_ID=',parameters('servicePrincipalClientId'),' SPN_CLIENT_SECRET=',parameters('servicePrincipalClientSecret'),' REGISTRY_REPLICAS=', parameters('registryReplicas'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Compute/virtualMachines",
|
||||
"name": "registry-vm",
|
||||
"name": "[concat(variables('rgname'),'-vm')]",
|
||||
"apiVersion": "2017-03-30",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"osProfile": {
|
||||
"computerName": "registry",
|
||||
"computerName": "[concat(variables('rgname'),'-vm')]",
|
||||
"adminUsername": "[parameters('adminUsername')]",
|
||||
"customData": "[base64(concat('#cloud-config\n\nwrite_files:\n- path: \"/opt/azure/containers/script.sh\"\n permissions: \"0744\"\n encoding: gzip\n owner: \"root\"\n content: !!binary |\n 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'))]",
|
||||
"linuxConfiguration": {
|
||||
"disablePasswordAuthentication": true,
|
||||
"ssh": {
|
||||
|
@ -149,11 +162,11 @@
|
|||
"secrets": [
|
||||
{
|
||||
"sourceVault": {
|
||||
"id": "[parameters('keyVaultResourceId')]"
|
||||
"id": "[parameters('pfxKeyVaultResourceId')]"
|
||||
},
|
||||
"vaultCertificates": [
|
||||
{
|
||||
"certificateUrl": "[parameters('keyVaultSecretUrl')]"
|
||||
"certificateUrl": "[parameters('pfxKeyVaultSecretUrl')]"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -181,29 +194,25 @@
|
|||
"networkProfile": {
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces', 'registry-nic')]"
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/networkInterfaces/', 'registry-nic')]"
|
||||
"[concat('Microsoft.Network/networkInterfaces/',variables('nicName'))]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"apiVersion": "2017-03-30",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Compute/virtualMachines/', 'registry-vm')]"
|
||||
"[concat('Microsoft.Compute/virtualMachines/',variables('rgname'),'-vm')]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "registry-vm/cse",
|
||||
"name": "[concat(variables('rgname'),'-vm/cse')]",
|
||||
"properties": {
|
||||
"protectedSettings": {
|
||||
"fileUris": [
|
||||
"[parameters('cseLocation')]",
|
||||
"[parameters('htpasswdLocation')]"
|
||||
],
|
||||
"commandToExecute": "[concat(variables('provisionScriptParameters'),' LOCATION=',variables('location'),' FQDN=', '\"', reference(resourceId('Microsoft.Network/publicIPAddresses', 'registry-pip'),'2017-10-01').dnsSettings.fqdn,'\"',' ./script.sh >> /var/log/azure/docker-registry.log 2>&1')]"
|
||||
"commandToExecute": "[concat(variables('provisionScriptParameters'),' LOCATION=',variables('location'),' TENANT_ID=',variables('tenantId'),' PIP_FQDN=', '\"', reference(resourceId('Microsoft.Network/publicIPAddresses',parameters('pipName')),'2017-10-01').dnsSettings.fqdn,'\"',' /opt/azure/containers/script.sh >> /var/log/azure/docker-registry.log 2>&1')]"
|
||||
},
|
||||
"publisher": "Microsoft.Azure.Extensions",
|
||||
"settings": {},
|
||||
|
@ -215,7 +224,7 @@
|
|||
},
|
||||
{
|
||||
"type": "Microsoft.Network/virtualNetworks",
|
||||
"name": "registry-vnet",
|
||||
"name": "[concat(variables('rgname'),'-vnet')]",
|
||||
"apiVersion": "2017-10-01",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
|
@ -236,7 +245,7 @@
|
|||
},
|
||||
{
|
||||
"type": "Microsoft.Network/networkInterfaces",
|
||||
"name": "registry-nic",
|
||||
"name": "[variables('nicName')]",
|
||||
"apiVersion": "2017-10-01",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
|
@ -249,19 +258,19 @@
|
|||
},
|
||||
"privateIPAllocationMethod": "Dynamic",
|
||||
"publicIpAddress": {
|
||||
"id": "[resourceId('Microsoft.Network/publicIpAddresses', 'registry-pip')]"
|
||||
"id": "[resourceId('Microsoft.Network/publicIpAddresses',parameters('pipName'))]"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"networkSecurityGroup": {
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', 'registry-nsg')]"
|
||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups',variables('nsgName'))]"
|
||||
}
|
||||
},
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/virtualNetworks/', 'registry-vnet')]",
|
||||
"[concat('Microsoft.Network/publicIpAddresses/', 'registry-pip')]",
|
||||
"[concat('Microsoft.Network/networkSecurityGroups/', 'registry-nsg')]"
|
||||
"[concat('Microsoft.Network/virtualNetworks/',variables('rgname'),'-vnet')]",
|
||||
"[concat('Microsoft.Network/publicIpAddresses/',parameters('pipName'))]",
|
||||
"[concat('Microsoft.Network/networkSecurityGroups/',variables('nsgName'))]"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -269,19 +278,19 @@
|
|||
"sku": {
|
||||
"name": "Basic"
|
||||
},
|
||||
"name": "registry-pip",
|
||||
"name": "[parameters('pipName')]",
|
||||
"apiVersion": "2017-10-01",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"publicIpAllocationMethod": "Dynamic",
|
||||
"publicIpAllocationMethod": "[parameters('pipAllocationMethod')]",
|
||||
"dnsSettings": {
|
||||
"domainNameLabel": "[parameters('domainNameLabel')]"
|
||||
"domainNameLabel": "[parameters('pipDomainNameLabel')]"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Network/networkSecurityGroups",
|
||||
"name": "registry-nsg",
|
||||
"name": "[variables('nsgName')]",
|
||||
"apiVersion": "2017-10-01",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
|
|
|
@ -2,34 +2,61 @@
|
|||
"schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"storageAccountName": {
|
||||
"value": ""
|
||||
},
|
||||
"storageAccountContainer": {
|
||||
"value": ""
|
||||
},
|
||||
"storageAccountKey": {
|
||||
"value": ""
|
||||
},
|
||||
"keyVaultResourceId": {
|
||||
"value": ""
|
||||
},
|
||||
"keyVaultSecretUrl": {
|
||||
"value": ""
|
||||
},
|
||||
"certificateThumbprint": {
|
||||
"adminUsername": {
|
||||
"value": ""
|
||||
},
|
||||
"adminPublicKey": {
|
||||
"value": ""
|
||||
},
|
||||
"domainNameLabel": {
|
||||
"virtualMachineSize": {
|
||||
"value": ""
|
||||
},
|
||||
"cseLocation": {
|
||||
"virtualMachinePublisher": {
|
||||
"value": ""
|
||||
},
|
||||
"htpasswdLocation": {
|
||||
"virtualMachineOffer": {
|
||||
"value": ""
|
||||
},
|
||||
"virtualMachineSku": {
|
||||
"value": ""
|
||||
},
|
||||
"virtualMachineVersion": {
|
||||
"value": ""
|
||||
},
|
||||
"pipName": {
|
||||
"value": ""
|
||||
},
|
||||
"pipDomainNameLabel": {
|
||||
"value": ""
|
||||
},
|
||||
"pipAllocationMethod": {
|
||||
"value": ""
|
||||
},
|
||||
"storageAccountResourceId": {
|
||||
"value": ""
|
||||
},
|
||||
"storageAccountContainer": {
|
||||
"value": ""
|
||||
},
|
||||
"pfxKeyVaultResourceId": {
|
||||
"value": ""
|
||||
},
|
||||
"pfxKeyVaultSecretUrl": {
|
||||
"value": ""
|
||||
},
|
||||
"pfxThumbprint": {
|
||||
"value": ""
|
||||
},
|
||||
"registryTag": {
|
||||
"value": ""
|
||||
},
|
||||
"registryReplicas": {
|
||||
"value": ""
|
||||
},
|
||||
"servicePrincipalClientId": {
|
||||
"value": ""
|
||||
},
|
||||
"servicePrincipalClientSecret": {
|
||||
"value": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
#!/bin/bash -x
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT license.
|
||||
|
||||
ERR_APT_INSTALL_TIMEOUT=9 # Timeout installing required apt packages
|
||||
ERR_MISSING_CRT_FILE=10 # Bad cert thumbprint OR pfx not in key vault OR template misconfigured VM secrets section
|
||||
ERR_MISSING_KEY_FILE=11 # Bad cert thumbprint OR pfx not in key vault OR template misconfigured VM secrets section
|
||||
ERR_REGISTRY_NOT_RUNNING=13 # the container registry failed to start successfully
|
||||
ERR_MOBY_APT_LIST_TIMEOUT=25 # Timeout waiting for moby apt sources
|
||||
ERR_MS_GPG_KEY_DOWNLOAD_TIMEOUT=26 # Timeout waiting for MS GPG key download
|
||||
ERR_MOBY_INSTALL_TIMEOUT=27 # Timeout waiting for moby install
|
||||
# ===
|
||||
# NOTE: the CSE script is embedded in azuredeploy.json (base64 encoding)
|
||||
# Update the VM resource (.properties.osPrifile.customData) to alter the CSE script.
|
||||
# ===
|
||||
|
||||
ERR_APT_INSTALL_TIMEOUT=9 # Timeout installing required apt packages
|
||||
ERR_MISSING_CRT_FILE=10 # Bad cert thumbprint OR pfx not in key vault OR template misconfigured VM secrets section
|
||||
ERR_MISSING_KEY_FILE=11 # Bad cert thumbprint OR pfx not in key vault OR template misconfigured VM secrets section
|
||||
ERR_MISSING_USER_CREDENTIALS=12 # No user credentials secret found on given key vault
|
||||
ERR_REGISTRY_NOT_RUNNING=13 # The container registry failed to start successfully
|
||||
ERR_MOBY_APT_LIST_TIMEOUT=25 # Timeout waiting for moby apt sources
|
||||
ERR_MS_GPG_KEY_DOWNLOAD_TIMEOUT=26 # Timeout waiting for MS GPG key download
|
||||
ERR_MOBY_INSTALL_TIMEOUT=27 # Timeout waiting for moby install
|
||||
ERR_METADATA=30 # Error querying metadata
|
||||
ERR_MS_PROD_DEB_DOWNLOAD_TIMEOUT=42 # Timeout waiting for https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb
|
||||
ERR_MS_PROD_DEB_PKG_ADD_FAIL=43 # Failed to add repo pkg file
|
||||
ERR_APT_UPDATE_TIMEOUT=99 # Timeout waiting for apt-get update to complete
|
||||
|
||||
UBUNTU_RELEASE=$(lsb_release -r -s)
|
||||
MOBY_VERSION="3.0.6"
|
||||
ERR_MS_PROD_DEB_PKG_ADD_FAIL=43 # Failed to add repo pkg file
|
||||
ERR_APT_UPDATE_TIMEOUT=99 # Timeout waiting for apt-get update to complete
|
||||
|
||||
retrycmd_if_failure() {
|
||||
retries=$1; wait_sleep=$2; timeout=$3;
|
||||
|
@ -66,13 +73,16 @@ apt_get_install() {
|
|||
wait_for_apt_locks
|
||||
}
|
||||
installDeps() {
|
||||
UBUNTU_RELEASE=$(lsb_release -r -s)
|
||||
MOBY_VERSION="3.0.6"
|
||||
|
||||
retrycmd_if_failure 120 5 25 curl https://packages.microsoft.com/config/ubuntu/${UBUNTU_RELEASE}/prod.list > /tmp/microsoft-prod.list || exit $ERR_MOBY_APT_LIST_TIMEOUT
|
||||
retrycmd_if_failure 10 5 10 cp /tmp/microsoft-prod.list /etc/apt/sources.list.d/ || exit $ERR_MOBY_APT_LIST_TIMEOUT
|
||||
retrycmd_if_failure 120 5 25 curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /tmp/microsoft.gpg || exit $ERR_MS_GPG_KEY_DOWNLOAD_TIMEOUT
|
||||
retrycmd_if_failure 10 5 10 cp /tmp/microsoft.gpg /etc/apt/trusted.gpg.d/ || exit $ERR_MS_GPG_KEY_DOWNLOAD_TIMEOUT
|
||||
apt_get_update || exit $ERR_APT_UPDATE_TIMEOUT
|
||||
|
||||
apt_get_install 20 30 120 moby-engine=${MOBY_VERSION} moby-cli=${MOBY_VERSION} --allow-downgrades || exit $ERR_MOBY_INSTALL_TIMEOUT
|
||||
apt_get_install 20 30 120 apache2-utils moby-engine=${MOBY_VERSION} moby-cli=${MOBY_VERSION} --allow-downgrades || exit $ERR_MOBY_INSTALL_TIMEOUT
|
||||
usermod -aG docker ${ADMIN_USER_NAME}
|
||||
|
||||
for apt_package in curl jq; do
|
||||
|
@ -82,26 +92,97 @@ installDeps() {
|
|||
fi
|
||||
done
|
||||
}
|
||||
fetchOAuth() {
|
||||
ENDPOINTS=$(mktemp)
|
||||
curl -s --retry 5 --retry-delay 10 --max-time 60 -f \
|
||||
https://management.${FQDN}/metadata/endpoints?api-version=2015-01-01 > ${ENDPOINTS}
|
||||
|
||||
echo ADMIN_USER_NAME: ${ADMIN_USER_NAME}
|
||||
echo REGISTRY_STORAGE_AZURE_ACCOUNTNAME: ${REGISTRY_STORAGE_AZURE_ACCOUNTNAME}
|
||||
echo REGISTRY_STORAGE_AZURE_ACCOUNTKEY: ${REGISTRY_STORAGE_AZURE_ACCOUNTKEY}
|
||||
echo REGISTRY_STORAGE_AZURE_CONTAINER: ${REGISTRY_STORAGE_AZURE_CONTAINER}
|
||||
echo CERT_THUMBPRINT: ${CERT_THUMBPRINT}
|
||||
echo FQDN: ${FQDN}
|
||||
echo LOCATION: ${LOCATION}
|
||||
echo PIP_LABEL: ${PIP_LABEL}
|
||||
echo REGISTRY_TAG: ${REGISTRY_TAG}
|
||||
echo REGISTRY_REPLICAS: ${REGISTRY_REPLICAS}
|
||||
if [ $? -ne 0 ]; then
|
||||
exit $ERR_METADATA
|
||||
fi
|
||||
|
||||
OAUTH=$(jq -r .authentication.loginEndpoint ${ENDPOINTS})
|
||||
echo ${OAUTH} | grep -e "/adfs$"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
TOKEN_URL="${OAUTH}/oauth2/token"
|
||||
else
|
||||
TOKEN_URL="${OAUTH}${TENANT_ID}/oauth2/token"
|
||||
fi
|
||||
}
|
||||
fetchCredentials() {
|
||||
RESOURCE=$(jq -r .authentication.audiences[0] ${ENDPOINTS} | sed "s|https://management.|https://vault.|")
|
||||
|
||||
TOKEN=$(curl -s --retry 5 --retry-delay 10 --max-time 60 -f -X POST \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=client_credentials" \
|
||||
-d "client_id=${SPN_CLIENT_ID}" \
|
||||
--data-urlencode "client_secret=${SPN_CLIENT_SECRET}" \
|
||||
--data-urlencode "resource=${RESOURCE}" \
|
||||
${TOKEN_URL} | jq -r '.access_token')
|
||||
|
||||
KV_URL="https://${KV_NAME}.vault.${FQDN}/secrets"
|
||||
SECRETS=$(curl -s --retry 5 --retry-delay 10 --max-time 60 -f \
|
||||
"${KV_URL}?api-version=2016-10-01" -H "Authorization: Bearer ${TOKEN}" | jq -r .value[].id)
|
||||
|
||||
rm .htpasswd
|
||||
touch .htpasswd
|
||||
for secret in ${SECRETS}
|
||||
do
|
||||
SECRET_NAME_VERSION="${secret//$KV_URL}"
|
||||
SECRET_NAME=$(echo ${SECRET_NAME_VERSION} | cut -d '/' -f 2)
|
||||
SECRET_VALUE=$(curl -s --retry 5 --retry-delay 10 --max-time 60 -f \
|
||||
"${secret}?api-version=2016-10-01" -H "Authorization: Bearer ${TOKEN}" | jq -r .value)
|
||||
htpasswd -Bb .htpasswd ${SECRET_NAME} ${SECRET_VALUE}
|
||||
done
|
||||
|
||||
if [ ! -s .htpasswd ]; then
|
||||
echo "file .htpasswd is empty, credentials were not created or there was an error fetching credentials from keyvault"
|
||||
exit $ERR_MISSING_USER_CREDENTIALS
|
||||
fi
|
||||
}
|
||||
fetchStorageKeys() {
|
||||
RESOURCE=$(jq -r .authentication.audiences[0] ${ENDPOINTS})
|
||||
|
||||
TOKEN=$(curl -s --retry 5 --retry-delay 10 --max-time 60 -f -X POST \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=client_credentials" \
|
||||
-d "client_id=${SPN_CLIENT_ID}" \
|
||||
--data-urlencode "client_secret=${SPN_CLIENT_SECRET}" \
|
||||
--data-urlencode "resource=${RESOURCE}" \
|
||||
${TOKEN_URL} | jq -r '.access_token')
|
||||
|
||||
SA_URL="https://management.${FQDN}/${SA_RESOURCE_ID}/listKeys?api-version=2017-10-01"
|
||||
SA_KEY=$(curl -s --retry 5 --retry-delay 10 --max-time 60 -f -X POST \
|
||||
"${SA_URL}" -H "Authorization: Bearer ${TOKEN}" -H "Content-Length: 0" | jq -r ".keys[0].value")
|
||||
}
|
||||
|
||||
echo LOCATION: ${LOCATION}
|
||||
echo TENANT_ID: ${TENANT_ID}
|
||||
echo ADMIN_USER_NAME: ${ADMIN_USER_NAME}
|
||||
echo SA_RESOURCE_ID: ${SA_RESOURCE_ID}
|
||||
echo SA_CONTAINER: ${SA_CONTAINER}
|
||||
echo KV_RESOURCE_ID: ${KV_RESOURCE_ID}
|
||||
echo CERT_THUMBPRINT: ${CERT_THUMBPRINT}
|
||||
echo PIP_FQDN: ${PIP_FQDN}
|
||||
echo PIP_LABEL: ${PIP_LABEL}
|
||||
echo REGISTRY_TAG: ${REGISTRY_TAG}
|
||||
echo REGISTRY_REPLICAS: ${REGISTRY_REPLICAS}
|
||||
echo SPN_CLIENT_ID: ${SPN_CLIENT_ID}
|
||||
echo SPN_CLIENT_SECRET: ***
|
||||
|
||||
SA_NAME=$(echo ${SA_RESOURCE_ID} | grep -oh -e '[[:alnum:]]*$')
|
||||
KV_NAME=$(echo ${KV_RESOURCE_ID} | grep -oh -e '[[:alnum:]]*$')
|
||||
|
||||
EXT_DOMAIN_NAME="${PIP_FQDN//$PIP_LABEL.$LOCATION.cloudapp.}"
|
||||
FQDN=${LOCATION}.${EXT_DOMAIN_NAME}
|
||||
|
||||
EXTERNAL_FQDN="${FQDN//$PIP_LABEL.$LOCATION.cloudapp.}"
|
||||
REGISTRY_STORAGE_AZURE_REALM=${LOCATION}.${EXTERNAL_FQDN}
|
||||
CRT_FILE="${CERT_THUMBPRINT}.crt"
|
||||
KEY_FILE="${CERT_THUMBPRINT}.prv"
|
||||
SECRET=$(openssl rand -base64 32)
|
||||
|
||||
if [ -f /var/log.vhd/azure/golden-image-install.complete ]; then
|
||||
echo "golden image; skipping dependencies installation"
|
||||
if [ -f /opt/azure/vhd-install.complete ]; then
|
||||
echo "aks base image; skipping dependencies installation"
|
||||
rm -rf /home/packer
|
||||
deluser packer
|
||||
groupdel packer
|
||||
|
@ -119,8 +200,7 @@ if [ ! -f "/var/lib/waagent/${KEY_FILE}" ]; then
|
|||
fi
|
||||
|
||||
echo adding certs to the ca-store
|
||||
CRT_DST_PATH="/usr/local/share/ca-certificates"
|
||||
cp "/var/lib/waagent/Certificates.pem" "${CRT_DST_PATH}/azsCertificate.crt"
|
||||
cp "/var/lib/waagent/Certificates.pem" "/usr/local/share/ca-certificates/azsCertificate.crt"
|
||||
update-ca-certificates
|
||||
|
||||
echo copy user cert to mount point
|
||||
|
@ -129,11 +209,17 @@ mkdir -p $STORE
|
|||
cp "/var/lib/waagent/${CRT_FILE}" "${STORE}/${CRT_FILE}"
|
||||
cp "/var/lib/waagent/${KEY_FILE}" "${STORE}/${KEY_FILE}"
|
||||
|
||||
echo moving .htpasswd to mount point
|
||||
echo getting management endpoints
|
||||
fetchOAuth
|
||||
|
||||
echo fetching storage key
|
||||
fetchStorageKeys
|
||||
|
||||
echo fetching user credentials
|
||||
HTPASSWD_DIR="/root/auth"
|
||||
mkdir -p $HTPASSWD_DIR
|
||||
awk '{ sub("\r$", ""); print }' .htpasswd > .htpasswd.tmp
|
||||
cp .htpasswd.tmp $HTPASSWD_DIR/.htpasswd
|
||||
fetchCredentials
|
||||
cp .htpasswd $HTPASSWD_DIR/.htpasswd
|
||||
|
||||
echo starting registry container
|
||||
cat <<EOF >> docker-compose.yml
|
||||
|
@ -153,11 +239,12 @@ services:
|
|||
- /etc/ssl/certs:/etc/ssl/certs:ro
|
||||
- /root/auth:/auth
|
||||
environment:
|
||||
- REGISTRY_LOG_ACCESSLOG_DISABLED=false
|
||||
- REGISTRY_STORAGE=azure
|
||||
- REGISTRY_STORAGE_AZURE_ACCOUNTNAME=${REGISTRY_STORAGE_AZURE_ACCOUNTNAME}
|
||||
- REGISTRY_STORAGE_AZURE_ACCOUNTKEY=${REGISTRY_STORAGE_AZURE_ACCOUNTKEY}
|
||||
- REGISTRY_STORAGE_AZURE_CONTAINER=${REGISTRY_STORAGE_AZURE_CONTAINER}
|
||||
- REGISTRY_STORAGE_AZURE_REALM=${REGISTRY_STORAGE_AZURE_REALM}
|
||||
- REGISTRY_STORAGE_AZURE_ACCOUNTNAME=${SA_NAME}
|
||||
- REGISTRY_STORAGE_AZURE_ACCOUNTKEY=${SA_KEY}
|
||||
- REGISTRY_STORAGE_AZURE_CONTAINER=${SA_CONTAINER}
|
||||
- REGISTRY_STORAGE_AZURE_REALM=${FQDN}
|
||||
- REGISTRY_AUTH=htpasswd
|
||||
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/.htpasswd
|
||||
- REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm"
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
function Random-Name {
|
||||
Param ([int]$length)
|
||||
-join ((97..122) | Get-Random -Count $length | % {[char]$_})
|
||||
}
|
||||
|
||||
# Set variables to match your environment
|
||||
#########################################
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT license.
|
||||
|
||||
$location = ""
|
||||
$resourceGroup = ""
|
||||
$saName = Random-Name 10
|
||||
$saContainer = Random-Name 10
|
||||
$tokenIni = Get-Date
|
||||
$tokenEnd = $tokenIni.AddYears(1.0)
|
||||
$saName = ""
|
||||
$saContainer = ""
|
||||
|
||||
$kvName = Random-Name 10
|
||||
$secretName = Random-Name 10
|
||||
$kvName = ""
|
||||
$pfxSecret = ""
|
||||
$pfxPath = ""
|
||||
$pfxPass = ""
|
||||
$dnsSubDomain = ""
|
||||
$spnName = ""
|
||||
$spnSecret = ""
|
||||
$userName = ""
|
||||
$userPass = ""
|
||||
|
||||
$dnsLabelName = ""
|
||||
$sshKey = ""
|
||||
$vmSize = ""
|
||||
$registryTag = "2.7.1"
|
||||
$registryReplicas = "5"
|
||||
|
||||
# RESOURCE GROUP
|
||||
# =============================================
|
||||
|
@ -34,25 +35,16 @@ New-AzureRmResourceGroup -Name $resourceGroup -Location $location | out-null
|
|||
# Create storage account
|
||||
Write-Host "Creating storage account:" $saName
|
||||
$sa = New-AzureRmStorageAccount -ResourceGroupName $resourceGroup -AccountName $saName -Location $location -SkuName Premium_LRS -EnableHttpsTrafficOnly 1
|
||||
$saKey = (Get-AzureRmStorageAccountKey -ResourceGroupName $resourceGroup -AccountName $saName)[0].Value
|
||||
|
||||
# Create container
|
||||
Write-Host "Creating blob container:" $saContainer
|
||||
Set-AzureRmCurrentStorageAccount -ResourceGroupName $resourceGroup -AccountName $saName | out-null
|
||||
$container = New-AzureStorageContainer -Name $saContainer
|
||||
New-AzureStorageContainer -Name $saContainer | out-null
|
||||
|
||||
# Upload configuration script
|
||||
Write-Host "Uploading configuration script"
|
||||
Set-AzureStorageBlobContent -Container $saContainer -File script.sh | out-null
|
||||
$cseToken = New-AzureStorageBlobSASToken -Container $saContainer -Blob "script.sh" -Permission r -StartTime $tokenIni -ExpiryTime $tokenEnd
|
||||
$cseUrl = $container.CloudBlobContainer.Uri.AbsoluteUri + "/script.sh" + $cseToken
|
||||
|
||||
# Upload htpasswd
|
||||
Write-Host "Uploading htpasswd file"
|
||||
Set-AzureStorageBlobContent -Container $saContainer -File .htpasswd | out-null
|
||||
$htpasswdToken = New-AzureStorageBlobSASToken -Container $saContainer -Blob .htpasswd -Permission r -StartTime $tokenIni -ExpiryTime $tokenEnd
|
||||
$htpasswdUrl = $container.CloudBlobContainer.Uri.AbsoluteUri + "/.htpasswd" + $htpasswdToken
|
||||
Write-Host "=> Storage Account Resource ID:" $sa.Id
|
||||
|
||||
Write-Host "Assigning contributor role to" $spnName
|
||||
New-AzureRMRoleAssignment -ApplicationId $spnName -RoleDefinitionName "Contributor" -Scope $sa.Id
|
||||
|
||||
# KEY VAULT
|
||||
# =============================================
|
||||
|
@ -60,8 +52,13 @@ $htpasswdUrl = $container.CloudBlobContainer.Uri.AbsoluteUri + "/.htpasswd" + $h
|
|||
# Create key vault enabled for deployment
|
||||
Write-Host "Creating key vault:" $kvName
|
||||
$kv = New-AzureRmKeyVault -ResourceGroupName $resourceGroup -VaultName $kvName -Location $location -Sku standard -EnabledForDeployment
|
||||
Write-Host "=> Key Vault Resource ID:" $kv.ResourceId
|
||||
|
||||
# Serialize certificate
|
||||
Write-Host "Setting access polices for client" $spnName
|
||||
Set-AzureRmKeyVaultAccessPolicy -VaultName $kvName -ServicePrincipalName $spnName -PermissionsToSecrets GET,LIST
|
||||
|
||||
# Store certificate as secret
|
||||
Write-Host "Storing certificate in key vault:" $pfxPath
|
||||
$fileContentBytes = get-content $pfxPath -Encoding Byte
|
||||
$fileContentEncoded = [System.Convert]::ToBase64String($fileContentBytes)
|
||||
$jsonObject = @"
|
||||
|
@ -74,59 +71,75 @@ $jsonObject = @"
|
|||
$jsonObjectBytes = [System.Text.Encoding]::UTF8.GetBytes($jsonObject)
|
||||
$jsonEncoded = [System.Convert]::ToBase64String($jsonObjectBytes)
|
||||
$secret = ConvertTo-SecureString -String $jsonEncoded -AsPlainText -Force
|
||||
|
||||
# Upload certificate as secret
|
||||
Write-Host "Storing certificate in key vault:" $pfxPath
|
||||
$kvSecret = Set-AzureKeyVaultSecret -VaultName $kvName -Name $secretName -SecretValue $secret
|
||||
$kvSecret = Set-AzureKeyVaultSecret -VaultName $kvName -Name $pfxSecret -SecretValue $secret -ContentType pfx
|
||||
|
||||
# Compute certificate thumbprint
|
||||
Write-Host "Computing certificate thumbprint"
|
||||
$tp = Get-PfxCertificate -FilePath $pfxPath
|
||||
|
||||
Write-Host "=> Certificate URL:" $kvSecret.Id
|
||||
Write-Host "=> Certificate thumbprint:" $tp.Thumbprint
|
||||
|
||||
Write-Host "Storing secret for sample user: $userName"
|
||||
$userSecret = ConvertTo-SecureString -String $userPass -AsPlainText -Force
|
||||
Set-AzureKeyVaultSecret -VaultName $kvName -Name $userName -SecretValue $userSecret -ContentType "user credentials" | out-null
|
||||
|
||||
|
||||
# BUILD TEMPLATE PARAMETERS JSON
|
||||
# =============================================
|
||||
$jsonParameters = New-Object -TypeName PSObject
|
||||
|
||||
$jsonStorageAccountName = New-Object -TypeName PSObject
|
||||
$jsonStorageAccountName | Add-Member -MemberType NoteProperty -Name value -Value $saName
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name storageAccountName -Value $jsonStorageAccountName
|
||||
$jsonAdminPublicKey = New-Object -TypeName PSObject
|
||||
$jsonAdminPublicKey | Add-Member -MemberType NoteProperty -Name value -Value $sshKey
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name adminPublicKey -Value $jsonAdminPublicKey
|
||||
|
||||
$jsonVirtualMachineSize = New-Object -TypeName PSObject
|
||||
$jsonVirtualMachineSize | Add-Member -MemberType NoteProperty -Name value -Value $vmSize
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name virtualMachineSize -Value $jsonVirtualMachineSize
|
||||
|
||||
$jsonPipName = New-Object -TypeName PSObject
|
||||
$jsonPipName | Add-Member -MemberType NoteProperty -Name value -Value $dnsLabelName
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name pipName -Value $jsonPipName
|
||||
|
||||
$jsonPipDomainNameLabel = New-Object -TypeName PSObject
|
||||
$jsonPipDomainNameLabel | Add-Member -MemberType NoteProperty -Name value -Value $dnsLabelName
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name pipDomainNameLabel -Value $jsonPipDomainNameLabel
|
||||
|
||||
$jsonStorageAccountResourceId = New-Object -TypeName PSObject
|
||||
$jsonStorageAccountResourceId | Add-Member -MemberType NoteProperty -Name value -Value $sa.Id
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name storageAccountResourceId -Value $jsonStorageAccountResourceId
|
||||
|
||||
$jsonStorageAccountContainerName = New-Object -TypeName PSObject
|
||||
$jsonStorageAccountContainerName | Add-Member -MemberType NoteProperty -Name value -Value $saContainer
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name storageAccountContainer -Value $jsonStorageAccountContainerName
|
||||
|
||||
$jsonStorageAccountKey = New-Object -TypeName PSObject
|
||||
$jsonStorageAccountKey | Add-Member -MemberType NoteProperty -Name value -Value $saKey
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name storageAccountKey -Value $jsonStorageAccountKey
|
||||
|
||||
$jsonKeyVaultResourceId = New-Object -TypeName PSObject
|
||||
$jsonKeyVaultResourceId | Add-Member -MemberType NoteProperty -Name value -Value $kv.ResourceId
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name keyVaultResourceId -Value $jsonKeyVaultResourceId
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name pfxKeyVaultResourceId -Value $jsonKeyVaultResourceId
|
||||
|
||||
$jsonKeyVaultSecretUrl = New-Object -TypeName PSObject
|
||||
$jsonKeyVaultSecretUrl | Add-Member -MemberType NoteProperty -Name value -Value $kvSecret.Id
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name keyVaultSecretUrl -Value $jsonKeyVaultSecretUrl
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name pfxKeyVaultSecretUrl -Value $jsonKeyVaultSecretUrl
|
||||
|
||||
$jsonCertificateThumbprint = New-Object -TypeName PSObject
|
||||
$jsonCertificateThumbprint | Add-Member -MemberType NoteProperty -Name value -Value $tp.Thumbprint
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name certificateThumbprint -Value $jsonCertificateThumbprint
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name pfxThumbprint -Value $jsonCertificateThumbprint
|
||||
|
||||
$jsonAdminPublicKey = New-Object -TypeName PSObject
|
||||
$jsonAdminPublicKey | Add-Member -MemberType NoteProperty -Name value -Value $sshKey
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name adminPublicKey -Value $jsonAdminPublicKey
|
||||
$jsonRegistryTag = New-Object -TypeName PSObject
|
||||
$jsonRegistryTag | Add-Member -MemberType NoteProperty -Name value -Value $registryTag
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name registryTag -Value $jsonRegistryTag
|
||||
|
||||
$jsonDomainNameLabel = New-Object -TypeName PSObject
|
||||
$jsonDomainNameLabel | Add-Member -MemberType NoteProperty -Name value -Value $dnsSubDomain
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name domainNameLabel -Value $jsonDomainNameLabel
|
||||
$jsonRegistryReplicas = New-Object -TypeName PSObject
|
||||
$jsonRegistryReplicas | Add-Member -MemberType NoteProperty -Name value -Value $registryReplicas
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name registryReplicas -Value $jsonRegistryReplicas
|
||||
|
||||
$jsonCseLocation = New-Object -TypeName PSObject
|
||||
$jsonCseLocation | Add-Member -MemberType NoteProperty -Name value -Value $cseUrl
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name cseLocation -Value $jsonCseLocation
|
||||
$jsonSpnName = New-Object -TypeName PSObject
|
||||
$jsonSpnName | Add-Member -MemberType NoteProperty -Name value -Value $spnName
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name servicePrincipalClientId -Value $jsonSpnName
|
||||
|
||||
$jsonHtpasswdLocation = New-Object -TypeName PSObject
|
||||
$jsonHtpasswdLocation | Add-Member -MemberType NoteProperty -Name value -Value $htpasswdUrl
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name htpasswdLocation -Value $jsonHtpasswdLocation
|
||||
$jsonSpnSecret = New-Object -TypeName PSObject
|
||||
$jsonSpnSecret | Add-Member -MemberType NoteProperty -Name value -Value $spnSecret
|
||||
$jsonParameters | Add-Member -MemberType NoteProperty -Name servicePrincipalClientSecret -Value $jsonSpnSecret
|
||||
|
||||
$jsonRoot = New-Object -TypeName PSObject
|
||||
$jsonRoot | Add-Member -MemberType NoteProperty -Name schema -Value "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#"
|
||||
|
|
Загрузка…
Ссылка в новой задаче