Skip to content

Fleet MDM

Device management for Tractorbeam using Fleet.

Overview

Fleet provides:

  • Device inventory: Hardware specs, installed software, OS versions
  • MDM (Mobile Device Management): Configuration profiles, remote wipe, app deployment
  • Osquery: Real-time device queries for security and compliance
  • Self-service: Users can install approved software via Fleet Desktop
┌─────────────────────────────────────────────────────────────────────────────┐
│                           fleet.tractorbeam.ai                               │
│                                                                              │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐                   │
│  │   ECS Task   │    │ Aurora MySQL │    │  ElastiCache │                   │
│  │  (Fleet Go)  │◄──►│   (fleetdb)  │    │   (Valkey)   │                   │
│  └──────────────┘    └──────────────┘    └──────────────┘                   │
│         ▲                                                                    │
└─────────│────────────────────────────────────────────────────────────────────┘
          │ HTTPS (443)

    ┌─────┴─────┐
    │    ALB    │
    └───────────┘


   ┌──────┴──────┐
   │   Devices   │
   │ (macOS/iOS) │
   └─────────────┘

Infrastructure: Terraform in aws/modules/fleet/

Accessing Fleet

URLPurpose
https://fleet.tractorbeam.aiAdmin UI and API
https://fleet.tractorbeam.ai/healthzHealth check

Authentication: Login with your Tractorbeam email. Fleet uses local auth (no SSO yet).

MDM Setup

Fleet MDM requires several Apple certificates and integrations.

Prerequisites

Before MDM can issue enrollment profiles, configure these in Fleet:

ComponentPurposeLocation in Fleet
APNs CertificatePush notifications to devicesSettings → Integrations → MDM → Apple Push
ABM TokenAutomatic device enrollmentSettings → Integrations → MDM → Apple Business Manager
SCEP CertificateDevice identity certificatesAuto-generated by Fleet

Apple Business Manager (ABM):

  1. Log in to business.apple.com
  2. Settings → Device Management Settings
  3. Add Fleet as an MDM server
  4. Set "Default Server Assignment" for personal devices to Fleet

BYOD Enrollment

Fleet supports two BYOD enrollment methods depending on the platform.

iOS/iPadOS: Account-driven User Enrollment

Platform: iOS and iPadOS only. macOS is not supported by Fleet for account-driven enrollment, even though Apple supports it on macOS 14+. This is a Fleet limitation - they only implemented iOS/iPadOS support in Fleet 4.72.0.

For personal iPhones and iPads, users can enroll via their Managed Apple Account:

  1. Open Settings → General → VPN & Device Management
  2. Tap Sign In to Work or School Account
  3. Enter Tractorbeam email (Okta credentials via federated auth)
  4. Device automatically enrolls in Fleet

Service Discovery: Apple discovers the MDM server via a well-known file:

  • File location: marketing repo at public/.well-known/com.apple.remotemanagement
  • For iOS 18.2+, Fleet can manage service discovery automatically via ABM
  • The well-known file is a fallback for older devices

See: Fleet BYOD Guide

macOS: Manual Enrollment Profile

Platform: macOS only. This is the only BYOD method for personal Macs not in ABM.

Why not account-driven? Apple supports Account-driven User Enrollment on macOS 14+, but Fleet hasn't implemented macOS support yet. If you try "Sign In to Work or School Account" on a Mac, you'll get "Did not receive an enrollment profile from your MDM server."

For personal Macs, users must manually install an enrollment profile:

  1. In Fleet UI: Hosts → Add hosts → macOS tab
  2. Copy the enrollment URL (team-specific, contains enroll secret)
  3. Share the URL with users (email, Slack, etc.)
  4. User opens URL, downloads enrollment profile
  5. User installs profile: System Settings → Privacy & Security → Profiles

This gives IT management capabilities while the Mac remains a personal device.

See: Fleet macOS MDM Setup

Company-owned Device Enrollment

Devices purchased through Apple Business Manager enroll automatically:

  1. Device powers on and connects to network
  2. ABM directs device to Fleet
  3. Fleet sends enrollment profile
  4. Device enrolls and applies configurations

GitOps Configuration

Fleet configuration is managed via GitOps in fleet-config/.

fleet-config/
├── default.yml          # Global settings (all teams)
├── teams/               # Team-specific configs
│   ├── workstations.yml
│   ├── byod.yml
│   └── personal-mobile.yml
├── lib/                 # Shared policies and queries
│   ├── all/
│   └── macos/
└── gitops.sh            # Apply script

Applying Changes

Changes deploy automatically via GitHub Actions (.github/workflows/fleet-gitops.yml).

Manual apply:

bash
cd fleet-config
export FLEET_URL="https://fleet.tractorbeam.ai"
export FLEET_API_TOKEN="..."  # From Secrets Manager
./gitops.sh

Configuration Reference

See Fleet GitOps docs.

CLI Tools

fleetctl

bash
# Install
brew install fleetdm/tap/fleetctl

# Configure
fleetctl config set --address https://fleet.tractorbeam.ai
fleetctl login

# Common commands
fleetctl get hosts                    # List enrolled devices
fleetctl get host <hostname>          # Device details
fleetctl query --query "SELECT * FROM users" --hosts <hostname>

Secrets

SecretLocationPurpose
Database passwordtractorbeam-fleet/database-passwordAurora MySQL
License keytractorbeam-fleet/license-keyFleet Premium
Private keyfleet-server-private-keySession encryption
GitOps tokentractorbeam/github-actions/fleetCI/CD

Note: The tractorbeam-fleet/ prefix predates the naming convention (tractorbeam/fleet/). See the migration plan in docs/standards/naming-conventions.md.

Operations

AWS Authentication

All commands require AWS credentials for the Shared Services account:

bash
# SSO login (if configured)
aws sso login

# Or assume role from management account
export AWS_PROFILE=shared-services

Viewing Logs

Fleet logs are in CloudWatch Logs in the Shared Services account (707264479446).

bash
# Assume role to Shared Services (from management account)
CREDS=$(AWS_PROFILE=root aws sts assume-role \
  --role-arn "arn:aws:iam::707264479446:role/OrganizationAccountAccessRole" \
  --role-session-name "fleet-logs" --output json)

export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo "$CREDS" | jq -r '.Credentials.SessionToken')

# Find Fleet log group (name is auto-generated by Terraform)
aws logs describe-log-groups --query 'logGroups[*].logGroupName' --output table

# Stream live logs (last 5 minutes, follow)
# Replace LOG_GROUP with actual name from above (e.g., terraform-2026...)
aws logs tail $LOG_GROUP --since 5m --follow

# Search for MDM enrollment attempts
aws logs filter-log-events \
  --log-group-name $LOG_GROUP \
  --start-time $(($(date +%s) - 3600))000 \
  --filter-pattern "account_driven_enroll" \
  --query 'events[*].message' --output text

# Search for errors
aws logs filter-log-events \
  --log-group-name $LOG_GROUP \
  --start-time $(($(date +%s) - 3600))000 \
  --filter-pattern "level=error" \
  --query 'events[*].message' --output text | tr '\t' '\n' | head -50

ECS Service Status

bash
# Check service status (requires Shared Services role - see above)
aws ecs describe-services \
  --cluster tractorbeam-fleet \
  --services fleet \
  --query 'services[0].{status:status,running:runningCount,desired:desiredCount,events:events[0:3]}'

# List running tasks
aws ecs list-tasks --cluster tractorbeam-fleet --service-name fleet

# Get task details
TASK_ID=$(aws ecs list-tasks --cluster tractorbeam-fleet --service-name fleet \
  --query 'taskArns[0]' --output text | cut -d'/' -f3)
aws ecs describe-tasks \
  --cluster tractorbeam-fleet \
  --tasks $TASK_ID \
  --query 'tasks[0].{status:lastStatus,startedAt:startedAt,taskDef:taskDefinitionArn}'

# Get log configuration from task definition
aws ecs describe-task-definition \
  --task-definition fleet:3 \
  --query 'taskDefinition.containerDefinitions[0].logConfiguration'

# Force new deployment (rolling restart)
aws ecs update-service \
  --cluster tractorbeam-fleet \
  --service fleet \
  --force-new-deployment

Database Connectivity

bash
# Check RDS cluster status
aws rds describe-db-clusters \
  --db-cluster-identifier tractorbeam-fleet \
  --query 'DBClusters[0].{status:Status,endpoint:Endpoint,reader:ReaderEndpoint}'

Health Checks

bash
# Fleet health endpoint
curl -s https://fleet.tractorbeam.ai/healthz && echo "OK"

# Service discovery endpoint (after marketing PR merges)
curl -s https://tractorbeam.ai/.well-known/com.apple.remotemanagement | jq .

# Check MDM enrollment endpoint responds
curl -s -o /dev/null -w "%{http_code}" \
  https://fleet.tractorbeam.ai/api/mdm/apple/account_driven_enroll

ALB Metrics

bash
# Get ALB ARN
ALB_ARN=$(aws elbv2 describe-load-balancers \
  --names tractorbeam-fleet \
  --query 'LoadBalancers[0].LoadBalancerArn' --output text)

# Check target health
aws elbv2 describe-target-health \
  --target-group-arn $(aws elbv2 describe-target-groups \
    --load-balancer-arn $ALB_ARN \
    --query 'TargetGroups[0].TargetGroupArn' --output text)

Troubleshooting

"Did not receive an enrollment profile"

This error during BYOD enrollment means Fleet isn't returning a valid profile.

Step 0: Check platform support (most common cause for macOS)

Account-driven User Enrollment (Settings → Sign In to Work or School Account) only works on iOS and iPadOS in Fleet. If you see this error on macOS, that's expected - Fleet hasn't implemented macOS support for account-driven enrollment yet (as of Feb 2026), even though Apple supports it on macOS 14+. Use manual enrollment instead - see macOS: Manual Enrollment Profile.

Step 1: Verify service discovery is working (iOS/iPadOS only)

bash
# Should return JSON with BaseURL pointing to Fleet
curl -s https://tractorbeam.ai/.well-known/com.apple.remotemanagement | jq .

# Check Content-Type header is application/json
curl -sI https://tractorbeam.ai/.well-known/com.apple.remotemanagement | grep -i content-type

Step 2: Check Fleet MDM configuration

  • MDM enabled? (Settings → Integrations → MDM)
  • APNs certificate uploaded and valid (not expired)?
  • ABM token connected and not expired?

Step 3: Check Fleet logs for enrollment errors

bash
# Assume role to Shared Services first (see Operations section)
# Find log group name
LOG_GROUP=$(aws logs describe-log-groups --query 'logGroups[?starts_with(logGroupName, `terraform-`)].logGroupName' --output text)

# Search for MDM enrollment attempts
aws logs filter-log-events \
  --log-group-name $LOG_GROUP \
  --start-time $(($(date +%s) - 3600))000 \
  --filter-pattern "account_driven_enroll" \
  --query 'events[*].message' --output text

# Look for: "level=error ... user=unauthenticated" = auth failure
# Look for: "level=info ... serving MDM service discovery" = service discovery working

Step 4: Check APNs and DEP sync status

bash
# Verify APNs pusher is running
aws logs filter-log-events \
  --log-group-name $LOG_GROUP \
  --start-time $(($(date +%s) - 3600))000 \
  --filter-pattern "apple_mdm_apns_pusher status=completed" \
  --query 'length(events)'

# Verify DEP sync with ABM
aws logs filter-log-events \
  --log-group-name $LOG_GROUP \
  --start-time $(($(date +%s) - 3600))000 \
  --filter-pattern "nanodep-syncer" \
  --query 'events[*].message' --output text | tr '\t' '\n' | tail -5

Common causes:

  • APNs certificate not uploaded or expired
  • ABM token expired (renew annually)
  • Domain not verified in ABM
  • IdP (Okta) not federated with ABM

Device not appearing in Fleet

  1. Check device has network connectivity
  2. Verify enrollment completed (Settings → VPN & Device Management)
  3. Wait a few minutes for initial check-in
  4. Check Fleet activity log for errors

MDM commands not executing

  1. Verify APNs certificate is valid (not expired)
  2. Check device has internet access
  3. Try manually triggering a check-in from device settings

Service discovery returns 404

The well-known file is missing or misconfigured. Check:

  1. File exists in marketing repo: public/.well-known/com.apple.remotemanagement
  2. Marketing site is deployed
  3. No redirect/rewrite interfering (Vercel doesn't allow rewrites on .well-known)