Giter Site home page Giter Site logo

Comments (12)

glatzert avatar glatzert commented on July 22, 2024

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.

 avatar commented on July 22, 2024

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.

 avatar commented on July 22, 2024

For your review. Let me know if you need more info. Thanks in advance.

https://gist.github.com/johnsonl317/9cb68fce12e64dde8f207343c644a361

from acme-ps.

glatzert avatar glatzert commented on July 22, 2024

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.

 avatar commented on July 22, 2024

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.

 avatar commented on July 22, 2024

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.

glatzert avatar glatzert commented on July 22, 2024

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.

 avatar commented on July 22, 2024

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.

glatzert avatar glatzert commented on July 22, 2024

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.

 avatar commented on July 22, 2024

Sorry, I don't understand what you mean?

from acme-ps.

glatzert avatar glatzert commented on July 22, 2024

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.

lejohnson0317 avatar lejohnson0317 commented on July 22, 2024

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:

  1. Reads the certificates stored in a keyvault
  2. Iterates through each certificate found
  3. Determines if the certificate expires in 30 days or less
  4. If they do, it grabs the info from the stored certificate
  5. With the information, it starts the renewal process
  6. 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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.