Host Hardening
The Riptides kernel module is reachable only by a process holding
CAP_SYS_ADMIN — see Kernel Interface. On
SELinux hosts an optional package narrows that further, so that only the
daemon’s own SELinux domain, and privileged containers, can open its devices
through /dev, whatever capabilities a process holds.
Nothing on this page is required, with one exception: on a host that enforces
module signatures (Secure Boot, or module.sig_enforce=1), the driver does not
load until its signing certificate is enrolled.
Otherwise the driver runs without it, and the capability check is independent of
SELinux.
The SELinux policy
Section titled “The SELinux policy”riptides-selinux ships a policy module that:
- gives the daemon its own domain,
riptides_t, entered when systemd executes/usr/bin/riptides - labels the module’s devices,
/dev/riptidesasriptides_device_tand/dev/riptides_proasriptides_pro_device_t - grants access to those device types to
riptides_t, and to privileged containers, which is how the daemon runs on Kubernetes (below)
With it installed and SELinux enforcing, a root shell on the host cannot open
either device through /dev.
It is built per distribution release, because a compiled policy module is tied
to the selinux-policy version it was built against.
sudo dnf install riptides-selinuxVerifying it
Section titled “Verifying it”# the module is loadedsudo semodule -l | grep riptides
# the devices carry the policy's label (needs the driver loaded)sudo ls -Z /dev/riptides /dev/riptides_pro
# and the daemon is in its own domainps -eZ | grep riptidesThe device check is the one that matters, and a working policy makes it fail:
root may not even look at a confined device, so Permission denied is the
result you want. If ls -Z shows device_t instead, the policy is loaded but
confining nothing. That happens when the driver was loaded before the policy was
installed and the node never got relabeled; have udev relabel it:
sudo udevadm trigger --action=add /sys/class/riptides/riptides /sys/class/misc/riptides_proWhat it does not confine
Section titled “What it does not confine”Root with a device node of its own. SELinux checks the label of the node
being opened, not the device behind it. Root can create another node for the
same device outside /dev and open the driver through that, as it could also
load a kernel module of its own. So the policy stops casual and accidental
access by root, not a determined attacker holding root; against that, the
control is the module’s capability check and who holds CAP_SYS_ADMIN.
The daemon itself. It reads /proc of every process on the host to
attribute connections to workloads, and manages the system trust store, so a
policy permitting its real behaviour would be broad enough to carry little
value. The policy confines the device, not the daemon.
Kubernetes. The daemon runs there as a privileged container, which does not
enter riptides_t, so the policy grants privileged containers access to the
device — without that the DaemonSet could not start. On a Kubernetes node the
controls are the module’s capability check and who is permitted to schedule a
privileged pod. A privileged pod can already load its own kernel module.
AppArmor hosts
Section titled “AppArmor hosts”There is no AppArmor profile, and this is a considered position rather than an omission.
AppArmor is path-based and only restricts processes that carry a profile, so it
cannot express “this device is reachable by the daemon alone” against the
unprofiled processes that are the concern. A profile confining the daemon
itself would have to permit reading every process’s memory maps and executables,
ptrace, and a broad capability set — which is not meaningfully different from
running unconfined.
On Debian and Ubuntu hosts the control is therefore the CAP_SYS_ADMIN check in
the module. If your policy requires a profile for third-party daemons, contact
us and we will supply one, with that caveat stated.
Failing closed
Section titled “Failing closed”By default the module fails open: if policy evaluation cannot complete, the connection proceeds unprotected rather than breaking. That keeps a control-plane problem from becoming an application outage, but it means a loss of protection is invisible to the application, which still succeeds.
Deployments that prefer the opposite trade-off should set:
echo Y | sudo tee /sys/module/riptides/parameters/eval_fail_closedConnections are then reset instead, whether the evaluation that failed was the one made when the connection opened or a message’s traffic evaluation (L7 and agent policy). Traffic the daemon receives but cannot parse is still passed through: that is the daemon’s own choice, not a failed evaluation.
It does not cover a daemon that is down. Until the daemon is connected and
has pushed its configuration, trust anchors and a workload identity, the module
evaluates no new connection at all and lets each one through untouched, with or
without eval_fail_closed. That is the state after a daemon crash, a restart,
or a write to /sys/class/riptides/force_close, which kills the daemon.
Monitor for it either way: command timeout lines in dmesg mark evaluations
the daemon did not answer, and /sys/module/riptides/health should read OK.
Alert on anything else: Waiting for daemon, Daemon is connected, but no workload identity defined. and OK (disabled) all mean new connections are not
being protected.
Module signing and Secure Boot
Section titled “Module signing and Secure Boot”The driver modules (riptides, bearssl and riptides_pro) are signed with the
Riptides module signing key. Every driver package installs its certificate at
/usr/share/riptides/riptides-module-signing.der, but nothing enrolls it, so on
a host enforcing module signatures (Secure Boot, or module.sig_enforce=1) the
modules will not load until you do.
The certificate is also published here, so you can enroll a host before the driver is installed, or build it into an image:
- riptides-module-signing.der (DER, what
mokutiltakes) - riptides-module-signing.crt (PEM, shown below)
-----BEGIN CERTIFICATE-----MIIFjzCCA3egAwIBAgIUatq7ho6YUnE566bvrVBfcNZDTfowDQYJKoZIhvcNAQELBQAwRjEsMCoGA1UEAwwjUmlwdGlkZXMgTGFicyBrZXJuZWwgbW9kdWxlIHNpZ25pbmcxFjAUBgNVBAoMDVJpcHRpZGVzIExhYnMwHhcNMjYwOTIyMTQwNTM3WhcNMzYwOTE5MTQwNTM3WjBGMSwwKgYDVQQDDCNSaXB0aWRlcyBMYWJzIGtlcm5lbCBtb2R1bGUgc2lnbmluZzEWMBQGA1UECgwNUmlwdGlkZXMgTGFiczCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANI7J5CGf5JcL6B3mjHtow/Ll1UfqrKOQNf6dFO3w4OvGbAWOfh0yn42XGyGX8SJbZJMdwVtpRz/zl8dS1Knwi5OLD+5gwg0TxznTCTAH/WMZYVcQ9ZNj0aLJvy5VkT+SC6Uq7WJ3rnliNUghfGS7C60umJIIYJtHLCRnEfmPnMWc5WNZk9bupfC8uSkwS0t8m/VAuRrEAMW8UBgbV3gjqxN8lf5X8AOW+NQt6wCFEpSKRFnQzQ7MCEzP2/eswWUic1vykNAzaaJeQ6wSz58p8ALXG8v5A/qaqzBlRskbge3Rqlk+Ql3Xl7lRLCc/UO3mZHL5KwNOxrKuNAH3qw+SYm5sAEnGPYTVDuhvrVi7RZf/A0qxT82DsEPGsWfJ5Skgxhg0srClGnGLxu6cJ2PApyb/h8fWgiEBlBRHmaztlLzLumZAlU88kwF9rDu+p1QxDir+b11S2Zp5560A8qAU/nVVPxlUJYbT9KGy2RYnQ+4iQhkk0QRNCzWVp1S3V3HCTxYREPYaofyodwkrSgs5ULSvdTfiA6fqgLIYtjYxwhx10fIuEq16yOLEv5dhpJC3brkRABY5RDae3sPH0zg3AyDJ9Y/mrTPtNZM2r1XNtDAK9rpg/vsDKm4ucID1hVwpOQco3wKI4m2GcQ6K1NCshy//0Ri9o9ik24kK0swjdVrAgMBAAGjdTBzMB8GA1UdIwQYMBaAFNqT+f+3qEmshelMTkbKL6Js3YmcMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBTak/n/t6hJrIXpTE5Gyi+ibN2JnDANBgkqhkiG9w0BAQsFAAOCAgEAo0QIh/mXwcY3NXXCSpOJGZiiG7FrnXVOnUD4GIaCybDfbuCMBUsQVEgwoM9jbam0YNWSRoqi4+6CyECp83d4+PMEg2BfXJjuzznm++SQE4nQCLJ/o/TcLy4t/OK3yIzMyGAUMHKQJy7rm9SQ2ZdWUJ5VEMZRxhxkMw2CU3CQaQwSX4BXHAtP8b2XSywo4v+ZcoeRSfrvkPyxyM5weGQqvXzNRe0ZmBQmXmjlyt2PZnxyMQhEUgi23Vw8nO90HHN2WqVER8pCuHvSq3Ui0jc+/lhkW4NSOxS0fvfwsT1LqrVcSqg9LSHnw5dKK9oZEe5qNZmny9Q3WRppI8wb+gfFHYvA8vTR2nYkhbbdge5n/4HPxGW4NjUFKxZVNVS29taG+vkphcP6sVKDif0ScKgbkQDvp3jvE8JhuKn33FOJX81B6x4Yk9ub3q0nMphE758RQyz4OZi5bIYDPfu19217YfCUmhfRwmOhxCFnKAqmwHbqBA8MZ9uVKwkGFMLpS90kgXNXBAN83h/KzWUwrpstWcbBHIXaOwbjKWClUVoc0+SjgmVU81ypkjQPgXii9j1kRrFPlu7d5DojHN129dSajkfnjr0HfQCYWW93n+u1SDv0V4vmOD+hd2rMMbgnSrwTRavV26h8TLG1yxHmE9WuUdZwW0tEt51fG90XDUNKLYE=-----END CERTIFICATE-----Check the certificate before you trust it, wherever it came from. Its SHA-256 fingerprint is:
37:A5:43:0A:17:19:A5:30:44:46:15:D5:15:56:0D:19:97:FB:6A:D4:D5:76:6C:2C:62:54:78:E6:B5:16:58:CAEnrolling the certificate
Section titled “Enrolling the certificate”Enrolling needs access to the host’s console at the next boot. mokutil ships
with Ubuntu and Debian; on RHEL-family hosts install it with
sudo dnf install mokutil.
Use the installed copy, or download the published one if the driver is not installed yet:
CERT=/usr/share/riptides/riptides-module-signing.der# or, before installing:curl -fsSLO https://docs.riptides.io/keys/riptides-module-signing.derCERT=./riptides-module-signing.derCheck its fingerprint against the one above, then queue the enrollment:
openssl x509 -inform DER -in "$CERT" -noout -fingerprint -sha256sudo mokutil --import "$CERT"sudo mokutil --timeout -1sudo rebootmokutil --import asks for a one-time password and only queues the request.
mokutil --timeout -1 makes MokManager wait for you at the next boot; by
default it gives up after 10 seconds and the request is dropped. At the next
boot MokManager shows a blue screen with Continue boot selected: pressing
Enter there boots without enrolling and drops the request. Move down to
Enroll MOK first, then choose Continue and Yes, enter the password,
and reboot.
On Azure, the VM’s Serial Console reaches MokManager, including on Trusted Launch VMs; boot diagnostics must be enabled. Where you cannot reach a boot console at all, disable Secure Boot instead.
After the reboot
Section titled “After the reboot”Confirm the certificate is enrolled:
mokutil --list-enrolled | grep -i riptidesIf that prints nothing, the MokManager screen was missed: queue the enrollment again. If the driver is already installed, load the modules; otherwise install it now, and the installer loads them:
sudo systemctl restart riptides-modulesO (out-of-tree) is expected in /sys/module/riptides/taint. An E means the
kernel could not verify the signature. That is normal when Secure Boot is off
and the certificate is not enrolled; with Secure Boot on, a module that fails
verification is not loaded at all.
Not yet qualified
Section titled “Not yet qualified”Secure Boot with the certificate enrolled has been checked on Ubuntu 24.04 on an
Azure Trusted Launch VM, in kernel lockdown (integrity): the modules load, the
daemon connects, health reads OK and connections are tracked. Policy
enforcement (mTLS, credential injection) has not been tested under lockdown. If
you run Secure Boot, talk to us before a deployment rather than after.