Skip to content

Commit

Permalink
Added AddrTools plugin and guide (#574)
Browse files Browse the repository at this point in the history
  • Loading branch information
rmbolger authored Oct 15, 2024
1 parent 6418e1c commit 96502d5
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 0 deletions.
217 changes: 217 additions & 0 deletions Posh-ACME/Plugins/AddrTools.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
function Get-CurrentPluginType { 'dns-01' }

function Add-DnsTxt {
[CmdletBinding()]
param(
[Parameter(Mandatory,Position=0)]
[string]$RecordName,
[Parameter(Mandatory,Position=1)]
[string]$TxtValue,
[Parameter(Mandatory)]
[securestring]$AddrToolsSecret,
[string]$AddrToolsHost='challenges.addr.tools',
[Parameter(ValueFromRemainingArguments)]
$ExtraParams
)

$secPlain = [pscredential]::new('a',$AddrToolsSecret).GetNetworkCredential().Password

$queryParams = @{
Uri = 'https://{0}' -f $AddrToolsHost
Method = 'POST'
Body = @{
secret = 'REDACTED'
txt = $TxtValue
}
Verbose = $false
ErrorAction = 'Stop'
}
# log with redacted secret
Write-Verbose "Adding a TXT record for $RecordName with value $TxtValue"
Write-Debug "$($queryParams.Method) $($queryParams.Uri)`n$($queryParams.Body|ConvertTo-Json)"

try {
$queryParams.Body.secret = $secPlain
$resp = Invoke-RestMethod @queryParams @script:UseBasic
if (-not $resp.Trim() -eq 'OK') {
Write-Warning "Addr.Tools returned: $($resp.Trim())"
}
} catch { throw }

<#
.SYNOPSIS
Add a DNS TXT record to challenges.addr.tools
.DESCRIPTION
Description for challenges.addr.tools
.PARAMETER RecordName
The fully qualified name of the TXT record.
.PARAMETER AddrToolsSecret
The secret associated with your challenges.addr.tools subdomain.
.PARAMETER AddrToolsHost
If self-hosting, domain name of your challenges.addr.tools equivalent (e.g. challenges.example.com)
.PARAMETER TxtValue
The value of the TXT record.
.PARAMETER ExtraParams
This parameter can be ignored and is only used to prevent errors when splatting with more parameters than this function supports.
.EXAMPLE
Add-DnsTxt '_acme-challenge.example.com' 'txt-value'
Adds a TXT record for the specified site with the specified value.
#>
}

function Remove-DnsTxt {
[CmdletBinding()]
param(
[Parameter(Mandatory,Position=0)]
[string]$RecordName,
[Parameter(Mandatory,Position=1)]
[string]$TxtValue,
[Parameter(Mandatory)]
[securestring]$AddrToolsSecret,
[string]$AddrToolsHost='challenges.addr.tools',
[Parameter(ValueFromRemainingArguments)]
$ExtraParams
)

$secPlain = [pscredential]::new('a',$AddrToolsSecret).GetNetworkCredential().Password

$queryParams = @{
Uri = 'https://{0}' -f $AddrToolsHost
Method = 'DELETE'
Body = @{
secret = 'REDACTED'
txt = $TxtValue
}
Verbose = $false
ErrorAction = 'Stop'
}
# log with redacted secret
Write-Verbose "Deleting $RecordName with value $TxtValue"
Write-Debug "$($queryParams.Method) $($queryParams.Uri)`n$($queryParams.Body|ConvertTo-Json)"

try {
$queryParams.Body.secret = $secPlain
$resp = Invoke-RestMethod @queryParams @script:UseBasic
if (-not $resp.Trim() -eq '') {
Write-Warning "Addr.Tools returned: $($resp.Trim())"
}
} catch { throw }

<#
.SYNOPSIS
Remove a DNS TXT record from <My DNS Server/Provider>
.DESCRIPTION
Description for <My DNS Server/Provider>
.PARAMETER RecordName
The fully qualified name of the TXT record.
.PARAMETER TxtValue
The value of the TXT record.
.PARAMETER AddrToolsSecret
The secret associated with your challenges.addr.tools subdomain.
.PARAMETER AddrToolsHost
If self-hosting, domain name of your challenges.addr.tools equivalent (e.g. challenges.example.com)
.PARAMETER ExtraParams
This parameter can be ignored and is only used to prevent errors when splatting with more parameters than this function supports.
.EXAMPLE
Remove-DnsTxt '_acme-challenge.example.com' 'txt-value'
Removes a TXT record for the specified site with the specified value.
#>
}

function Save-DnsTxt {
[CmdletBinding()]
param(
[Parameter(ValueFromRemainingArguments)]
$ExtraParams
)
<#
.SYNOPSIS
Not required.
.DESCRIPTION
This provider does not require calling this function to commit changes to DNS records.
.PARAMETER ExtraParams
This parameter can be ignored and is only used to prevent errors when splatting with more parameters than this function supports.
#>
}

############################
# Helper Functions
############################

# https://challenges.addr.tools/

function Get-AddrToolsCNAME {
[CmdletBinding()]
param(
[Parameter(Mandatory,Position=0)]
[string[]]$Domain,
[Parameter(Mandatory,Position=1)]
[securestring]$AddrToolsSecret,
[string]$AddrToolsHost='challenges.addr.tools'
)

$challengeSub = Get-AddrToolsSubdomain $AddrToolsSecret -AddrToolsHost $AddrToolsHost

# Create a unique list of domains after stripping wildcards
$Domain | Select-Object @{
L='FQDN'; E={ '_acme-challenge.{0}' -f $_.TrimStart('*.') }
},@{
L='Target';E={ $challengeSub }
} | Select-Object -Unique *
}

function Get-AddrToolsSubdomain {
[CmdletBinding()]
param(
[Parameter(Mandatory,Position=0)]
[securestring]$AddrToolsSecret,
[string]$AddrToolsHost='challenges.addr.tools'
)

if (-not $script:UseBasic) {
$script:UseBasic = @{UseBasicParsing=$true}
}

# The subdomain for a give secret is the SHA-224 hash of the secret
# prepended to the challenges FQDN. So by default:
# <sha224>.challenges.addr.tools
#
# Until we have a local SHA-224 hashing implementation, you can get this
# value by querying the endpoint with just the secret and no other arguments.

$secPlain = [pscredential]::new('a',$AddrToolsSecret).GetNetworkCredential().Password

$queryParams = @{
Uri = 'https://{0}' -f $AddrToolsHost
Method = 'POST'
Body = @{
secret = $secPlain
}
Verbose = $false
ErrorAction = 'Stop'
}
try {
Write-Debug "POST $($queryParams.Uri)"
$resp = Invoke-RestMethod @queryParams @script:UseBasic
} catch { throw }

return $resp.Trim().TrimEnd('.')
}
1 change: 1 addition & 0 deletions Posh-ACME/Private/Import-PluginDetail.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function Import-PluginDetail {
$script:Plugins = @{
'AcmeDns' = [pscustomobject]@{PSTypeName = 'PoshACME.PAPluginDetail'; ChallengeType = 'dns-01'; Path = ''; Name = 'AcmeDns'}
'Active24' = [pscustomobject]@{PSTypeName = 'PoshACME.PAPluginDetail'; ChallengeType = 'dns-01'; Path = ''; Name = 'Active24'}
'AddrTools' = [pscustomobject]@{PSTypeName = 'PoshACME.PAPluginDetail'; ChallengeType = 'dns-01'; Path = ''; Name = 'AddrTools'}
'Akamai' = [pscustomobject]@{PSTypeName = 'PoshACME.PAPluginDetail'; ChallengeType = 'dns-01'; Path = ''; Name = 'Akamai'}
'Aliyun' = [pscustomobject]@{PSTypeName = 'PoshACME.PAPluginDetail'; ChallengeType = 'dns-01'; Path = ''; Name = 'Aliyun'}
'All-Inkl' = [pscustomobject]@{PSTypeName = 'PoshACME.PAPluginDetail'; ChallengeType = 'dns-01'; Path = ''; Name = 'All-Inkl'}
Expand Down
52 changes: 52 additions & 0 deletions docs/Plugins/AddrTools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
title: AddrTools

# How To Use the AddrTools DNS Plugin

This plugin works against [challenges.addr.tools](https://challenges.addr.tools/) which is a specialized provider purpose built for validating dns-01 challenges using CNAME aliases. It is part of the larger [addr.tools](https://www.addr.tools/) open source project which means you can self-host your own instance. But the default configuration works against the author's public instance.

## Setup

It may help to read the [Using DNS Challenge Aliases](../Guides/Using-DNS-Challenge-Aliases.md) guide to better understand how CNAME records work with ACME challenges. Most importantly, there will be a one-time CNAME record creation for each name in the certificate you are requesting.

There is a helper function in the plugin to help determine which CNAME records to create. It uses the same parameters that the AddrTools plugin uses. So use the following code to create an appropriate `$pArgs` variable and a `$domains` variable that contains the list of domains in your certificate.

```powershell
$pArgs = @{
AddrToolsSecret = Read-Host -Prompt "Enter Secret" -AsSecureString
AddrToolsHost = 'challenges.addr.tools' # optional unless self-hosting
}
$domains = 'example.com','www.example.com'
```

Now run the following to load and run the helper function that will tell you what CNAME records to create.

```powershell
Import-Module Posh-ACME
. (Join-Path (Get-Module Posh-ACME).ModuleBase "Plugins\AddrTools.ps1")
Get-AddrToolsCNAME $domains @pArgs
```

The output will look similar to this depending on how many unique domains you have:

```
FQDN Target
---- ------
_acme-challenge.example.com 7870508034f01f4a28d86812fa7bd10a03cb7e7e6ddda0ddb95ff771.challenges.addr.tools
_acme-challenge.www.example.com 7870508034f01f4a28d86812fa7bd10a03cb7e7e6ddda0ddb95ff771.challenges.addr.tools
```

## Using the Plugin

Once all necessary CNAME records are created, you can use the same `$pArgs` value from setup with the plugin. `AddrToolsSecret` is always required and `AddrToolsHost` is only required if you're self-hosting your own instance at a different domain.

You'll also need to use the `-DnsAlias` parameter from New-PACertificate with the Target value from the CNAME records.

```powershell
# set this to the CNAME Target value from setup
$target = 'xxxxxxxxxxxxxxxxxx.challenges.addr.tools'
$pArgs = @{
AddrToolsSecret = (Read-Host 'Access Token' -AsSecureString)
}
New-PACertificate example.com -Plugin AddrTools -PluginArgs $pArgs -DnsAlias $target
```
1 change: 1 addition & 0 deletions docs/Plugins/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Plugin | Provider | Guide | PS Core Compatible
------ | -------- | ----- | :----------------:
AcmeDns | [acme-dns](https://github.com/joohoi/acme-dns) | [Usage Guide](AcmeDns.md) | :white_check_mark:
Active24 | [Active24](https://Active24.com) | [Usage Guide](Active24.md) | :white_check_mark:
AddrTools | [addr.tools](https://challenges.addr.tools) | [Usage Guide](AddrTools.md) | :white_check_mark:
Akamai | [Akamai Edge DNS](https://www.akamai.com/products/edge-dns) | [Usage Guide](Akamai.md) | :white_check_mark:
Aliyun | [Aliyun (Alibaba Cloud)](https://www.alibabacloud.com/product/dns) | [Usage Guide](Aliyun.md) | :white_check_mark:
All-Inkl | [All-Inkl](https://all-inkl.com/) | [Usage Guide](All-Inkl.md) | :white_check_mark:
Expand Down

0 comments on commit 96502d5

Please sign in to comment.