9.6 KiB
Deployment
deploy/lw-deploy.sh configures and deploys one LogWisp node per run. It asks
for what its flags leave open, prints a plan with the equivalent non-interactive
command, then writes the files, runs lw --check on them (the node's binary or
image, with its mounts) and starts the node. --dry-run stops at printing;
--yes never asks and fails on a missing required value. It creates no
certificates: see Security.
Roles
edge- tails each
--log-dir(not recursive) for--log-pattern(default*.log) - forwards to
--aggregatorovertcp_chain(port 9440) or, with--chain http,http_chain(port 9441) - labels its entries
--node: the short host name, or the jail name
- tails each
aggregator- one chain listener on
--listen(default0.0.0.0) and--chain-port - outputs, at least one:
--file-dir(rotating--file-name.log),--http-port(SSE/stream, JSON/status),--tcp-port --formattxt(default),jsonorraw
- one chain listener on
standalone- the edge's sources and the aggregator's outputs, no chain
Runtimes
docker,podman(Linux)- the container runs
--read-only --cap-drop ALL --security-opt no-new-privileges -u 65532:65532 --restart unless-stopped --config-dir(default/etc/logwisp/NAME) holdslogwisp.toml,tls/, and the credentials files, owned by 65532 and mounted read-only at/etc/logwisp- log directories mount read-only and the output directory writable, each at
its host path;
--log-groupadds that group's id to the container - listener ports publish on
--listen, an IP address; the process inside binds0.0.0.0 --network NETjoins a user network, created when missing, where edges reach an aggregator by container name;hostpublishes nothing--imagedefaults tologwisp:dev, themake imagetag;--buildbuilds it from the repository. Behind an HTTPS-intercepting proxy add--build-ca FILEand, for a proxy on loopback,--build-flags "--network host"; the environment's proxy variables pass through as build arguments- rootful engines need root to give the files to 65532; rootless podman maps
the caller to 65532 with
--userns keep-id - SELinux hosts must label the mounted directories for containers; the
script does not relabel, since
:zon a shared directory such as/var/logwould relabel it for every other service too
- the container runs
native, Linux- needs systemd; installs
lwto/usr/local/binunless one is installed (--bin FILE, or--buildformake build), anddeploy/package/logwisp.service,logwisp.sysusersandlogwisp.tmpfilesunder/etc - a package's unit (
/usr/lib/systemd/system/logwisp.service) is used as it is, with thelwitsExecStartruns;--binand--buildthen stop the run, since the service would never run that binary - writes
/etc/logwisp/logwisp.toml,root:logwisp, mode 0640 - refuses log and output directories under
/tmpand/var/tmp: the unit'sPrivateTmp=yesgives the service its own, empty ones - adds
logwisp.service.d/deploy.confwhen the node needs it:ReadWritePathsfor an output outside/var/log/logwisp,ProtectHome=read-onlyfor logs or output under/home,SupplementaryGroupsfor--log-group,CAP_NET_BIND_SERVICEfor a port below 1024
- needs systemd; installs
native, FreeBSD- installs
deploy/package/logwisp.rcas/usr/local/etc/rc.d/logwisp, creates thelogwispuser withpw, enables it withsysrc; LogWisp logs to syslog under the taglogwisp - writes
/usr/local/etc/logwisp/logwisp.toml --jail NAMEwrites the files and runs the commands throughjexec, so the jail's own symlinks cannot redirect a write onto the host; the jail must be running, and the script prints ajail.confexample when it is not- a non-root user binds a port below 1024 only with
sysctl net.inet.ip.portrange.reservedhighlowered ormac_portacl
- installs
manual- writes into
--config-dir, an absolute path (default~/logwisp-ROLE), adds users with the locallw, and prints thelw -ccommand
- writes into
FreeBSD runs no Docker, and podman there runs FreeBSD images only while the
LogWisp image is Linux: on FreeBSD the script offers native instead, on the
host or in a jail. A native install needs a host of its --os; for another
one, --dry-run shows the install and --runtime manual writes the
configuration.
Re-running the same command updates the node: an existing logwisp.toml is
kept as logwisp.toml.bak, the container is replaced, generated passwords are
reused. A user already in a credentials file whose password file is missing
stops the run before any change, instead of getting a new password that would
lock its edge out. Under --yes, replacing a configuration or a container
needs --force.
Security options
--tlssecures every network link of the node; the files are copied into the configuration directory astls/node.crt,tls/node.key,tls/ca.crt- listeners present
--cert-fileand--key-file - an edge verifies the aggregator with
--ca-file, or the system roots; the certificate must name the address dialed (an IP SAN for an IP), or the name given as--server-name
- listeners present
--authon the chain linkmtls: edges present--cert-file; the aggregator admits the--allowCNs (none: any certificate the CA issued); an edge's--allowpins the aggregator's CNscram: the aggregator creates each--add-user, its password generated into--secrets-dir, an absolute path (default~/logwisp-secrets), and handed tolw auth add-user, natively or through the image; copy each password file to its edge as--password-file, whose name without.passis the default--username- either binds the node label to the authenticated identity
--sink-authon thehttpandtcpoutputsmtlswith--sink-allow, orscramwith--add-viewer(a separateviewers.toml); viewers log in withlw auth tokenandlw auth stream- without it the outputs admit anyone who reaches them: bind
--listento a trusted address
- without
--author--sink-auth, the auth flags imply their mode:--allowand--sink-allowmtls;--add-user,--username,--password-fileand--add-viewerscram. Under--yesone that does not apply, such as--add-userwith--auth noneor without--tls, stops the run rather than deploy the node open
FreeBSD host, jails and one aggregator
Application jails run an edge each; a logs jail aggregates. Every jail runs
already, and the logs jail has an address the others reach (AGG_ADDR).
-
Certificates: a CA, and a server certificate for
logsnamingAGG_ADDR(Security). -
The aggregator, from the host:
deploy/lw-deploy.sh --yes --runtime native --jail logs --role aggregator \ --file-dir /var/log/logwisp --http-port 8080 \ --tls --cert-file logs.crt --key-file logs.key \ --auth scram --add-user web1 --add-user db1 \ --sink-auth scram --add-viewer opsThe passwords land in
~/logwisp-secrets/:web1.pass,db1.passandops.pass. -
An edge per application jail:
deploy/lw-deploy.sh --yes --runtime native --jail web1 --role edge \ --log-dir /var/log/nginx --aggregator AGG_ADDR \ --tls --ca-file ca.crt --auth scram --password-file ~/logwisp-secrets/web1.pass -
Check:
jexec logs service logwisp status, the files in thelogsjail's/var/log/logwisp, andhttps://AGG_ADDR:8080/statuswith a token fromlw auth token --url https://AGG_ADDR:8080 --user ops --password-file ~/logwisp-secrets/ops.pass --ca-file ca.crt(CLI).
Variants:
- the aggregator on the host itself: drop
--jail logs - no daemon per jail: one
standaloneoredgeon the host tails each jail's logs through the host path (--log-dir JAIL_PATH/var/log); the entries then carry the host's label and the bare file name, so files of the same name in two jails cannot be told apart - a Linux aggregator: run step 2 with
--runtime dockeron that host and point the edges at it; the chain protocol is the same
Linux host with containers
An aggregator container and an edge container per application, on one user network:
deploy/lw-deploy.sh --yes --runtime docker --role aggregator --network logwisp \
--file-dir /srv/logwisp --http-port 8080 --listen 127.0.0.1
deploy/lw-deploy.sh --yes --runtime docker --role edge --name logwisp-edge-app \
--network logwisp --aggregator logwisp-aggregator --log-dir /var/log/app
--listen 127.0.0.1 keeps the published ports on loopback; edges on other
hosts need it on an address they reach. docker kill -s HUP NAME reloads an
edited configuration or credentials file.
Not covered
Edit the generated logwisp.toml for these; config/logwisp.toml documents
every key.
- filters, rate limits, heartbeat, formatter flags and timestamp layouts
- more than one pipeline; both chain transports, or a further hop, on one node
- proxy mode: browser logins through a TLS-terminating proxy
aclon the listeners: address rules, PROXY headers- mtls identities other than the certificate CN;
node_bindingother thanforce - creating certificates
- several native instances on one host: use one per host or jail
Testing the script
test/deploy-test.sh --auto drives the script with --yes and --dry-run for
the manual, native and docker runtimes, runs the generated edge, aggregator and
standalone nodes end to end, and checks that --yes fails closed and that
--dry-run changes nothing.