Comments (12)
The authorization is just an object that's send from the ACME Server. It contains Wildcard: true
or false
.
Also the challenges are reduced, as wildcard requires DNS01 challenge.
from acme-ps.
Thank you. I'm getting the following error now:
OperationStopped: Server returned Problem (Status: 403). Type: urn:ietf:params:acme:error:orderNotReady Order's status ("invalid") is not acceptable for finalization
I'm guessing the following code to see the error goes after the $authz loop and immediately after the "# Wait a little bit and update the order, until we see the status 'ready' or 'invalid'" section?
if($order.Status -ieq ("invalid")) {
$order | Get-ACMEAuthorizationError -State $acmeStateDir;
throw "Order was invalid";
}
That's where I'm stuck. Unfortunately, I've hit the limit for cert requests. Can this be run against the Let's Encrypt staging systems?
from acme-ps.
For your review. Let me know if you need more info. Thanks in advance.
https://gist.github.com/johnsonl317/9cb68fce12e64dde8f207343c644a361
from acme-ps.
You can use the staging system Get-AcmeServiceDirectory
has a switch for that.
About your script: that might be a race condition, since your loop removes TXT records and your cert contains both the root and it's wildcard.
There's also a CmdLet to get the specific error (im on mobile and can't look it up now)
from acme-ps.
So it looks like you are 100% correct about the txt record being the issue. My skill set is not quite where it needs to be to figure out how to work around the issue. I'm using DNS-01 in Azure to create the txt record for the challenge.
My goal is to renew a root cert and a wild-card cert using subject alternate names. Here is how it looks from the cert stored in a keyvault.
SubjectName : CN=staging.eam-echos.io
DnsNames : {*.staging.eam-echos.io, staging.eam-echos.io}
What I'm stuck with is the fact that the script wants to create two challenge texts using the same name which is in the foreach($authz in $authorizations)
loop.
The first loop through works fine, the txt record is created with the proper content.
Challenge Data:
Type : dns-01
Token : 1xcXZZHKWHd1duuZDuTVq4-h3zI-iWI2BUJ5mLn8RC0
TxtRecordName : _acme-challenge.staging.eam-echos.io
Content : D-DhsZ-2-nJMREfHhYIyIEzySk46MukeDHS1qFkxbiI
Id : /subscriptions/bc7d55a2-39ea-48f7-83b9-e1f4cc0b992b/resourceGroups/rg-eam-prod-zeus-coreinfra/providers/Microsof
t.Network/dnszones/staging.eam-echos.io/TXT/_acme-challenge
Name : _acme-challenge
ZoneName : staging.eam-echos.io
ResourceGroupName : rg-eam-prod-zeus-coreinfra
Ttl : 300
Etag : 88b617cb-68cd-4a0d-89e8-1e53f8daa418
RecordType : TXT
TargetResourceId :
Records : {D-DhsZ-2-nJMREfHhYIyIEzySk46MukeDHS1qFkxbiI}
Metadata :
ProvisioningState : Succeeded
When it runs through to create the challenge for the second SAN name, it can't create a new record because it already exists. If I try to delete the txt file from the first pass and let it create the second txt file, the second cert gets marked invalid.
I'm sure this is simply programming logic I'm not understanding. Any ideas?
from acme-ps.
I've made some changes based on this issue posted by GeorgeSchiro: #127
By borrowing some of his code, it seems I'm closer to getting this thing to work. My issue now is the challenge is stuck in pending and I'm not sure why.
I made my biggest changes to the script on lines 90-143. https://gist.github.com/johnsonl317/9d77910f1ec05aab1ce66f47f11aae33
Order from script:
Status : pending
Expires : 05/31/2023 04:18:06
NotBefore :
NotAfter :
Identifiers : {dns:*.staging.eam-echos.io, dns:staging.eam-echos.io}
AuthorizationUrls : {https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/6603934044,
https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/6603934054}
FinalizeUrl : https://acme-staging-v02.api.letsencrypt.org/acme/finalize/103451844/8898314814
CertificateUrl :
CSROptions : AcmeCsrOptions
1st Auth URL (Valid):
{
"identifier": {
"type": "dns",
"value": "staging.eam-echos.io"
},
"status": "valid",
"expires": "2023-06-23T04:18:18Z",
"challenges": [
{
"type": "dns-01",
"status": "valid",
"url": "https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/6603934044/2Kr2bw",
"token": "RatAiO_Md84r24MAyzsA_vR0eBOnZdbNVjIZRnbJqVE",
"validationRecord": [
{
"hostname": "staging.eam-echos.io"
}
],
"validated": "2023-05-24T04:18:18Z"
}
],
"wildcard": true
}
2nd Auth (Pending):
{
"identifier": {
"type": "dns",
"value": "staging.eam-echos.io"
},
"status": "pending",
"expires": "2023-05-31T04:18:06Z",
"challenges": [
{
"type": "http-01",
"status": "pending",
"url": "https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/6603934054/xcF1Bg",
"token": "w3AZoW2MItc3e9i50Eqb6RT2qnPpDI5uPKTNU2AyTas"
},
{
"type": "dns-01",
"status": "pending",
"url": "https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/6603934054/g2LXVA",
"token": "w3AZoW2MItc3e9i50Eqb6RT2qnPpDI5uPKTNU2AyTas"
},
{
"type": "tls-alpn-01",
"status": "pending",
"url": "https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/6603934054/sq19qA",
"token": "w3AZoW2MItc3e9i50Eqb6RT2qnPpDI5uPKTNU2AyTas"
}
]
}
Not sure why it's trying HTTP and TLS types?
Either way, I'm still quite sure this is logic error. I must be doing something out of order or I'm missing a step. Thanks for the help and education.
from acme-ps.
After you create the order, you need to loop through the AuthZ elements.
For each of them, you have to select a challenge, fulfill it and signal "it's ready" to the ACME Server.
If you do that, ACME will send you an updated authorization element, containing only the selected challenge.
You can recheck (get-acmeauthorizatiin) the AuthZ with the server to get the current status.
So essentially (pseudocode)
- create order
- get AuthZ
- foreach AuthZ
- prepare challenge response
- signal server challenge ready
- reload auth until challenge valid
I wanted to check the ACME specs, if it allows multiple dns tokens in a single TXT record, but I'm on mobile currently and RFC on mobile is no fun 😅
from acme-ps.
Had the same thought last night after I posted my comment. I redid that part of my script. Here was my logic.
- Create Order
- get Authz
- foreach Authz
- prep first challenge
- grab challenge info
- look for existing DNS challenge record
- if exists, update TXT record
- else, create TXT record
- Complete challenge
- Repeat for next challenge
- Wait for valid status
When I use this method, I get one valid challenge and one invalid challenge. The invalid challenge says the TXT record is incorrect.
"type": "urn:ietf:params:acme:error:unauthorized",
"detail": "During secondary validation: Incorrect TXT record \"aYBHStSp02rsF8OK3YOzlmvwAIIxtXE7VT22tgG2nOc\" found at _acme-challenge.staging.eam-echos.io",
"status": 403
If I move the "wait for valid status" snippet inside the for loop, I end up in a never ending pending status.
I'm assuming that each authorization has its own TXT record value which is why I'm updating the DNS record for each authz. Am I wrong in this thinking?
Challenge:
ResourceUrl : https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/6610279884
Status : pending
Expires : 5/31/2023 3:57:05 PM +00:00
Identifier : dns:staging.eam-echos.io
Challenges : {AcmeChallenge}
Wildcard : True
ResourceUrl : https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/6610279894
Status : pending
Expires : 5/31/2023 3:57:05 PM +00:00
Identifier : dns:staging.eam-echos.io
Challenges : {AcmeChallenge, AcmeChallenge, AcmeChallenge}
Wildcard : False
Updated code section:
# Fetch the authorizations for that order
$authorizations = @(Get-ACMEAuthorization -State $state -Order $order)
foreach($authz in $authorizations) {
#Start challenge process
#$challenge = Get-ACMEChallenge $state $authorizations[$SanMap[0]] "dns-01"
# Select a challenge to fullfill
$challenge = Get-ACMEChallenge $state $authZ "dns-01";
# Inspect the challenge data
"Challenge Data:"
$challenge.Data;
$challengeRecordName = $challenge.Data.TxtRecordName
$challengeNonce = $challenge.Data.Content
$challengeHostName = $challengeRecordName.Replace("." + $ZoneName, "")
# Update any existing TXT record that conflicts with the challenge
$oldChallengeRecordSet = `
Get-AzDnsRecordSet `
-Name $challengeHostName `
-RecordType TXT `
-ResourceGroupName $ZoneResourceGroup `
-ZoneName $ZoneName `
-ea SilentlyContinue
if ($oldChallengeRecordSet -ne $null) {
"Updating existing challenge record set $challengeRecordName"
$recordSet = Get-AzDnsRecordSet -name $challengeHostName -RecordType TXT -ZoneName $ZoneName -ResourceGroupName $ZoneResourceGroup
$recordSet.Records[0].Value = $challengeNonce
set-azdnsrecordset -recordset $recordSet
} else {
# Create the TXT record requested by the challenge
$challengeRecords = @()
$challengeRecords += New-AzDnsRecordConfig -Value $challengeNonce
New-AzDnsRecordSet `
-Name $challengeHostName `
-RecordType TXT `
-ResourceGroupName $ZoneResourceGroup `
-TTL 300 `
-ZoneName $ZoneName `
-DnsRecords $challengeRecords
}
"*** Waiting 10 seconds for DNS propagation..."
Start-Sleep -Seconds 10;
# Signal the ACME server that the challenge is ready
$challenge | Complete-ACMEChallenge $state;
}
# Wait a little bit and update the order, until we see the states
while ($order.Status -notin ("ready", "invalid")) {
Start-Sleep -Seconds 10;
$order | Update-ACMEOrder $state -PassThru;
}
from acme-ps.
If I move the "wait for valid status" snippet inside the for loop, I end up in a never ending pending status.
If you do that, you'll need to update the Authorization - not the order.
from acme-ps.
Sorry, I don't understand what you mean?
from acme-ps.
Sorry, I don't understand what you mean?
Disregard that ;)
I read up on the general problem and found this: https://serverfault.com/questions/1095321/can-i-set-multiple-txt-record-on-my-dns-in-order-to-proove-the-ownership-of-a#:~:text=Yes%2C%20any%20name%20on%20the%20DNS%20can%20have,entity%20requesting%20the%20presence%20of%20those%20TXT%20records.
And refered here: https://www.rfc-editor.org/rfc/rfc8555 (Page 66, Point 3).
So the solution to your problem is delete the TXT records before you answer the authorizations, then add all the required tokens to multiple TXT records with the same name. The server will check them all.
from acme-ps.
Thomas,
Thank you so much!!! You gave me the push I needed to make it through this.
My script is set up as an automation account in Azure. It does the following:
- Reads the certificates stored in a keyvault
- Iterates through each certificate found
- Determines if the certificate expires in 30 days or less
- If they do, it grabs the info from the stored certificate
- With the information, it starts the renewal process
- Once completed, the script uploads the certificate to the key vault
Feel free to use or share any of this code as you wish. Most of it's yours anyway. :-)
You can close this as completed.
https://gist.github.com/lejohnson0317/bfd550642609c2731c96b6a011376994
from acme-ps.
Related Issues (20)
- Order shows that cert expires in 6 days, but cert shows 90 days? HOT 3
- [Improvement] Allow DirectoryUrl to be passed to revocation, to omit the state object
- [Improvement] Add state reference to order
- [BUG]? Full chain export seems to be exporting in the wrong order HOT 4
- [BUG] Chain not included for specific instance.. HOT 1
- [Improvement] Exporting x509 certs/keys as PEM HOT 4
- Exception calling "GetResult" with "0" argument(s): "An error occurred while sending the request." HOT 6
- Certificate not working on older Android after 29.9.2021 HOT 2
- New-AcmePSKey invalid ValidateSet for RSAKeySize HOT 1
- DNS-01 HOT 10
- New Order / Old Account HOT 5
- Are SHA-1 self signatures being used to issue CSRs? HOT 1
- HTTP-01 Challenge File Not Getting Created HOT 3
- [BUG] The certificate chain seems to be out of order in 1.5.2. Versions 1.5.3-beta, and 1.5.4 Fails to run. HOT 4
- [BUG] Some of the *ToExport keys are missing from the module manifest HOT 2
- [BUG] v1.5.6 Export-Certificate "value cannot be null" HOT 10
- Cannot export non-exportable private key HOT 1
- [BUG] When using New-ACMEAccount with previous AccountKey it errors with Get-Account HOT 1
- [BUG] The exported PFX certificate doesn't have the full Let's Encrypt chain HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from acme-ps.