Deploy Device Protection with Puppet
Use a Puppet class to install Device Protection on the Linux nodes your Puppet agent already manages. The class below picks the right package per platform, installs it with your user group token, and keeps the service running on every run.
Read Deploying on Linux first for the token, the package list, and the reboot behaviour that applies to every method.
Module layout
modules/aikido_device_protection/
└── manifests/init.pp
data/
└── groups/developers.yamlSet up the class
Store the token in Hiera eyaml
Encrypt the token for the group of nodes that maps to your Aikido user group:
eyaml encrypt -l 'aikido_device_protection::token' -s '<your-token>'Paste the output into the matching Hiera layer:
---
aikido_device_protection::token: >
ENC[PKCS7,MIIBiQYJKoZIhvcNAQcDoIIBejCCAXYCAQAxggEhMIIBHQIBADAFMAACAQEw...]The class parameter is typed Sensitive, and Puppet wraps values coming from Hiera automatically, so nothing else is needed.
Add the class
class aikido_device_protection (
Sensitive[String[1]] $token,
String[1] $release_url = 'https://github.com/AikidoSec/safechain-internals/releases/latest/download',
) {
$arch = $facts['os']['architecture'] ? {
/^(aarch64|arm64)$/ => 'arm64',
default => 'amd64',
}
case $facts['os']['family'] {
'Debian': {
$package_file = "EndpointProtection-${arch}.deb"
$install_command = 'apt-get install -y'
$installed_check = "dpkg-query -W -f='\${db:Status-Status}' aikido-endpoint-protection 2>/dev/null | grep -qx installed"
}
'RedHat': {
$package_file = "EndpointProtection-${arch}.el${facts['os']['release']['major']}.rpm"
$install_command = 'dnf install -y'
$installed_check = 'rpm -q aikido-endpoint-protection'
}
default: {
fail("Aikido Device Protection does not support ${facts['os']['family']}")
}
}
$package_path = "/var/cache/aikido/${package_file}"
file { '/var/cache/aikido':
ensure => directory,
owner => 'root',
group => 'root',
mode => '0700',
}
exec { 'download aikido-endpoint-protection':
command => "curl -fsSLo ${package_path} ${release_url}/${package_file}",
provider => shell,
path => ['/usr/bin', '/bin'],
creates => $package_path,
unless => $installed_check,
require => File['/var/cache/aikido'],
}
$install_script = @("SCRIPT")
#!/bin/sh
set -e
export AIKIDO_TOKEN='${$token.unwrap}'
exec ${install_command} ${package_path}
| SCRIPT
file { '/usr/local/sbin/aikido-install':
ensure => file,
owner => 'root',
group => 'root',
mode => '0700',
content => Sensitive($install_script),
}
exec { 'install aikido-endpoint-protection':
command => '/usr/local/sbin/aikido-install',
provider => shell,
path => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'],
unless => $installed_check,
require => [
Exec['download aikido-endpoint-protection'],
File['/usr/local/sbin/aikido-install'],
],
}
service { 'aikido-endpoint-protection':
ensure => running,
enable => true,
require => Exec['install aikido-endpoint-protection'],
}
}The download uses curl, which minimal images sometimes leave out. If yours does, install it alongside this class.
Classify your nodes
Declare the class where you classify nodes, through roles and profiles, the Puppet Enterprise console, or site.pp:
include aikido_device_protectionThe next agent run installs the agent. Classify one group first, then widen.
Why a script and not an exec environment
The package reads AIKIDO_TOKEN while it installs, so the token has to be in the environment of the process that runs apt-get or dnf. Passing it through environment => ["AIKIDO_TOKEN=..."] on the exec works, but Puppet does not treat that attribute as sensitive: the token then shows up in agent logs and in reports sent to the primary server.
Writing it into a root-only script whose content is wrapped in Sensitive() avoids that. Puppet redacts sensitive content from logs, reports, and --noop diffs.
The token still lands on disk in two places. /usr/local/sbin/aikido-install holds it in plaintext, and because the file resource has no guard, Puppet keeps that script in place long after the node is installed. The catalog cached under /opt/puppetlabs/puppet/cache contains it too, because the agent needs the value to apply the resource. Both are root-only. Treat them as sensitive, and keep report access restricted.
Once a group of nodes is installed, switching the file resource to ensure => absent clears the script from all of them. Put it back before the next new node joins that group.
Keep runs idempotent
unless => $installed_check guards the download and the install, so nodes that already run the agent do nothing. The token is only needed on first install, and upgrades keep the device's registration.
On the Debian family the check is dpkg-query, not dpkg -s. dpkg -s also succeeds for a package that was removed but not purged, so a node where someone ran apt remove aikido-endpoint-protection would look installed to Puppet and never be brought back. That check is a pipeline, and exec does not use a shell by default, which is what provider => shell is there for.
Handle the reboot
Installing sets the Aikido CA environment variables system-wide, and running shells only pick them up after a new login shell or a reboot. Puppet has no built-in reboot resource, so either ask users to log out and back in, or handle the reboot with your existing maintenance tooling. If you already use puppetlabs-reboot, notify it from the install exec.
Verify the rollout
On a node that has run:
The device then appears in your device list with an Active status.
Troubleshooting
The package installs but the device never appears in the dashboard
AIKIDO_TOKEN was not set for the install command. Configuration management tools do not forward your local environment to the host, so set the variable on the task itself, then install the package again
apt or dnf looks for the package in your repositories instead of installing the file
Pass a path, not a name: apt install ./EndpointProtection-amd64.deb. The leading ./ is what makes the package manager treat it as a local file
The install fails on a Red Hat-family host
Match the build to the major version: use the el9 package on version 9 and the el10 package on version 10
The service is not running
Run systemctl status aikido-endpoint-protection, then sudo aikido-doctor diagnostics to send us the details
Node.js or uv still reject the Aikido certificate
Installing sets NODE_EXTRA_CA_CERTS and UV_SYSTEM_CERTS system-wide, and running shells do not pick them up. Open a new login shell or reboot the device
The token shows up in run output or logs
Use your tool's redaction: no_log in Ansible, sensitive true in Chef, Sensitive() in Puppet
Several machines share one entry in the device list
They booted with the same /etc/machine-id. Device identity on Linux follows that file, so clear it in the image you clone from and let systemd write a fresh one on first boot
No tray icon appears
Expected on GNOME outside Ubuntu, and cosmetic. See Tray Icon Support on Linux
Last updated
Was this helpful?