Skip to content

Releases: haruspexsystems/Ducks-in-a-Row

Ducks in a Row 0.10.0-beta.1

Pre-release

Choose a tag to compare

@lethe377 lethe377 released this 09 Aug 16:27

This is a beta. The installer is not code signed yet, so Windows SmartScreen and
Microsoft Defender will warn you when you run it. Verify the download against
the SHA256 checksum on the release page. A signed 1.0 will follow this beta.
Read the Known Issues section at the foot of these notes before installing.

Verified on Windows Server 2019 and Windows Server 2025. Not verified on
Windows Server 2022 in this release
, and Server 2022 has a servicing floor
that did not exist before; see the .NET 10 entry under Changed.

Added

  • A persistent way to reach the project, at the foot of every dashboard page
    and of the setup wizard (#242). The product collects no telemetry, so every
    word we get back is one an operator chose to send, which makes it our own
    problem if the way to send it is hard to find. It was: the only in app
    feedback link sat on the Settings page, one of four tabs, and GitHub
    Discussions was named in the support documentation but linked nowhere in the
    interface at all. The footer now carries both. The setup wizard carries it
    too, deliberately, because an operator who gives up partway through setup is
    the one we can least afford to lose and the one no other channel will ever
    hear from. Nothing about this sends anything: the feedback link opens a draft
    in the operator's own mail client, with the subject filled in and the body
    left alone so nothing the app knows rides along uninvited, and the
    Discussions link is an ordinary navigation the operator chooses to make,
    carrying rel="noopener noreferrer" so GitHub is not even told where the
    click came from. The Privacy section of the README is unchanged and stays
    true word for word.

  • An Alerts card on the Settings page, so the alerting engine is finally visible
    (#161). The product shipped complete expiry monitoring, email and webhook
    notifiers, and an alert history table, and the dashboard referenced none of
    it, so an operator could not find out whether alerting was on, what thresholds
    were in force, who was being told, or whether sending had been failing. The
    card shows all of that plus the most recent alerts, with failures and their
    error text called out, and it says plainly when monitoring is switched off or
    when monitoring is on with nothing configured to send over, which is the state
    a default install is in. The card also has a Send a test button, which delivers
    over every configured channel and reports per channel success or failure,
    because SMTP fails quietly and an alerting system nobody has seen work is one
    nobody should trust. The test is unmistakable at both ends: the email subject
    leads with [Ducks in a Row TEST] and says on its first line that no
    certificate is expiring, and the webhook payload is the distinct test.alert
    event carrying test: true and no certificate list. It goes through the same
    signing path as a real alert, so it proves the real path rather than a
    shortcut. It writes nothing to the alert history, deliberately: that table has
    no way to mark a row as a test, and a test row would consume a real
    certificate's slot in the unique index and permanently suppress its actual
    warning. Roughly a minute of cooldown sits between tests, shared across
    everyone signed in.

  • Alert configuration is now writable from the Settings page (#162). It could
    previously only be changed by hand editing appsettings.json on the server,
    which is why the card above named that file in four places. Expiry monitoring,
    the check interval, the warning thresholds, the SMTP relay host, the sender
    address and the recipient list are all editable and saved through the settings
    overlay. The load bearing part is not the endpoint but how a saved value is
    applied: .NET flattens a JSON array into indexed keys and merges one index at
    a time, so an overlay saving two thresholds over the four the product ships
    would have yielded four, silently, with every value positive, distinct and
    correctly ordered. Arrays are therefore replaced wholesale rather than merged.

  • The whole SMTP transport is configurable from the same card (PR #252). The send
    path always supported the port, transport security and authentication; the
    configuration plumbing stopped at three fields, which left an operator who
    needed a nonstandard port or a credential editing a file on the server for a
    channel the dashboard otherwise owns. Port, an explicit TLS mode (none,
    STARTTLS, implicit), username, password and sender display name are now part
    of the writable set. TLS became a choice instead of a derivation: with no mode
    stored the old rule based on the port still applies, so an install configured
    before the mode existed keeps exactly the behaviour it had, and the card always
    shows the mode a send would actually use. The password is write only end to
    end. It is protected with the Data Protection keyring before it reaches the
    store, and no response, list, log line or error body ever carries it in any
    form, ciphertext included. A save that does not mention the password carries
    the stored one forward, because every save rewrites the whole alert block.
    The webhook block stays file only.

  • ACME device attestation (device-attest-01, draft-ietf-acme-device-attest-08)
    for issuing to hardware attested devices that present a permanent-identifier
    instead of a dns name (#139 to #146). Administration lives in a device
    attestation card on the ACME dashboard tab, and the profiles, allowlist, and
    trust anchors are stored in the database, so every change hot applies to in
    flight orders without a restart. Apple is the only attestation format in this
    release; the verifier is a plugin registry keyed on the CBOR format string,
    and TPM and hardware module formats are deferred. The feature is off by
    default and fails closed: a template with no enabled device attestation
    profile does not offer device-attest-01 at all, so a device order is refused
    as unsupportedIdentifier exactly as if the feature were absent. An allowlist
    gates which devices may enrol and an empty allowlist issues to nobody. The
    gate is re-checked at new order, at challenge validation, and at finalize,
    each writing a policy audit row the dashboard labels as blocked by the device
    attestation policy. The attested public key must equal the CSR public key, any
    dns SAN on a device order is refused, and the Apple root is embedded and
    pinned, with custom trust anchors allowed only as additions that can never
    shadow or replace it. Documented in docs/device-attestation.md.

  • Automatic renewal of the server's own TLS certificate (#105). The wizard
    enrols a TLS certificate for the host from the connected CA, but nothing
    renewed it, so at the end of its validity the host fell back to the self
    signed certificate and trust broke for every browser and ACME client at once.
    A daily background service now re-enrols the certificate inside a renewal
    window, using the same template and computer account path as setup. Renewal
    never restarts the host on its own: a successful renewal installs the new
    certificate and stages it, and the dashboard carries the pending change behind
    an Apply button, which is the announced restart. The window is capped at a
    third of the certificate's validity so a short lived template does not renew
    on every check, and the server's own certificate is kept out of the product's
    expiry alerting.

  • Provisioning the server TLS certificate from the Settings page (#106). Once
    setup completes the wizard's one click enrolment is locked, so an installed
    instance previously had no way to provision or re-provision its certificate
    and the certificate warning was inert. The Settings page now offers a Provision
    certificate action on a host that never enrolled one, sharing the same enrol
    and restart flow as renewal, and the external URL certificate warning links
    straight to it.

  • Dashboard revocation scope modes (#262). Which certificates the dashboard will
    revoke is now an administrator choice: ducks-managed (the default), custom
    with a selected template list, or all. Every mode sits under the TLS
    capability ceiling described below and none of them can widen it. A status file
    written before the setting existed reads as ducks-managed with an empty list,
    so an upgraded install starts narrow rather than wide. Ducks managed is a
    union: a certificate this product issued over ACME, or one whose template is in
    the enabled set. The setting is read fresh on each decision, so a change
    applies without a restart, and the startup log reports the active mode. ACME
    revoke-cert is deliberately exempt: a client revoking its own certificate
    keeps its RFC 8555 authorization and must never wait on a dashboard setting,
    because that path is how a key compromise gets answered.

  • Private range egress blocking for challenge validation (#102): one setting,
    Certus:Acme:ChallengeValidation:BlockPrivateRanges, adds the RFC 1918
    ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) to the HTTP-01 and
    TLS-ALPN-01 egress block list without hand listing CIDRs. Off by default,
    because an internal CA usually validates hosts on exactly these ranges; the
    new hardening guide (docs/hardening.md) documents that tradeoff and the
    AdditionalBlockedCidrs recipe for anything else, carrier grade NAT for
    example. With the flag on, an order for a private IP literal is refused at
    order time and a name resolving to a private address fails validation as a
    policy rejection, not a retried transport error.

  • Optional AD principal link on EAB credentials (#132): a credential can
    record which directory account (user, computer, or group) it was issued
    to, picked through a debounced type ahead over Active Directory an...

Read more

Ducks in a Row 0.9.0-beta.1

Pre-release

Choose a tag to compare

@lethe377 lethe377 released this 13 Jul 05:50

This section becomes the 0.9 beta, the first public release, once testing
wraps up. It ships unsigned: Haruspex Systems B.V. is still being set up, so a
code signing certificate is not available yet. A signed 1.0 follows this beta.

Added

  • ACME server (RFC 8555) that proxies certificate enrolment to Active Directory
    Certificate Services.
  • A directory per ADCS template at /acme/{template}/directory.
  • HTTP-01, DNS-01, and TLS-ALPN-01 challenge validation.
  • React dashboard showing the full certificate inventory read from the ADCS CA
    database.
  • Expiry monitoring with email (SMTP) and webhook alerts.
  • Guided, browser based setup wizard that discovers the CAs published in Active
    Directory, live tests the connection, applies the configuration, and restarts
    the service to load it.
  • Windows Integrated Authentication on the dashboard, gated to a configured
    administrator group.
  • MSI installer and Windows service for production deployment, with a data
    folder prompt (also settable unattended via DATAFOLDER=).
  • EF Core schema migrations: existing databases upgrade in place at service
    start; databases from before migrations were introduced are adopted when
    their schema matches, otherwise startup fails with a documented reset.
  • Certificate revocation tracking: a dashboard tile and filtered view for
    revoked certificates, with the revocation date and reason shown whether the
    certificate was revoked through ACME or directly on the CA console.
  • One click TLS certificate enrollment for the server itself during setup,
    issued from your own CA, so the dashboard and ACME clients trust the
    connection without a manual certificate.
  • The setup wizard checks each certificate template for ACME readiness and
    explains any issue, restricts the list to templates that will actually
    work, and resumes where you left off if interrupted partway through.
  • Change the external URL from the dashboard Settings page any time after
    setup, without hand editing configuration files.
  • Manual certificate renewal and CA certificate chain download from the
    dashboard.
  • On demand inventory sync: a Refresh button, plus an automatic sync right
    after any issuance or revocation, so the dashboard catches up in seconds
    rather than waiting for the next scheduled cycle.

Changed

  • Default sync interval lowered from 15 to 5 minutes, so a certificate
    revoked directly on the CA console appears on the dashboard within about
    five minutes instead of up to sixteen.

  • The Fleet Health score reads "No certificates yet" rather than a
    misleading 100% healthy before anything has been issued.

  • Dashboard mascot and browser tab icon updated to the duck knight artwork.

  • Clean break rename of everything user visible from Certus to Ducks in a
    Row: install folder C:\Program Files\Ducks in a Row, data folder
    C:\ProgramData\Ducks in a Row, Windows service DucksInARow, executable
    DucksInARow.Service.exe, database ducks.db, log files ducks-*.log,
    installer Ducks-in-a-Row.msi. Existing pre release installs are not
    migrated: uninstall the old product, install the new MSI, and delete the old
    C:\ProgramData\Certus folder when you no longer need it.

  • An empty CA connection string no longer falls back to the mock CA. The
    service starts unconfigured (CA operations answer 503 until the setup wizard
    connects a CA); the mock now requires the explicit Certus:UseMockCa=true
    and shows a banner in the dashboard.

  • Same version rebuilds of the MSI now replace the installed product instead
    of installing beside it. Installing the new MSI also removes stacked
    duplicate installs from earlier builds and stops the orphaned service they
    left behind; uninstall reliably stops and removes the service again.