Created
September 12, 2018 17:54
-
-
Save smourier/5a509761ed19e5790fee6372e5b68934 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#requires -Modules AcmeSharp, Azure, AzureRM.Websites | |
#with support for custom subscription id - smourier - 2018/09/12 | |
<#PSScriptInfo | |
.VERSION 1.4.4 | |
.TITLE GetSSL - Azure Automation | |
.AUTHOR Dani Alonso, Lee Holmes | |
.GUID 21904884-3b46-4b37-b388-6a9958592401 | |
.DESCRIPTION Este script es capaz de generar y renovar automaticamente los certificados SSL en sitios alojados en Microsoft Azure. Basado en el script original de Lee Holmes, realizando una serie de correcciones y mejoras que automatiza el correcto proceso en Azure Automation. (by Dani Alonso). | |
.MANUAL https://w.itpro.es/ssl-spa | |
.TAGS LetsEncrypt SSL Azure Linux Windows Automation | |
#> | |
param( | |
[Parameter(Mandatory)] | |
[String] $Credential, | |
[Parameter(Mandatory)] | |
[String] $Domain, | |
[Parameter(Mandatory)] | |
[String] $RegistrationEmail, | |
[Parameter(Mandatory)] | |
[String] $ResourceGroup, | |
[Parameter(Mandatory)] | |
[String] $WebApp, | |
[String] $SubscriptionId, | |
[Switch] $UseUnixFileVerification | |
) | |
Set-StrictMode -Version Latest | |
function GetSafeFilename | |
{ | |
param( | |
$BasePath = ".", | |
$Text, | |
$Extension = ".txt" | |
) | |
$invalidChars = [IO.Path]::GetInvalidFileNameChars() | |
$invalidCharsRegex = "[" + (-join ($invalidChars | % { [Regex]::Escape($_) })) + "]" | |
$baseFilename = $Text -replace $invalidCharsRegex,'_' | |
$reservedDeviceNames = -split "CON PRN AUX NUL COM1 COM2 COM3 COM4 COM5 COM6 COM7 COM8 COM9 LPT1 LPT2 LPT3 LPT4 LPT5 LPT6 LPT7 LPT8 LPT9" | |
if($baseFilename -in $reservedDeviceNames) | |
{ | |
$baseFilename = "_" + $baseFilename | |
} | |
$baseFilename = $baseFilename.Substring(0, [Math]::Min(50, $baseFilename.Length)) | |
$counter = 1 | |
$fileName = $baseFilename + $Extension | |
while(Test-Path (Join-Path $BasePath $fileName)) | |
{ | |
$filename = $baseFilename + "_${counter}${Extension}" | |
$counter++ | |
} | |
$fileName.Trim() | |
} | |
function PublishWebsiteFile | |
{ | |
param( | |
[Parameter(Mandatory)] | |
$ResourceGroup, | |
[Parameter(Mandatory)] | |
$WebApp, | |
[Parameter(Mandatory)] | |
$PublishSettingsFile, | |
[Parameter(Mandatory)] | |
$RemotePath, | |
[Parameter(Mandatory)] | |
$FileContent | |
) | |
$RemotePath = $RemotePath.Trim("/\") | |
$publishSettings = [xml] (Get-Content $PublishSettingsFile -Raw) | |
$ftpPublishSettings = $publishSettings.publishData.publishProfile | ? publishMethod -eq MSDeploy | |
$username = $ftpPublishSettings.userName | |
$password = $ftpPublishSettings.userPWD | |
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password))) | |
$apiBaseUrl = "https://$WebApp.scm.azurewebsites.net/api" | |
Invoke-RestMethod -Uri "$apiBaseUrl/vfs/site/wwwroot/$RemotePath" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo); 'If-Match' = '*'} -Method PUT -Body $FileContent | |
} | |
$outputDirectory = GetSafeFilename -Text $Domain -Extension "" | |
if(-not (Test-Path $outputDirectory)) | |
{ | |
$null = New-Item -Type Directory $outputDirectory | |
} | |
Write-Progress "Creating Let's Encrypt registration" | |
if(-not (Get-AcmeVault)) | |
{ | |
$null = Initialize-ACMEVault -BaseURI https://acme-v01.api.letsencrypt.org/ | |
} | |
$identifier = -join (([int][char]'a'..[int][char]'z') | Get-Random -Count 10 | % { [char] $_ }) | |
$null = New-ACMERegistration -Contacts mailto:$RegistrationEmail -AcceptTos | |
$null = New-ACMEIdentifier -Dns $domain -Alias $identifier | |
Write-Progress "Receiving challenge" | |
$completedChallenge = Complete-ACMEChallenge -Ref $identifier -Challenge http-01 -Handler manual -Regenerate | |
$challengeAnswer = ($completedChallenge.Challenges | Where-Object { $_.HandlerName -eq "manual" }).Challenge | |
$key = $challengeAnswer.FilePath | |
$target = "$key/index.html" | |
if($UseUnixFileVerification) { $target = $key } | |
Write-Progress "Uploading key and challenge to $domain/$target" | |
$myCredential = Get-AutomationPSCredential -Name $Credential | |
Add-AzureRmAccount -Credential $myCredential | |
if($SubscriptionId) | |
{ | |
Write-Progress "Changing to subscription id $SubscriptionId" | |
Select-AzureRmSubscription -SubscriptionId $SubscriptionId | |
} | |
$mysubscription=(Get-AzureRmContext).Subscription.Id | |
$mytenant = (Get-AzureRmContext).Subscription.TenantId | |
Write-Progress "SubscriptionId is $mysubscription" | |
Write-Progress "TenantId is $mytenant" | |
Add-AzureRmAccount -TenantId $mytenant -SubscriptionId $mysubscription -Credential $myCredential | |
$tempFile = New-TemporaryFile | |
try | |
{ | |
$null = Get-AzureRmWebAppPublishingProfile -ResourceGroupName $ResourceGroup -Name $WebApp -OutputFile $tempFile | |
PublishWebsiteFile -ResourceGroup $ResourceGroup -WebApp $WebApp -PublishSettingsFile $tempFile -RemotePath $target -FileContent $challengeAnswer.FileContent | |
} | |
finally | |
{ | |
Remove-Item $tempFile | |
} | |
$counter = 0 | |
Write-Progress "Waiting for challenge verification" -PercentComplete ($counter++) | |
$challenge = Submit-ACMEChallenge -Ref $identifier -ChallengeType http-01 | |
while ($challenge.Status -eq "pending") | |
{ | |
Start-Sleep -m 500 | |
Write-Progress "Waiting for challenge verification" -PercentComplete ($counter++) | |
$challenge = Update-ACMEIdentifier -Ref $identifier | |
} | |
if($challenge.Status -eq "valid") | |
{ | |
$rawPassword = -join (([int][char]'a'..[int][char]'z') | Get-Random -Count 20 | % { [char] $_ }) | |
$certIdentifier = -join (([int][char]'a'..[int][char]'z') | Get-Random -Count 10 | % { [char] $_ }) | |
New-ACMECertificate -Identifier $identifier -Alias $certIdentifier -Generate | |
$certificateInfo = Submit-ACMECertificate -Ref $certIdentifier | |
Write-Progress "Waiting for IssuerSerialNumber to be issued" | |
while(-not ((Test-Path variable:\certificate) -or $certificateInfo.IssuerSerialNumber)) | |
{ | |
Start-Sleep -m 500 | |
$certificateInfo = Update-ACMECertificate -Ref $certIdentifier | |
} | |
$outputFile = Join-Path $pwd cert1-all.pfx | |
$null = Get-ACMECertificate -Ref $certIdentifier -ExportPkcs12 $outputFile -CertificatePassword $rawPassword | |
Get-Item $outputFile | |
New-AzureRmWebAppSSLBinding -ResourceGroupName $ResourceGroup -WebAppName $WebApp -CertificateFilePath $outputFile -CertificatePassword $rawPassword -Name $Domain | |
} | |
else | |
{ | |
Write-Error (("Certificate generation failed. Status is '{0}', can't continue as it is not 'valid'. " + | |
"Let's Encrypt could not retrieve the expected content from '$domain/$target'") -f $challenge.Status) | |
$challenge | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment