Security & Network Architecture
A technical reference for the documented deployment and the evidence Pillar collects. Use it as input to your security review. It is not an independent audit, certification, or determination that Pillar or your facility meets TPN, MPA, contractual, or regulatory requirements.
1. Inspect the running deployment
Inspect TCP sockets visible in the Agent container’s network namespace. The container image does not include ss or netstat, so read the kernel's own socket tables directly:
docker exec -it pillar-agent cat /proc/net/tcp /proc/net/tcp6In a dedicated container network namespace, inspect entries for the 0A (TCP_LISTEN) state. A listening socket appears as an entry with state 0A in the fourth column. These tables do not establish process ownership, cover UDP or Unix sockets, or assess the full host network. A host-network deployment can expose sockets belonging to other host processes.
Replace YOUR_PILLAR_DOMAIN with your configured Cloud hostname, then test a TLS 1.3 connection from this host. This checks the probe, not every Agent connection:
curl --fail --show-error --verbose --tlsv1.3 --tls-max 1.3 https://YOUR_PILLAR_DOMAIN/api/v1/nodes/health-check2.Deployment control reference
These controls describe intended configuration, not a formal mapping to an external framework. Inspect available per-node evidence and its freshness on the Security Posture page.
| Security Domain | Studio Requirement | Pillar Architectural Implementation | Status |
|---|---|---|---|
| Media Asset Isolation | Avoid mounting production dataset paths into the container namespace. | No dataset, share, or media filesystem is mounted. The Agent can still read every host block device (/dev bind, cgroup rule b *:* r, SYS_RAWIO) for SMART and identity, so raw sectors are readable. Assess this block-level access in your review. | Designed control |
| Network Exposure | No TCP/UDP listening sockets in the documented Agent deployment. | The Agent opens no TCP or UDP listeners. Its only listener is the Unix socket /run/pillar/observer.sock (mode 0660), created only when the Observer is enabled. The Observer runs with --network none and connects to that socket. | Designed control |
| Transport | Encrypt all control-plane traffic. | The Agent requires TLS 1.3 (1.2 is refused) and never follows redirects. Plain HTTP is accepted only with PILLAR_ALLOW_INSECURE_HTTP=true, which is for development and logs a security warning. | Designed control |
| Credentials | Limit the lifetime and exposure of node credentials. | Single-use claim tokens expire after 15 minutes. The API key is stored in Cloud only as a SHA-256 hash, and on the host in /etc/pillar/agent.env (mode 0600). Rotation and revocation are audited in Settings. | Designed control |
| Remote Control | Cloud cannot change the host. | The Agent is observe-only. It ignores any command in heartbeat responses, advertises no actions, and never writes enclosure LEDs or starts or pauses scrubs. | Designed control |
| Execution Hardening | Reduce runtime privilege and writable filesystem exposure. | Read-only root, all capabilities dropped except SYS_RAWIO, no-new-privileges, 128-PID and 256 MiB limits, and a noexec /tmp. Both containers run as UID 0. | Designed control |
| Update Integrity | Install only authentic releases. | The updater verifies the release manifest and image with cosign (keyless, pinned to Pillar's release workflows), deploys by digest only, refuses downgrades, and rolls back on a failed health check. Set PILLAR_AUTO_UPDATE=false to turn it off. | Designed control |
| Metadata Minimization | Review operational identifiers against your data-handling requirements. | PILLAR_REDACT_METADATA=true masks serials and MACs and hashes serial-bearing disk IDs. It is off by default, and it is not anonymization. See section 3. | Opt-in, partial |
3.Privacy posture of outbound telemetry
The Agent sends storage health and hardware identity, never file contents. Hostnames, hardware identifiers, and pool and dataset names are sent unless noted below.
Privacy posture
What leaves the host
Every heartbeat field that can identify a host, drive, or production. The last column shows each field with PILLAR_REDACT_METADATA=true. The setting is off by default, and with it off every field is sent as collected, except machine_id, which is always hashed.
| Field | What it contains | With redaction on |
|---|---|---|
| Host | ||
| node.hostname | OS hostname, or PILLAR_HOST_ALIAS when set. Also sent in the one-time claim request. Only .local, .lan, .internal, .corp and .home suffixes are stripped. | Sent as-is |
| node.machine_id | SHA-256 of /etc/machine-id, truncated to 32 hex characters. The raw ID never leaves the host, but the hash is a stable identifier for the host. | Always hashed |
| node.os_version, kernel, arch, platform_version, uptime_seconds | Host software fingerprint, for example 6.8.0-45-generic or the TrueNAS or Unraid release. | Sent as-is |
| IP addresses | The Agent never reads interface addresses. Pillar Cloud sees the connecting public IP, as any HTTPS server does. | Not collected |
| Disks and enclosures | ||
| inventory.disks[].serial | SMART serial. Serials of 8 or more characters keep the first 3 and last 4 (S7DNNJ0W123456A becomes S7D-****-456A). Shorter serials are sent unchanged. | Masked |
| disk_id (inventory, smart, block, vdevs, Observer series) | WWN (wwn-0x…) and NVMe EUI IDs are sent unchanged. For by-id and serial-derived IDs, the serial part is replaced by a 16-hex SHA-256 token. | Hashed or as-is |
| inventory.disks[].by_id_path | Dropped when its serial was hashed; otherwise sent as /dev/disk/by-id/wwn-…. | Dropped or as-is |
| inventory.disks[].wwn, by_path, controller_path | World Wide Name, PCI address, and SAS address. Each is a globally unique hardware identifier. | Sent as-is |
| inventory.disks[].vendor, model, firmware, device | Drive model and kernel device name, such as /dev/sdb. | Sent as-is |
| inventory.enclosures[].enclosure_id, sysfs_path | SES enclosure logical identifier (globally unique) and its SCSI address. | Sent as-is |
| Pools and datasets | ||
| pools[].name, mountpoint | ZFS, Unraid, or mdadm pool names and mountpoints you chose. | Sent as-is |
| datasets[].name, dataset_id, mountpoint | Full dataset paths. These can name productions, clients, or projects, such as tank/projects/feature_s02. | Sent as-is |
| pools[].vdevs[].name, disk_ids[] | A single-disk vdev name follows the disk_id rule above. A member Pillar cannot resolve to a disk is sent under its raw name, such as a partition UUID. | Hashed or as-is |
| Network | ||
| network.interfaces[].mac | The vendor OUI (first three octets) is kept and the rest becomes xx:xx:xx. With redaction off, the full MAC is sent. | Masked |
| network.interfaces[].name | Interface name. USB adapter names such as enx3cecef123456 contain the full MAC. | Sent as-is |
| Posture and diagnostics | ||
| posture.mounts[], unexpected_mounts[], media_filesystems[] | The Agent container's mount table. Mount sources can include ZFS dataset names or NFS and SMB server:/export paths. | Sent as-is |
| smart[].raw_error, components[].detail | Error text from smartctl or the Observer connection. It can include device paths. | Sent as-is |
| Measurements | ||
| observer_windows[].latency_series, request_size_series | Per-disk histogram bucket counts, one set per window. Disk IDs are mapped to the Agent's (possibly redacted) disk_id, and any the Agent cannot map are dropped. The Observer never sees process names, file names, paths, or I/O contents. | Counts only |
| block, smart, network counters, pools[].capacity | Rates, latencies, temperatures, error counters, and byte totals, read from /proc/diskstats, sysfs, and SMART (smartctl -n standby, so idle drives are not spun up). No file contents are read. | Counts only |
Redaction is opt-in and is not anonymization
PILLAR_REDACT_METADATAdefaults tofalse.pillar configcannot set it yet. AddPILLAR_REDACT_METADATA=trueto the Agent'sruntime.envand restart the Agent.pillar installrewrites that file, so add the setting again after a reinstall.- Turn it on before pairing. Cloud keeps a serial it already received for a disk whose ID does not change, such as a WWN-identified disk.
- The serial token is an unsalted, truncated SHA-256 hash. Together with the masked serial's visible prefix and suffix, most real serials can be recovered by brute force. WWNs, SAS addresses, and enclosure IDs identify hardware just as uniquely and are never masked.
- Security Posture reports whether redaction is on (
posture.redaction_enabled) but does not evaluate it as a control.
4.Container isolation
| Control | Agent | Observer (optional) |
|---|---|---|
| Root filesystem | --read-only | --read-only |
| Capabilities | --cap-drop=ALL --cap-add=SYS_RAWIO | --cap-drop=ALL --cap-add=BPF,PERFMON |
| Privilege escalation | no-new-privileges:true | no-new-privileges:true |
| User | UID 0 | UID 0 (needed to load eBPF) |
| Network | Default bridge, outbound HTTPS only | --network none |
| Resource limits | --pids-limit 128, --memory 256m | --pids-limit 64, --memory 128m |
| Scratch space | /tmp tmpfs: noexec,nosuid,nodev,size=64m | /tmp tmpfs: noexec,nosuid,nodev,size=16m |
| Devices | /dev:ro; cgroup b *:* r and c 10:249 rw (/dev/zfs) | None |
| Host mounts (read-only) | /proc/diskstats, /sys/block, /sys/class/block, /sys/class/enclosure; host identity and platform version files | /sys/kernel/btf/vmlinux, /dev/disk/by-id |
| Writable volumes | /etc/pillar (credentials), /run/pillar (Observer socket) | /run/pillar |
| Not used | Docker socket, host PID, host network, --privileged | Docker socket, host PID, SYS_ADMIN, --privileged |
| Logs | json-file, 10 MB x 3 | json-file, 10 MB x 3 |
--cap-drop=ALLremoves Docker's defaults, such asCAP_DAC_OVERRIDE,CAP_SETUID,CAP_CHOWN, andCAP_NET_RAW.CAP_SYS_ADMINandCAP_NET_ADMINare never granted. The Agent reports unexpected capabilities inposture.unexpected_capabilities, and the Observer refuses to start with any capability beyond BPF and PERFMON.SYS_RAWIOpermits low-level device I/O, which SMART pass-through needs. It is broader than a singleSG_IOcall. Theb *:* rdevice rule makes block devices read-only at the kernel level, because a read-only/devbind alone would not./dev/zfsis read-write becausezpoolopens it that way even for queries. Pool configuration changes needCAP_SYS_ADMIN, which is not granted. Some dataset operations rely onzfs allowdelegation instead, so do not delegate ZFS permissions broadly on the host.posture.media_mounts_detectedchecks for/mnt/user,/mnt/disk1,/tank,/zfs, and/Volumesinside the container.posture.media_filesystemsflags any ZFS, NFS, CIFS/SMB, shfs, mergerfs, XFS, Btrfs, or ext4 mount outside the reference allowlist.- The Observer attaches read-only block-layer tracepoints (insert, merge, issue, requeue, complete). It needs Linux 5.11 or later with BTF, and its release probe-set digest is verified on upgrade.
5.Use Security Posture and export evidence
- Open Security Posture. The title row gives the one-line status (the evaluation's headline, how many nodes were evaluated, and when evidence was last verified). A note names any node whose evidence is not current; its controls count as not verified in every category.
- Under Controls by category, categories are listed worst first and the worst one is open. Open a category to see each control: what Pillar checks, how many nodes pass, which nodes do not and why, and what passing looks like. Each control also keeps its per-node evidence (observed and expected values, verification time and reason) one click away. Choose a node to open its posture drawer, or switch to By node or History.
- Read each control’s scope. Some checks are unsupported or not applicable, and missing evidence is not a pass. Deployment/configuration evidence is not a continuous scan for media access or a penetration test.
- Use history to investigate changes. A Facility Admin, Organization Admin, or Security Auditor can pick an evidence range (last 7, 30, or 90 days) in the title row and download a PDF report, JSON evidence bundle, or CSV control results.
- Review the selected facility, coverage, and report limits before sharing. Treat exported host identifiers and operational details as sensitive.
What verification means