DatumHuedatumhue.com
Contents

Deployment Tool

What it does

The deployment tool, datumhue-deploy, turns one description of a deployment, its hosts, its aggregator and its providers with their mounts, sign-in services, channels and rules, into a bundle with one folder per host. Each folder holds that host's settings, identity keys, capability files, certificates, service units and install steps; the aggregator's also holds the deployment secret. The tool also makes capabilities for a provider added later, and revokes a provider's key. See the Overview for the whole deployment.

Quick start

shell
chmod +x datumhue-deploy-linux-x86_64
./datumhue-deploy-linux-x86_64 init deployment.kdl
$EDITOR deployment.kdl
./datumhue-deploy-linux-x86_64 validate deployment.kdl
DATUMHUE_KEYSTORE_PASSPHRASE='choose-a-strong-passphrase' \
    ./datumhue-deploy-linux-x86_64 generate deployment.kdl -o bundle/ \
        --license customer.dhlicense

Then follow bundle/CHECKLIST.md and the README.md in each host's folder.

How it works

  1. init writes a starter description, with a comment on every key.
  2. You edit it.
  3. validate checks it, and reports what is wrong or doubtful.
  4. generate --license customer.dhlicense writes the bundle, with a new deployment secret and every provider's capabilities signed under it.
  5. You follow bundle/CHECKLIST.md, then the README.md in each host's folder, on that host.

The tool owns everything that ties the services together: URLs, keys, capability files, environment files and units. The blocks that say what each provider serves, its mounts, sign-in services, channels and publish rules, go into that provider's settings as you wrote them, in the form its own page in this manual describes.

Without a license file, generate writes license-request.kdl, filled in with the deployment's counts, for a license DatumHue issues by hand. With one, it checks the description against the license's counts.

The deployment secret signs every capability file. generate makes a new one, or keeps the one --deployment-secret names, and writes it to the aggregator host's state/aggregator/deployment.secret. A new or renewed license leaves the capability files in force. add-provider and reissue-capabilities read the secret from the bundle, or from --deployment-secret once you keep it elsewhere, and stop without it; reissue-capabilities --new-deployment-secret replaces it.

The access key admits the deployment's workstations. generate makes one and writes it to the aggregator host's etc/access.env, to datumhue-client.env for the workstation app and command line, and as the browser access link to access-link.txt; each file is readable by its owner only. Whoever holds the key gets a workstation seat, so give it only to the deployment's people, and make a new one with new-access-key when someone leaves.

The admin socket, through which aggregator lease lists the seats and ends workstation sessions, is set up in the aggregator's unit and compose stack; the aggregator host's README.md gives the command.

The bundle holds every key. The keys and the deployment secret are encrypted with DATUMHUE_KEYSTORE_PASSPHRASE; every service, the aggregator included, reads it from its host's keystore.env.

Capabilities last 30 days. A running provider renews its own before they end. A provider stopped for longer needs its file made again with reissue-capabilities.

Revoking a provider key

A revocation withdraws a provider key's right to its namespaces before its capabilities end: aggregators then refuse the key's announcements, renewals, seat and sign-in key publishing, and leave its provider and the keys it published out of every lookup. revoke signs one revocation for each namespace the description grants the provider, and for each --namespace and --issuer-url you add; lift signs the lifts that restore them. For each key and namespace, the newest record stands.

Each record is added to the bundle's revocations.txt. --aggregator submits the records at once, and any aggregator passes them to the others. --out writes them to a file instead, for submit on a host that reaches an aggregator:

shell
datumhue-deploy revoke deployment.kdl --provider identity-provider \
    --host providers-1 --key <public key> --out revoke.txt
datumhue-deploy submit revoke.txt --aggregator https://datumhue.example

The command submits every record, and ends with an error unless the aggregator accepted each one. Then replace the key:

  1. Make the provider a new key in the bundle, with its capability file:

    shell
    datumhue-deploy add-provider deployment.kdl \
        --provider identity-provider --host providers-1 --out bundle
    
  2. Install its files on the host as its README.md describes, and restart the provider.

  3. Replace each secret the host held, such as a sign-in service's client-secret.

reissue-capabilities makes no capability file for a key that stands revoked in revocations.txt. With --new-deployment-secret, it also writes the aggregator host's state/aggregator/revocations: install that file with the secret, so the revoked keys stay revoked.

Command line

text
datumhue-deploy <COMMAND>
CommandDescription
datumhue-deploy initWrite a commented starter deployment description.
datumhue-deploy validateCheck a deployment description and report findings; exits non-zero on errors.
datumhue-deploy generateGenerate the per-host installation bundle.
datumhue-deploy reissue-capabilitiesMake every provider's capability file of a bundle again, keeping the bundle's keys: for capabilities that lapsed while a provider was stopped, or under a new deployment secret.
datumhue-deploy new-access-keyReplace the deployment's access key in a bundle: the aggregator host's etc/access.env, datumhue-client.env and the browser access link. Install the new etc/access.env on every aggregator and restart them together; sessions on the old key end within seconds.
datumhue-deploy add-providerMake the files of one provider added to a deployment: its key, its capability file, its settings and its service unit, without generating the bundle again.
datumhue-deploy revokeRevoke a provider key before its capabilities end: aggregators refuse it, and leave it and the sign-in keys it published out of every lookup.
datumhue-deploy liftLift a provider key's revocation, restoring what it withdrew.
datumhue-deploy submitSubmit the records of a file revoke --out or lift --out wrote, or of the bundle's revocations.txt, to an aggregator.

datumhue-deploy init

text
datumhue-deploy init [OPTIONS] [PATH]
ArgumentDefaultDescription
[PATH]deployment.kdlWhere to write the description
FlagDefaultDescription
--forceoffOverwrite an existing file

datumhue-deploy validate

text
datumhue-deploy validate <PATH>
ArgumentDefaultDescription
<PATH>requiredThe deployment description to check

datumhue-deploy generate

text
datumhue-deploy generate [OPTIONS] <PATH>
ArgumentDefaultDescription
<PATH>requiredThe deployment description to generate from
FlagDefaultDescription
--out <OUT>, -obundleThe folder to write the bundle into
--forceoffOverwrite a non-empty output directory
--license <LICENSE>noneThe deployment's issued .dhlicense, checked against the description's counts. Without it, generate writes license-request.kdl, for a license DatumHue issues by hand
--deployment-secret <DEPLOYMENT_SECRET>noneA deployment secret to keep, such as the one your aggregators already run under. Without it, generate makes a new one

datumhue-deploy add-provider

text
datumhue-deploy add-provider [OPTIONS] --provider <PROVIDER> --host <HOST> \
    <PATH>
ArgumentDefaultDescription
<PATH>requiredThe deployment description, with the new provider's block added
FlagDefaultDescription
--license <LICENSE>noneThe deployment's issued .dhlicense, checked against the description's counts
--bundle <BUNDLE>bundleThe bundle directory generate wrote, which keeps the deployment secret the capability file is signed under
--deployment-secret <DEPLOYMENT_SECRET>noneThe deployment secret, when it is no longer in the bundle
--provider <PROVIDER>requiredThe kind of provider to add, as its block in the description names it, such as fs-data-provider
--host <HOST>requiredThe host the provider runs on, by its name in the description
--out <OUT>, -obundle-addThe folder to write the new provider's files into

add-provider writes the new provider's settings, key, capability file and unit into a folder for its host, in the bundle's layout. Install them as that host's README.md describes.

datumhue-deploy reissue-capabilities

text
datumhue-deploy reissue-capabilities [OPTIONS] <PATH>
ArgumentDefaultDescription
<PATH>requiredThe deployment description the bundle was generated from
FlagDefaultDescription
--license <LICENSE>noneThe deployment's issued .dhlicense, checked against the description's counts
--bundle <BUNDLE>bundleThe bundle directory generate wrote
--deployment-secret <DEPLOYMENT_SECRET>noneThe deployment secret, when it is no longer in the bundle
--new-deployment-secretoffMake a new deployment secret and every capability file under it; install the secret on every aggregator and the files on every provider host

After a reissue, install each host's new state/<service>/<service>.capabilities; running providers take it without a restart. After --new-deployment-secret, first install the bundle's new state/aggregator/deployment.secret on every aggregator, with state/aggregator/revocations when the bundle has one, and restart them together. Each package provider then stops once when its new file arrives, and keeps its catalog when its service starts it again.

datumhue-deploy new-access-key

text
datumhue-deploy new-access-key [OPTIONS] <PATH>
ArgumentDefaultDescription
<PATH>requiredThe deployment description the bundle was generated from
FlagDefaultDescription
--bundle <BUNDLE>bundleThe bundle directory generate wrote

It replaces the key in the aggregator host's etc/access.env, datumhue-client.env and access-link.txt, and prints the new key's id. Install the new etc/access.env on every aggregator and restart them together; each logs the id at start. Sessions that took their seat with the old key end within seconds. Then give the deployment's people the new datumhue-client.env, and browser users the new access link.

datumhue-deploy revoke

text
datumhue-deploy revoke [OPTIONS] --provider <PROVIDER> --host <HOST> \
    --key <KEY> <--aggregator <AGGREGATOR>|--out <OUT>> <PATH>
ArgumentDefaultDescription
<PATH>requiredThe deployment description
FlagDefaultDescription
--bundle <BUNDLE>bundleThe bundle directory generate wrote, which keeps the deployment secret and the ledger of every revocation signed for the deployment, revocations.txt
--deployment-secret <DEPLOYMENT_SECRET>noneThe deployment secret, when it is no longer in the bundle
--provider <PROVIDER>requiredThe provider, as its block in the description names it, such as identity-provider
--host <HOST>requiredThe host it runs on, by its name in the description
--key <KEY>requiredThe provider's public key, as it logs it at start and pubkeys.txt lists it
--namespace <NAMESPACE>noneA namespace to cover besides those the description grants the provider; repeat for several
--issuer-url <ISSUER_URL>noneAn issuer URL whose sign-in keys to cover besides those the description gives the provider; repeat for several
--aggregator <AGGREGATOR>noneSubmit each record to this aggregator now, by its public URL
--out <OUT>noneWrite the records to this new file instead, for submit on another host

datumhue-deploy lift

text
datumhue-deploy lift [OPTIONS] --provider <PROVIDER> --host <HOST> --key <KEY> \
    <--aggregator <AGGREGATOR>|--out <OUT>> <PATH>
ArgumentDefaultDescription
<PATH>requiredThe deployment description
FlagDefaultDescription
--bundle <BUNDLE>bundleThe bundle directory generate wrote, which keeps the deployment secret and the ledger of every revocation signed for the deployment, revocations.txt
--deployment-secret <DEPLOYMENT_SECRET>noneThe deployment secret, when it is no longer in the bundle
--provider <PROVIDER>requiredThe provider, as its block in the description names it, such as identity-provider
--host <HOST>requiredThe host it runs on, by its name in the description
--key <KEY>requiredThe provider's public key, as it logs it at start and pubkeys.txt lists it
--namespace <NAMESPACE>noneA namespace to cover besides those the description grants the provider; repeat for several
--issuer-url <ISSUER_URL>noneAn issuer URL whose sign-in keys to cover besides those the description gives the provider; repeat for several
--aggregator <AGGREGATOR>noneSubmit each record to this aggregator now, by its public URL
--out <OUT>noneWrite the records to this new file instead, for submit on another host

datumhue-deploy submit

text
datumhue-deploy submit --aggregator <AGGREGATOR> <FILE>
ArgumentDefaultDescription
<FILE>requiredThe file revoke --out or lift --out wrote, or the bundle's revocations.txt
FlagDefaultDescription
--aggregator <AGGREGATOR>requiredThe aggregator to submit to, by its public URL

submit submits the file's records in order. Given the bundle's revocations.txt, it gives a new aggregator every record; an aggregator that already holds them answers Stale, so submit ends with an error after submitting every line.

Environment

VariableDescription
DATUMHUE_KEYSTORE_PASSPHRASEgenerate, add-provider and reissue-capabilities encrypt the keys and the deployment secret with it, or read them with it, and stop without it. revoke and lift read the bundle's deployment secret with it. The services decrypt them with the same value, from each host's keystore.env
DATUMHUE_CERT_PATHA CA certificate revoke, lift and submit trust, besides the public ones, when they reach an aggregator, such as the bundle's ca-cert.pem

Configuration

The description is KDL: one deployment block that names the deployment and holds the customer id, the hosts, one aggregator block and a block for each provider. A key the tool does not know, in the deployment block, the aggregator block or a provider's own settings, is an error that validate reports.

kdl
deployment "acme-prod" {
    customer-id "acme"

    host "agg-1"
    host "providers-1"

    aggregator {
        host "agg-1"
        public-url "https://datumhue.acme.example"
        tls "self-managed"
        max-sessions 100
    }

    identity-provider {
        host "providers-1"
        issuer "keycloak" {
            issuer-url "https://keycloak.acme.example/realms/acme"
            client-id "datumhue-client"
            scopes "profile" "email" "groups"
        }
    }

    fs-provider {
        host "providers-1"
        fs-mount "shared" {
            path "/mnt/nas/shared"
            mode "rw"
            issuer "https://keycloak.acme.example/realms/acme" {
                allow claim="groups" array_contains="acme-users" \
                    rights="rw"
            }
        }
    }
}

Deployment

KeyRequiredDescription
deployment "<name>"yesThe deployment's label, which names the bundle and appears in the files it holds
customer-idyesYour customer id, which the license request carries
hostyesA host's label, once for each host. Each becomes a folder of the bundle, and every service names one

Aggregator

KeyRequiredDefaultDescription
hostyesnoneThe host that runs the aggregator
public-urlyesnoneThe HTTPS URL workstations and providers use, also the relay and discovery URL
https-bindno0.0.0.0:443The HTTPS address
quic-bindno0.0.0.0:7842The UDP address of public-address lookups for the workstation app and providers
stun-bindno0.0.0.0:3478The UDP address of public-address lookups for browsers
webrtc-bindno0.0.0.0:7843The UDP address of browsers' direct connections
webrtc-publicnothe public URL's host and the webrtc-bind portThe host:port browsers reach it at, when that differs
static-dirno/opt/datumhue/staticThe folder of the browser workstation
tlsno"self-managed"Where the certificate comes from, as Certificates describes
max-sessionsno100The session count the license request asks for

Providers

A block for each provider instance: package-provider, fs-provider, fs-data-provider, adbc-data-provider, identity-provider, egress-provider or ingress-provider. A host runs at most one of each kind, and a deployment at most one egress-provider.

KeyApplies toRequiredDescription
hostevery provideryesThe host that runs it
namespacepackage-provideryesThe namespace it serves
listeningress-providernoThe address it takes events on
outbound-proxyegress-providernoThe proxy its requests to the origins go through: an http:// or https:// URL with no user name or password

Everything else in a provider's block says what it serves: fs-mount, fs-data-mount, adbc-data-mount, issuer, http-mount, ingress-channel and publish-rules, in the form the provider's own page describes. The tool makes a capability for each one, in that provider's capability file. An issuer gets two: one to announce it by name, and one to publish its keys, made for its issuer-url and named by it in a comment above the line.

More than one copy. For availability, give a provider block of the same kind, with the same mounts, to more hosts. Each copy serves the same mounts with its own key and capabilities, and workstations reach whichever copies run. Each copy takes one of the license's provider seats.

Certificates

  • tls "self-managed" makes a certificate authority and a server certificate for the public URL's host, in the aggregator host's tls/ folder, and copies the CA certificate to every host's etc/ and the bundle's top folder. Providers and workstations then trust the aggregator from their first start, and an aggregator restart renews the server certificate once it has less than 30 days left.
  • tls "operator" takes a certificate and key from your own certificate authority; the settings name where you install them, and the tool makes no certificates.

Access rules

The tool copies each mount's, channel's and registry's rules into its provider's settings, and validate loads them as the provider will. Every mount and channel needs a rule; one without is an error, and so is a rule its provider would refuse. An issuer block must name an issuer-url of the identity-provider exactly as written. A rule that reads a sign-in outside an issuer block is an error, and when the description declares one sign-in service, the error shows the block to write. allow anyone needs no sign-in service and is a warning, in the words its provider logs at start.

These are warnings too:

  • a rule on a claim no sign-in service asks a scope for;
  • a rule on email or phone_number, which matches only a token that says the sign-in service verified the value;
  • allow signed-in under https://accounts.google.com without a require claim="hd", which admits every Google account;
  • allow signed-in in publish-rules, which lets everyone the issuer signs in publish.

The rules themselves work as each provider's page describes.

Network, state and dependencies

Network surface

Only submit, and revoke and lift with --aggregator, connect anywhere: to that aggregator's public URL, over HTTPS. Everything else runs on any Linux machine, offline included, and reads only the description, the license file, the bundle and the deployment secret.

Persistent state

The tool keeps nothing of its own, but its inputs and outputs are the deployment's records:

PathHolds
deployment.kdlThe description, which every later add-provider and reissue-capabilities reads
bundle/Every service's settings and keys, the CA's private key, and the deployment secret in the aggregator host's state/aggregator/
bundle/revocations.txtEvery revocation and lift the tool signed, which reissue-capabilities reads. Keep it with the bundle
bundle/datumhue-client.env, bundle/access-link.txtThe workstations' settings with the access key, and the browser access link
The passphraseThe only way to read the keys again

External dependencies

  • The license file, customer.dhlicense, which --license checks the description against.

Security notes

  • The bundle holds private keys, the CA's among them. Move it over a secure channel, and delete working copies once the hosts are set up.
  • The passphrase protects every key. Keep it in your secret store; each host needs it in keystore.env, mode 600.
  • The deployment secret makes capabilities. Anyone with it and this tool can authorize a provider: keep it in your secret store, as safe as the keys, and never copy it to another deployment.
  • The access key admits workstations. It admits whoever holds it, as one of the deployment's people: hand datumhue-client.env and the access link out privately, and replace the key with new-access-key when someone should no longer get in.

Troubleshooting

validate reports errors. Each one stops generate:

  • a host that is not declared, or declared twice;
  • no aggregator block, or a public-url that is not HTTPS;
  • a bind address that does not parse;
  • a mount or channel name used twice on one host, or by two kinds of provider. The same name on more hosts of one kind is a set of copies, and allowed;
  • a package-provider without namespace;
  • an issuer without issuer-url, or with one that is not an https URL with no query, fragment or user name;
  • two issuer entries of one provider with the same issuer-url;
  • an issuer whose jwks-ttl is longer than "24h", which aggregators keep published keys for at most;
  • an issuer whose person-claim many people share or a person can change, such as tid or email;
  • a mount or channel without rules, a rule its provider would refuse, or a rule that reads a sign-in outside an issuer block;
  • an issuer block whose URL is not an issuer-url the identity-provider declares;
  • two providers of one kind on one host;
  • two keys on one line, such as { path "/x" mode "r" }: KDL reads that as one path with extra values. Put each key on its own line, or end each with ;.

validate reports warnings. Generation goes on, and the warnings appear in CHECKLIST.md: for example, a rule on a claim that no sign-in service asks a scope for, an allow anyone, or person-claim "oid" without the profile scope, which Microsoft Entra ID puts oid in ID tokens for.

generate refuses the license. The file is not an Enterprise deployment license, or the description has more providers than the license's provider count. A description with more max-sessions than the license only warns: the license's count applies.

reissue-capabilities cannot read a key. The passphrase differs from the one generate used: set DATUMHUE_KEYSTORE_PASSPHRASE to that one.

reissue-capabilities or add-provider stops: no deployment secret. The bundle holds no state/aggregator/deployment.secret. Pass --deployment-secret with the file your aggregators run under; reissue-capabilities --new-deployment-secret makes a new one instead, which every aggregator then needs.

A service cannot read its key. The passphrase in the host's keystore.env differs from the one the bundle was made with.

revoke, lift or submit reports a record not accepted. Each line names what the aggregator decided. Rejected: it runs under another deployment secret than the one the record is signed under. Stale: it holds a record for that key and namespace at least as new, which stands; run revoke or lift again with --aggregator to sign past it.

revoke or lift stops: the aggregator holds records under another deployment secret. The aggregator --aggregator names runs under another secret than the one the command read, or belongs to another deployment. Pass --deployment-secret with the file your aggregators run under, or name one of this deployment's aggregators. Nothing is signed or recorded.

reissue-capabilities warns that a key is revoked. That provider keeps the file it has. add-provider --out bundle makes it a new key, as Revoking a provider key describes; lift restores the old key instead.

datumhue.com

Victor Mono is licensed under the SIL Open Font License 1.1
Copyright (c) 2024, Rune Bjørnerås (https://github.com/rubjo)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
    ↑↓ selectEnter openTab filter

    Settings

    Theme
    Text
    Print

    Keyboard shortcuts

    / or Ctrl KSearch
    ↑ ↓ EnterPick a result
    TabNext result filter
    j kNext or previous entry
    [ ]Previous or next page
    yCopy a link to the current entry
    ?These shortcuts
    EscClose

    On this page