Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/development/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ The script collects the `bor-agent` packages for `VERSION` (and
|---|---|
| `manifest.json` | Index of all files with checksums and a `signed` flag, read by the web UI and checked at server startup |
| `deb/` | Flat apt repository: packages, `Packages(.gz)`, `Release`, plus `InRelease` and `Release.gpg` when signed |
| `rpm/` | dnf/zypper repository with `repodata/`, plus `repodata/repomd.xml.asc` when signed |
| `rpm/` | dnf/zypper repository with `repodata/`, plus `repodata/repomd.xml.asc` and `repodata/repomd.xml.key` (the public key at the path zypper looks for) when signed |
| `apk/`, `arch/` | Direct downloads (no repository index) |
| `repo-key.asc` | Public signing key, only when signed |

Expand Down
105 changes: 66 additions & 39 deletions doc/installation/agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,24 @@ The **Deploy agent** wizard generates a script that does all four.
`node_group:view` and `node_group:create` permissions.
5. Click the copy icon on the script and run it in a shell on the desktop.

The generated script:

1. Downloads `/agent/ca.crt` and adds it to the system trust store. This
first download uses `curl -k` because the CA cannot be verified before it
is trusted; skip this step if the server has a publicly trusted
certificate.
The generated script is a single command: its lines are joined with
`&& \`, so a paste runs it as a unit and a failing step stops it instead
of every later step failing on its own. It:

1. Downloads `/agent/ca.crt` and adds it to the system trust store (the
first two lines). This first download uses `curl -k` because the CA
cannot be verified before it is trusted; remove the two lines if the
server has a publicly trusted certificate.
2. Adds the signed repository served by your server and installs
`bor-agent` (Debian/Ubuntu, RHEL/Fedora, SUSE), or downloads and installs
the package directly (Alpine, Arch).
3. With the enrollment step: sets `server.address` and
`server.enrollment_port` in `/etc/bor/config.yaml` to the address you
used to open the web UI (a URL without a port, such as
`https://bor.example.com`, gives `enrollment_port` 443), sets `insecure_skip_verify` to `false`, writes
the token to a root-only file, runs
`bor-agent --token-file /etc/bor/enroll-token`, deletes the token file
and runs `systemctl enable --now bor-agent`.
`https://bor.example.com`, gives `enrollment_port` 443), sets
`insecure_skip_verify` to `false`, passes the token to
`bor-agent --token-file /dev/stdin` on standard input (nothing is left
on disk) and runs `systemctl enable --now bor-agent`.

The **Direct downloads** tab lists the individual package files for the
selected architecture with their sizes and SHA-256 checksums.
Expand All @@ -101,7 +103,9 @@ selected architecture with their sizes and SHA-256 checksums.
Use these commands to script installations yourself, for example in a
configuration management tool. Replace `bor.example.com` with your
server's address. If the server uses a web port other than 443, for
example the default 8443, write it as `bor.example.com:8443`.
example the default 8443, write it as `bor.example.com:8443`. The commands
of each block are joined with `&& \`, so a block pastes as one command and
stops at the first failure.

### Trust the server CA

Expand All @@ -110,35 +114,35 @@ Skip this when the server uses a certificate from a publicly trusted CA.
=== "Debian / Ubuntu"

```bash
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /usr/local/share/ca-certificates/bor-ca.crt >/dev/null
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /usr/local/share/ca-certificates/bor-ca.crt >/dev/null && \
sudo update-ca-certificates
```

=== "RHEL / Fedora"

```bash
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /etc/pki/ca-trust/source/anchors/bor-ca.crt >/dev/null
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /etc/pki/ca-trust/source/anchors/bor-ca.crt >/dev/null && \
sudo update-ca-trust
```

=== "SUSE"

```bash
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /etc/pki/trust/anchors/bor-ca.crt >/dev/null
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /etc/pki/trust/anchors/bor-ca.crt >/dev/null && \
sudo update-ca-certificates
```

=== "Alpine"

```bash
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /usr/local/share/ca-certificates/bor-ca.crt >/dev/null
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /usr/local/share/ca-certificates/bor-ca.crt >/dev/null && \
sudo update-ca-certificates
```

=== "Arch Linux"

```bash
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /etc/ca-certificates/trust-source/anchors/bor-ca.crt >/dev/null
curl -fsSk https://bor.example.com/agent/ca.crt | sudo tee /etc/ca-certificates/trust-source/anchors/bor-ca.crt >/dev/null && \
sudo update-ca-trust
```

Expand All @@ -154,25 +158,30 @@ Skip this when the server uses a certificate from a publicly trusted CA.
=== "Debian / Ubuntu"

```bash
sudo install -d -m 755 /etc/apt/keyrings
curl -fsS https://bor.example.com/agent/repo-key.asc | sudo tee /etc/apt/keyrings/bor.asc >/dev/null
printf 'Types: deb\nURIs: https://bor.example.com/agent/deb/\nSuites: ./\nSigned-By: /etc/apt/keyrings/bor.asc\n' \
| sudo tee /etc/apt/sources.list.d/bor.sources >/dev/null
sudo apt-get update && sudo apt-get install -y bor-agent
sudo install -d -m 755 /etc/apt/keyrings && \
curl -fsS https://bor.example.com/agent/repo-key.asc | sudo tee /etc/apt/keyrings/bor.asc >/dev/null && \
printf '%s\n' \
'Types: deb' \
'URIs: https://bor.example.com/agent/deb/' \
'Suites: ./' \
'Signed-By: /etc/apt/keyrings/bor.asc' \
| sudo tee /etc/apt/sources.list.d/bor.sources >/dev/null && \
sudo apt-get update && \
sudo apt-get install -y bor-agent
```

=== "RHEL / Fedora"

```bash
cat <<EOF | sudo tee /etc/yum.repos.d/bor.repo >/dev/null
[bor]
name=Bor Agent
baseurl=https://bor.example.com/agent/rpm/
enabled=1
gpgcheck=0
repo_gpgcheck=1
gpgkey=https://bor.example.com/agent/repo-key.asc
EOF
printf '%s\n' \
'[bor]' \
'name=Bor Agent' \
'baseurl=https://bor.example.com/agent/rpm/' \
'enabled=1' \
'gpgcheck=0' \
'repo_gpgcheck=1' \
'gpgkey=https://bor.example.com/agent/repo-key.asc' \
| sudo tee /etc/yum.repos.d/bor.repo >/dev/null && \
sudo dnf install -y bor-agent
```

Expand All @@ -182,10 +191,29 @@ Skip this when the server uses a certificate from a publicly trusted CA.
=== "SUSE"

```bash
sudo zypper addrepo --refresh https://bor.example.com/agent/rpm/ bor
printf '%s\n' \
'[bor]' \
'name=Bor Agent' \
'baseurl=https://bor.example.com/agent/rpm/' \
'enabled=1' \
'autorefresh=1' \
'type=rpm-md' \
'gpgcheck=1' \
'repo_gpgcheck=1' \
'gpgkey=https://bor.example.com/agent/repo-key.asc' \
| sudo tee /etc/zypp/repos.d/bor.repo >/dev/null && \
sudo zypper --gpg-auto-import-keys install -y bor-agent
```

`gpgkey=` tells zypper where to fetch the signing key and
`--gpg-auto-import-keys` imports it without a prompt. zypper's
`gpgcheck=1` is the master switch: with the metadata signed and verified,
packages are accepted by the SHA-256 checksum recorded in the metadata,
the same as dnf's `repo_gpgcheck=1`. The repository also publishes the
key as `rpm/repodata/repomd.xml.key`, the path zypper tries on its own
when a repository has no `gpgkey=` line, so a plain `zypper addrepo`
works too.

=== "Alpine"

Alpine and Arch have no hosted repository; download the package
Expand All @@ -194,7 +222,7 @@ Skip this when the server uses a certificate from a publicly trusted CA.
**Direct downloads** tab of the wizard.

```bash
curl -fsSO https://bor.example.com/agent/apk/<file>.apk
curl -fsSO https://bor.example.com/agent/apk/<file>.apk && \
sudo apk add --allow-untrusted ./<file>.apk
```

Expand All @@ -209,7 +237,7 @@ Skip this when the server uses a certificate from a publicly trusted CA.
=== "Arch Linux"

```bash
curl -fsSO https://bor.example.com/agent/arch/<file>.pkg.tar.zst
curl -fsSO https://bor.example.com/agent/arch/<file>.pkg.tar.zst && \
sudo pacman -U --noconfirm ./<file>.pkg.tar.zst
```

Expand Down Expand Up @@ -305,14 +333,13 @@ join:
Tokens are single-use and valid for 5 minutes. Then, on the desktop:

```bash
sudo install -m 600 /dev/null /etc/bor/enroll-token
printf '%s' 'PASTE-THE-TOKEN-HERE' | sudo tee /etc/bor/enroll-token >/dev/null
sudo bor-agent --token-file /etc/bor/enroll-token
sudo rm -f /etc/bor/enroll-token
printf '%s' 'PASTE-THE-TOKEN-HERE' | sudo bor-agent --token-file /dev/stdin
```

You can also pass the token in the `BOR_ENROLLMENT_TOKEN` environment
variable, or with `--token` (deprecated: the token is visible in the process
`--token-file` reads any file, so a configuration management tool can also
place the token in a root-only file (mode `0600`) and delete it after
enrolling. You can also pass the token in the `BOR_ENROLLMENT_TOKEN`
environment variable, or with `--token` (deprecated: the token is visible in the process
list; the **Node Groups** dialog shows a `sudo bor-agent --token ...`
command for convenience). If several are given, `--token-file` wins over
`BOR_ENROLLMENT_TOKEN`, which wins over `--token`.
Expand Down
3 changes: 2 additions & 1 deletion doc/operations/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ The server publishes its agent packages at `https://bor.example.com/agent/`
|---------|-------|-----|
| apt: certificate verification failed / dnf: `Curl error (60)` / SSL certificate problem | The endpoint does not trust the Bor CA used on the web port | Run the CA trust step from the **Deploy agent** wizard: download `/agent/ca.crt` into the system anchors and run `update-ca-certificates` or `update-ca-trust` |
| `404 Not Found` for every file | The server has no agent repository (see the previous section) | Install the official `bor-server` package |
| apt: `NO_PUBKEY` / signature errors; dnf: repomd signature errors | The repository key is missing or the repository was re-signed | Re-download `https://bor.example.com/agent/repo-key.asc` to `/etc/apt/keyrings/bor.asc` (apt) or re-import it (dnf/zypper) |
| apt: `NO_PUBKEY` / signature errors; dnf: repomd signature errors | The repository key is missing or the repository was re-signed | Re-download `https://bor.example.com/agent/repo-key.asc` to `/etc/apt/keyrings/bor.asc` (apt) or import it again with `sudo rpm --import https://bor.example.com/agent/repo-key.asc` (dnf, zypper) |
| zypper: `File 'repomd.xml' from repository 'bor' is signed with an unknown key`, then `Repository 'bor' is invalid` | The repository was added with a plain `zypper addrepo`, so it has no `gpgkey=` line, and the server predates the key at `rpm/repodata/repomd.xml.key` that zypper tries instead | Replace the definition with the one from the **Deploy agent** wizard (`/etc/zypp/repos.d/bor.repo` with a `gpgkey=` line), or run `sudo rpm --import https://bor.example.com/agent/repo-key.asc` and retry |
| The wizard shows "This repository is UNSIGNED (development build)" | The server package was built without a signing key | Use official release packages; unsigned repositories need `trusted=yes` / `gpgcheck=0` |
| Connection errors after the server moved | The repository definition still has the old address | Update `/etc/apt/sources.list.d/bor.sources` (or `bor.list`), `/etc/yum.repos.d/bor.repo`, or `sudo zypper modifyrepo` |
| Updates install an older or newer agent than the server | The server's packaged agent differs from the server version (wizard warns "The packaged agent version ... differs from this server ...") | Upgrade `bor-server`; it carries the matching agent packages |
Expand Down
2 changes: 1 addition & 1 deletion doc/reference/files-and-ports.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ of Flatpak repository catalogs.
| `/var/lib/bor/agent/luks-state.json` | root | Disk-encryption rotation progress (never contains keys). | `disk_encryption.state_file` |
| `/etc/bor/luks-bootstrap/` | root | One-time LUKS provisioning credentials placed by an installer; wiped after adoption. | `disk_encryption.bootstrap_dir` |
| `/run/bor/luks/` | root, `0700` | Work directory and lock file for disk-encryption operations. | `disk_encryption.run_dir` |
| `/etc/bor/enroll-token` | root, `0600` | Temporary token file used by the deploy script; deleted after enrollment. | `--token-file` |
| `/etc/bor/enroll-token` | root, `0600` | Conventional path for a token file written by hand or by a configuration management tool; delete it after enrollment. The deploy wizard passes the token on standard input instead. | `--token-file` |

### Service and user

Expand Down
53 changes: 37 additions & 16 deletions scripts/assemble-agent-repo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# ├── deb/ flat apt repo: *.deb + Packages(.gz) + Release
# │ + InRelease/Release.gpg (when signing)
# ├── rpm/ dnf/zypper repo: *.rpm + repodata/
# │ + repodata/repomd.xml.asc (when signing)
# │ + repodata/repomd.xml.asc|.key (when signing)
# ├── apk/ direct-download .apk files (no index — Alpine
# │ repo signing is abuild-specific; see plan §4.4)
# └── arch/ direct-download pacman packages
Expand Down Expand Up @@ -136,6 +136,9 @@ if [ -n "$SIGN_KEY_ID" ]; then
"$OUT_DIR/rpm/repodata/repomd.xml"
# Public key, served to clients for Signed-By= / gpgkey= (no passphrase needed).
gpg --batch --export --armor "$SIGN_KEY_ID" > "$OUT_DIR/repo-key.asc"
# zypper looks for the key at repodata/repomd.xml.key when a repository
# has no gpgkey= line (plain `zypper addrepo`): same key, second path.
cp "$OUT_DIR/repo-key.asc" "$OUT_DIR/rpm/repodata/repomd.xml.key"
[ -n "$PASSFILE" ] && rm -f "$PASSFILE" && PASSFILE=""
SIGNED=true
else
Expand Down Expand Up @@ -229,23 +232,41 @@ tokens) is in the web UI: <em>Nodes &rarr; Deploy agent</em>.</p>
Signing key: <a href="repo-key.asc">repo-key.asc</a> ·
Instance CA: <a href="ca.crt">ca.crt</a></p>
<h2>Debian / Ubuntu</h2>
<pre><code>sudo install -d -m 755 /etc/apt/keyrings
curl -fsS <span class="origin">ORIGIN</span>/agent/repo-key.asc | sudo tee /etc/apt/keyrings/bor.asc &gt;/dev/null
printf 'Types: deb\nURIs: <span class="origin">ORIGIN</span>/agent/deb/\nSuites: ./\nSigned-By: /etc/apt/keyrings/bor.asc\n' | sudo tee /etc/apt/sources.list.d/bor.sources &gt;/dev/null
sudo apt-get update &amp;&amp; sudo apt-get install -y bor-agent</code></pre>
<pre><code>sudo install -d -m 755 /etc/apt/keyrings &amp;&amp; \\
curl -fsS <span class="origin">ORIGIN</span>/agent/repo-key.asc | sudo tee /etc/apt/keyrings/bor.asc &gt;/dev/null &amp;&amp; \\
printf '%s\n' \\
'Types: deb' \\
'URIs: <span class="origin">ORIGIN</span>/agent/deb/' \\
'Suites: ./' \\
'Signed-By: /etc/apt/keyrings/bor.asc' \\
| sudo tee /etc/apt/sources.list.d/bor.sources &gt;/dev/null &amp;&amp; \\
sudo apt-get update &amp;&amp; \\
sudo apt-get install -y bor-agent</code></pre>
<h2>RHEL / Fedora</h2>
<pre><code>cat &lt;&lt;REPO | sudo tee /etc/yum.repos.d/bor.repo &gt;/dev/null
[bor]
name=Bor Agent
baseurl=<span class="origin">ORIGIN</span>/agent/rpm/
enabled=1
gpgcheck=0
repo_gpgcheck=1
gpgkey=<span class="origin">ORIGIN</span>/agent/repo-key.asc
REPO
<pre><code>printf '%s\n' \\
'[bor]' \\
'name=Bor Agent' \\
'baseurl=<span class="origin">ORIGIN</span>/agent/rpm/' \\
'enabled=1' \\
'gpgcheck=0' \\
'repo_gpgcheck=1' \\
'gpgkey=<span class="origin">ORIGIN</span>/agent/repo-key.asc' \\
| sudo tee /etc/yum.repos.d/bor.repo &gt;/dev/null &amp;&amp; \\
sudo dnf install -y bor-agent</code></pre>
<p>SUSE uses the same rpm repository via <code>zypper addrepo</code>; Alpine
and Arch packages are direct downloads — paths in
<h2>SUSE</h2>
<pre><code>printf '%s\n' \\
'[bor]' \\
'name=Bor Agent' \\
'baseurl=<span class="origin">ORIGIN</span>/agent/rpm/' \\
'enabled=1' \\
'autorefresh=1' \\
'type=rpm-md' \\
'gpgcheck=1' \\
'repo_gpgcheck=1' \\
'gpgkey=<span class="origin">ORIGIN</span>/agent/repo-key.asc' \\
| sudo tee /etc/zypp/repos.d/bor.repo &gt;/dev/null &amp;&amp; \\
sudo zypper --gpg-auto-import-keys install -y bor-agent</code></pre>
<p>Alpine and Arch packages are direct downloads - paths in
<a href="manifest.json">manifest.json</a>. If this instance uses its
auto-generated certificate, trust <a href="ca.crt">ca.crt</a> first. Details:
<code>doc/installation/agent.md</code> in the Bor repository.</p>
Expand Down
Loading
Loading