Skip to content

Mass provisioning

The problem

Per-agent tokens are one-shot — one click in the dashboard yields one token good for one registration. That doesn’t scale when Terraform or an autoscaling group spins up 20 or 100 VMs in parallel. You want a single secret that all hosts may use, with a built-in counter and an expiry.

Enrolment tokens

An enrolment token (prefix enrl_) is a multi-use secret with:

  • max_uses — hard ceiling on the number of registrations
  • expires_at — TTL between 1 hour and 30 days
  • default_tags + default_role — auto-applied to every agent it registers
  • allowed_cidrs (optional) — source-IP allowlist for extra hardening
  • revoked_at — instant kill switch from the dashboard

The hub stores only the SHA-256; the raw token is shown once and from then on only lives in your secret store.

Mint a token

  1. Dashboard → Settings → Enrolment tokens
  2. Name: e.g. production-cluster-eu-west
  3. TTL: 72 h, max uses: 50, default tags: prod,eu-west,web, role: web
  4. (Optional) Allowed CIDRs: e.g. 10.0.0.0/8 if hosts sit inside the VPC
  5. Create — copy the enrl_… token immediately

Use in cloud-init

#cloud-config
runcmd:
- bash -c '
export MONSYS_TOKEN="enrl_xxxxx"
export MONSYS_TAGS="$(curl -fsS http://169.254.169.254/latest/meta-data/placement/availability-zone)"
curl -fsSL https://get.monsys.ai/install.sh | sudo -E bash
'

The installer detects the enrl_ prefix, calls POST /api/v1/agents/enrol on the hub, and gets a fresh per-agent token (agt_…) back. That token is written to /etc/monsys/agent.toml. The enrolment token is never persisted on the host — from then on the agent uses only its own one-shot token.

Use in Terraform

module "monsys" {
source = "git::https://github.com/gotrust/monsys.git//agent/packaging/terraform"
monsys_token = var.monsys_enrolment_token # from Vault / SOPS
tags = ["shard-${count.index}"]
role = "web"
}
resource "aws_instance" "web" {
count = 50
ami = "ami-..."
instance_type = "t4g.small"
user_data = module.monsys.cloud_init
}

50 instances, one secret. Every host comes up with its own agt_… token plus tags prod,eu-west,web,shard-N.

Use in Ansible

- name: install monsys agent
hosts: all
become: true
vars:
monsys_token: "{{ lookup('hashi_vault', 'secret/monsys/enrolment') }}"
tasks:
- shell: |
export MONSYS_TOKEN="{{ monsys_token }}"
export MONSYS_TAGS="{{ group_names | join(',') }}"
export MONSYS_ROLE="{{ ansible_role | default('') }}"
curl -fsSL https://get.monsys.ai/install.sh | bash
args:
creates: /etc/monsys/agent.toml

Tag merging

Token default_tags come first; tags passed via MONSYS_TAGS or the Terraform tags variable are appended (deduplicated). Same for role: the token default wins unless the installer is given an explicit MONSYS_ROLE.

Audit

Every registration is recorded in enrolment_uses with:

  • token id
  • new agent id
  • source IP
  • timestamp

When 100 agents appear in 5 minutes you can see immediately in the enrolment-tokens list which token authorised them, and you can revoke it in one click if there’s a suspicious host in the batch.

Failure modes

All cases below return 401 — deliberately indistinguishable to deny an attacker useful signal:

  • token doesn’t exist (wrong hash)
  • token expired (expires_at passed)
  • token revoked
  • max_uses reached
  • source IP outside allowed_cidrs

Operator feedback comes from the dashboard (uses counter, expiry, status).

Rotation

Tokens don’t renew themselves — you mint a new one and revoke the old when the batch is done. Registered agents keep working; only new registrations through that token are blocked.