GetSSL-LetsEncrypt.ps1
#requires -Modules AcmeSharp, Azure, AzureRM.Websites <#PSScriptInfo .VERSION 1.4.2 .TITLE GetSSL Let's Encrypt .AUTHOR Dani Alonso, Lee Holmes .GUID 21904884-3b46-4b37-b388-6a9958592401 .DESCRIPTION Script capaz de generar y renovar automaticamente los certificados SSL en sitios alojados en Microsoft Azure. Basado en el script original de Register-LetsEncryptCertificate (by Lee Holmes), realizando una serie de correcciones y mejoras que automatiza el correcto proceso (by Dani Alonso). .MANUAL (proximamente) .TAGS LetsEncrypt SSL Azure Linux Windows Automation #> param( [Parameter(Mandatory)] [String] $Domain, [Parameter(Mandatory)] [String] $RegistrationEmail, [Parameter(Mandatory)] [String] $ResourceGroup, [Parameter(Mandatory)] [String] $WebApp, [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" ####################################################################### ## ACCION REQUERIDA! Incluir tu credencial de Automation: $myCredential�= Get-AutomationPSCredential -Name�'<CREDENCIAL>' ## Fin de area configurable. ####################################################################### Add-AzureRmAccount -Credential�$myCredential $mysubscription�= (Get-AzureRmContext).Subscription.Id $mytenant�= (Get-AzureRmContext).Subscription.TenantId 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 } |