delanguageRegister | Login
fingerprint

Login

call

Contact

help

Help

ACME: Create LE certificate

1 ratings
CertificateLets Encryptposh-acmeAzureDNS

What it does

Diese Ressource automatisiert die Ausstellung eines Lets Encrypt Zertifikats im Zusammenhang einer DNS Zone, welche bei Azure liegt. Der User, der hier verwendet wird, muss in Azure / Entra ID die Berechtigung besitzen DNS Einträge zu verwalten (speziell anlegen und ändern von TXT Records)

Description

Create a Lets Encrypt Certificate with Posh-ACME

Creation Details

  • Author: Sebastian
  • Created: 22.11.2023 21:44:23
  • Last modification: 22.11.2023 21:44:23
Resource Image:

Input Parameters

Name: domain

Description: enter the full domain name (fqdn) for the certificate

Name: leenv

Description: choose the production or the stage environment for Lets Encrypt

Name: acmecontact

Description: choose the LE ACME Account

Resource Parameters

Name: appid

Description: this AppId is the Application ID from the Azure App

Name: tenantid

Description: The Azure Active Directory / Entra ID Tenant ID

Code

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$false)]
    [string]$installPath="not-set",
    [Parameter(Mandatory=$false)]
    [string]$jobId="not-set",
    [Parameter(Mandatory=$false)]
    [string]$action="not-set"
)

$debugScript = 0;
if ($debugScript -eq 1) {
    write-host "debugging mode on" -f yellow
    $installPath = "C:\addy\" #Debugging
    $jobId = "jobXXXXXXX" #only for debugging
}

# Only use TLSv1.1 and TLSv1.2
$AllProtocols = [System.Net.SecurityProtocolType]'Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols

$errorCount = 0 # counting errors. If this variable is greater than 0, the script should not run
# loading functions
write-host "$(get-date -f  "dd.MM.yyyy HH:mm:ss") include functions"
if (test-path "$($installPath)scripts\functions.global.ps1") {
    write-host "Functions-File exists"
    import-module "$($installPath)scripts\functions.global.ps1" -force
} else {
    write-host "Functions file do not exist. Increasing ErrorCounter." 
    $errorCount++
}

set-location $installPath # setting the location
$machineId = Get-MachineId # generate a unique machineID
write-addylog "All parameter initialized" # write log

# Handling with parameters
if ($debugScript -eq 0) {
    # Load parameter information about this job
    $jsonBody = @{ localCurrentTime = $(get-date -f  "dd.MM.yyyy HH:mm:ss")}
    $body = (ConvertTo-Json -Depth 4 $jsonBody) 
    $resultInitializeInvoke = Invoke-RestMethod -Uri "$addyhostaddress/api/v1/heartbeat-consumer?action=checkforjobs&jobId=$jobId" -Method POST -Body $body -ContentType 'application/json; charset=UTF-8' -Headers @{"Publickey"="$publickey";"Privatekey"="$privatekey";"Machineid" = "$machineId"} # -Headers @{'Authorization'='Basic YWRtaW46YWRtaW4'}
    # take a look in the answer from the addy with $resultInitializeInvoke
    # Example Jobname: $resultInitializeInvoke.jobDataArray.businessAutomationJobsPendingJobname 
    
    # Example to get input parameter
    # $addyPayloadResourceInput = $resultInitializeInvoke.jobDataArray.businessAutomationJobsPendingPayload.payload

    # Example to get a specific input parameter
    # [string]$aStringParameter = $addyPayloadResourceInput.aStringParameter # "aStringParameter" is definied in the Input Parameter. This are now a parameter for this script 
    # $aStringParameter = $aStringParameter.trim()
    
    # Example to get resource parameter
    # [string]$ParamAnyString = $resultInitializeInvoke.scriptParameter.anyString #"anyString" is definied in the Resource Parameter. This are now a parameter for this script
    # $ParamAnyString = $ParamAnyString.trim()

    # cast scriptParameter int
    # [int]$ParamaNumber = "$($resultInitializeInvoke.scriptParameter.aNumber)" #"aNumber" is definied in the Resource Parameter. This are now a parameter for this script
}
###################### End header - Start main ############################

# Start: Introducing commands
write-addylog "Start the Script." #-Level "INFO","ERROR", "WARN"
$startOfScript = get-date

write-addylog "Initializing variables"
$errorCount = 0
$error.clear()
# End: Introducing commands

# Start: set a response
$jsonMessageBody = @{  
    message = "working"
    timestamp=$(get-date -f  "dd.MM.yyyy HH:mm:ss")
}
write-addylog "Set a job response. Message to `"working`""
set-JobResponse -jobId $jobId -jsonMessageBody $jsonMessageBody -publickey $publickey -privatekey $privatekey -machineId $machineId
# End: set a response

# Start: load resource parameter
write-addylog "Initializing resource parameter"
$addyPayloadResourceParameter = $resultInitializeInvoke.scriptParameter

#[string]$temp0resourceparameter = $addyPayloadResourceParameter.temp0resourceparameter #"temp0resourceparameter" is definied in the Resource Parameter. This are now a parameter for this script
#$temp0resourceparameter = $temp0resourceparameter.trim()
#write-addylog "[resource parameter] `"temp0resourceparameter`" is set to: $temp0resourceparameter"
# End: load resource parameter

[string]$resourceParameterAppId = $addyPayloadResourceParameter.appid #"appid" is definied in the Resource Parameter. This are now a parameter for this script
$resourceParameterAppId = $resourceParameterAppId.trim()
write-addylog "[resource parameter] `"AppId`" is set to: $resourceParameterAppId"

[string]$resourceParameterTenantId = $addyPayloadResourceParameter.tenantid #"appid" is definied in the Resource Parameter. This are now a parameter for this script
$resourceParameterTenantId = $resourceParameterTenantId.trim()
write-addylog "[resource parameter] `"TenantId`" is set to: $resourceParameterTenantId"

# Start: load input parameter
write-addylog "Initializing input parameter"
$addyPayloadResourceInput = $resultInitializeInvoke.jobDataArray.businessAutomationJobsPendingPayload.payload

#[string]$temp1parameter = $addyPayloadResourceInput.temp1parameter # "temp1parameter" is definied in the Resource input Parameter. This are now a parameter for this script 
#$temp1parameter = $temp1parameter.trim()
#write-addylog "[input parameter] `"temp1parameter`" is set to: $temp1parameter"

[string]$inputParameterDomain = $addyPayloadResourceInput.domain # "domain" is definied in the Resource input Parameter. This are now a parameter for this script 
$inputParameterDomain = $inputParameterDomain.trim()
write-addylog "[input parameter] `"domain`" is set to: $inputParameterDomain"

[string]$inputParameterLeEnv = $addyPayloadResourceInput.leenv # "leenv" is definied in the Resource input Parameter. This are now a parameter for this script 
$inputParameterLeEnv = $inputParameterLeEnv.trim()
write-addylog "[input parameter] `"leenv`" is set to: $inputParainputParameterLeEnvmeterDomain"

[string]$inputParameterAcmeContact = $addyPayloadResourceInput.acmecontact # "acmecontact" is definied in the Resource input Parameter. This are now a parameter for this script 
$inputParameterAcmeContact = $inputParameterAcmeContact.trim()
write-addylog "[input parameter] `"acmecontact`" is set to: $inputParameterAcmeContact"
# End: load input parameter

#
# Start Main part
#

$acmeContact = $inputParameterAcmeContact 
$LeEnv = $inputParameterLeEnv
$domain= $inputParameterDomain

write-addylog "Domain: $domain"
write-addylog "LE Environment: $LeEnv"
write-addylog "Subitted ACME Contact: $acmeContact"

$servicePrincipalAppId = $resourceParameterAppId
$tenantId = $resourceParameterTenantId

write-addylog "AppId: $servicePrincipalAppId"
write-addylog "TenantId: $tenantId"

$DatasetArray = get-addydataset -datasetName "addy-dns-manage-certificates" -username "addy-dns-manage-certificates"
$servicePrincipalPassword = $DatasetArray.credential.GetNetworkCredential().password

# load the module
$ResultLoadModule = LoadModule "Posh-ACME"
if ($ResultLoadModule -eq $true) {
    write-addylog "Posh-ACME module loading successfully"
} else {
    write-addylog "Posh-ACME module loading failed" -level ERROR
    $errorCount++
}

if ($errorCount -eq 0) {

    write-addylog "Creating the credential object"
    $spSecureString = ConvertTo-SecureString $servicePrincipalPassword -AsPlainText -Force
    $psCredentials = New-Object System.Management.Automation.PSCredential ($servicePrincipalAppID, $spSecureString)

    write-host "connecting to Azure Account (with service principal)"
    $az = $NULL
    $az = Connect-AzAccount -ServicePrincipal -Credential $psCredentials -Tenant $tenantId
    if ($az) {
        write-addylog "connect to azure successfully"
    } else {
        write-addylog "connect to azure failed" -level ERROR
        $errorCount++
    }
} #if ($errorCount -eq 0) 

if ($errorCount -eq 0) {
    $error.clear()
    if ($LeEnv -eq "production") {
        $LeServer="LE_PROD"
    } elseif ($LeEnv -eq "staging") {
        $LeServer="LE_STAGE"
    } else {
        $LeServer="LE_STAGE"
    }

    # Configure Posh-ACME server
    write-addylog "Configure LE Server to `"$LeServer`""
    Set-PAServer $LeServer
    Get-PAPlugin Azure

    # Configure Posh-ACME account
    write-addylog "Configure Posh-ACME account. Contact: `"$($acmeContact)`""
    $PaAccount = Get-PAAccount
    if (-not $PaAccount) {
        # New account
        Write-Host "Create New Posh-ACME LE Account"
        $PaAccount = New-PAAccount -Contact $acmeContact -AcceptTOS
    } elseif ($PaAccount.contact -ne "mailto:$acmeContact") {
        # Update account contact
        Write-Host "Set Existing Account ID: $($PaAccount.id), Contact: `"$acmeContact`""
        Set-PAAccount -ID $PaAccount.id -Contact $acmeContact
    }
    if ($error) {
        write-addylog "an error occured. Error: $($error[0])" -level ERROR
        $errorCount++
    } 
} #if ($errorCount -eq 0) 

if ($errorCount -eq 0) {
    # Acquire access token for Azure
    Write-Host "Azure DNS Sub $($az.Context.Subscription.name)"
    $AzAccessToken = $NULL
    $AzAccessToken = $(Get-AzAccessToken -ResourceUrl 'https://management.core.windows.net/').Token

    if ($AzAccessToken) {
        write-addylog "getting access token successfully"
    } else {
        write-addylog "getting access token failed" -level ERROR
        $errorCount++
    }
} #if ($errorCount -eq 0) 

if ($errorCount -eq 0)  {
    # Request certificate
    write-addylog "requesting a new certificate. The certificate creation will create a new TXT record in the DNS Zone and sleep for 120 seconds while DNS changes propagate."
    $pArgs = @{
        AZSubscriptionId = $az.Context.Subscription.Id
        AZAccessToken = $AzAccessToken
    }
    $resNewPACertificate = $NULL
    $resNewPACertificate = New-PACertificate $domain -Plugin Azure -PluginArgs $pArgs -Verbose
    if ($resNewPACertificate) {
        write-addylog "Certificate created: `"$($resNewPACertificate.CertFile)`""
    }

    $PACertificateData = Get-PACertificate | Select-Object *
    if ($PACertificateData) {
        write-host "Certificate expiring date: $($PACertificateData.NotAfter)"
    }
} #if ($errorCount -eq 0) 

write-addylog "disconnecting from azure"
Disconnect-AzAccount

if ($errorCount -eq 0) {
    $messageJobResponse = "done"
} else {
    $messageJobResponse = "failed"
}
$jsonMessageBody = @{  
    message = $messageJobResponse
    timestamp=$(get-date -f  "dd.MM.yyyy HH:mm:ss")
}
write-addylog "Set a job response. Message to `"messageJobResponse`""
set-JobResponse -jobId $jobId -jsonMessageBody $jsonMessageBody -publickey $publickey -privatekey $privatekey -machineId $machineId

###########

# get certificate
# Get-PACertificate -list

# get data from PA Certificate
#Get-PACertificate -name "lecert01.test.cloud.adminsbuddy.com" | select * 

# renew a specific certificate
#Submit-Renewal "lecert01.test.cloud.adminsbuddy.com" -Force

# renew all force
#Submit-Renewal -AllOrders -force

#
# END Main Part
#

# Start: cleanup commands
$EndOfScript = get-date
write-addylog "Start of script: $startOfScript"
write-addylog "End of script: $EndOfScript"
$errorCount = 0
$error.clear()
$addyPayloadResourceInput = ""; $addyPayloadResourceParameter = "" # Reset important variables
# End: cleanup commands


###################### End main - Start footer ############################
# setting the state
if ($debugScript -eq 0) {
    write-addylog "update state of this job to done"
    update-modifiedState -jobId $jobId -modifiedState "done" -publickey $publickey -privatekey $privatekey -machineId $machineId
    Start-Sleep 2 
    write-addylog "End of script reached"
    Start-Sleep 2
    exit
}

Rating

login and obtain the library resource to set a rating.