For the complete documentation index, see llms.txt. This page is also available as Markdown.

Deploy Device Protection with Ansible

Use Ansible to install Device Protection across your Linux fleet. The role below picks the right package for each host, installs it with your user group token, and leaves the service enabled.

Read Deploying on Linux first for the token, the package list, and the reboot behaviour that applies to every method.

Role layout

roles/aikido_device_protection/
├── defaults/main.yml
├── handlers/main.yml
└── tasks/main.yml
group_vars/
└── developer_workstations.yml
site.yml

Set up the role

1

Add the defaults

roles/aikido_device_protection/defaults/main.yml
---
aikido_release_url: https://github.com/AikidoSec/safechain-internals/releases/latest/download

# Reboot after installing. See "Handle the reboot" below.
aikido_reboot: false
2

Add the tasks

The first task decides whether there is anything to do, so repeat runs are cheap and never touch the token.

roles/aikido_device_protection/tasks/main.yml
---
- name: Check whether Device Protection is already installed
  ansible.builtin.command: aikido-doctor --simple
  register: aikido_installed
  changed_when: false
  failed_when: false

- name: Install Device Protection
  when: aikido_installed.rc != 0
  block:
    - name: Work out the package architecture
      ansible.builtin.set_fact:
        aikido_arch: "{{ 'arm64' if ansible_facts['architecture'] == 'aarch64' else 'amd64' }}"

    - name: Work out the package name
      ansible.builtin.set_fact:
        aikido_package: >-
          {{
            'EndpointProtection-' ~ aikido_arch ~ '.deb'
            if ansible_facts['os_family'] == 'Debian'
            else 'EndpointProtection-' ~ aikido_arch ~ '.el'
                 ~ ansible_facts['distribution_major_version'] ~ '.rpm'
          }}

    - name: Download the package
      ansible.builtin.get_url:
        url: "{{ aikido_release_url }}/{{ aikido_package }}"
        dest: "/tmp/{{ aikido_package }}"
        mode: "0600"

    - name: Install the package on Debian and Ubuntu
      ansible.builtin.apt:
        deb: "/tmp/{{ aikido_package }}"
      environment:
        AIKIDO_TOKEN: "{{ aikido_token }}"
      no_log: true
      when: ansible_facts['os_family'] == 'Debian'
      notify: Reboot to activate Device Protection

    - name: Install the package on RHEL, Rocky Linux and CentOS
      ansible.builtin.dnf:
        name: "/tmp/{{ aikido_package }}"
        state: present
      environment:
        AIKIDO_TOKEN: "{{ aikido_token }}"
      no_log: true
      when: ansible_facts['os_family'] == 'RedHat'
      notify: Reboot to activate Device Protection

    - name: Remove the downloaded package
      ansible.builtin.file:
        path: "/tmp/{{ aikido_package }}"
        state: absent

- name: Make sure the service is enabled and running
  ansible.builtin.systemd_service:
    name: aikido-endpoint-protection
    state: started
    enabled: true

The role needs facts, so leave gather_facts on. distribution_major_version is what selects the el9 or el10 build.

3

Store the token in Ansible Vault

Encrypt the token for the inventory group that maps to your Aikido user group:

ansible-vault encrypt_string --name aikido_token '<your-token>'

Paste the output into the group's variables:

group_vars/developer_workstations.yml
---
aikido_token: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  62313365396662343061393464336163383764373764613633653634306231386433626436623361
  ...

Repeat per group if you use more than one user group. Each group gets its own token and its own group_vars file.

If the token already lives in your CI secrets, read it from the controller's environment instead of committing a vaulted copy: aikido_token: "{{ lookup('env', 'AIKIDO_TOKEN') }}".

4

Write the playbook and run it

site.yml
---
- name: Deploy Aikido Device Protection
  hosts: developer_workstations
  become: true
  serial: 20%
  roles:
    - aikido_device_protection

Start with a few machines, then widen:

ansible-playbook site.yml --ask-vault-pass --limit pilot
ansible-playbook site.yml --ask-vault-pass

How the token reaches the package

The package reads AIKIDO_TOKEN while it installs. The task-level environment keyword is what puts it there: Ansible sets those variables around the module invocation on the host, so the dpkg or dnf process the module starts inherits them. This works with become: true, because the variables are set inside the privilege escalation wrapper.

Setting AIKIDO_TOKEN in your own shell before running ansible-playbook does nothing. Ansible does not forward the controller's environment to the host.

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. The role ships with a handler that stays off by default:

Set aikido_reboot: true for hosts nobody is working on. On developer machines, leave it off and ask people to log out and back in, or reboot in a maintenance window.

Verify the rollout

The devices then appear in your device list with an Active status.

Troubleshooting

Problem
Fix

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?