Appearance
Connect AWS
Connecting an AWS account lets Kadmo run agents on EC2 machines in that account. You create an IAM user with a least-privilege policy, paste its access key into the app, and name the subnet agents launch in. From then on Kadmo handles each agent machine's whole life: launch, reboot, stop, start and terminate. This guide covers the account setup, the exact policy, where the keys go in the app, what Kadmo creates, and the fix for every error the app shows.
In this release
The app reaches agents over Kadmo's private network. An AWS connection therefore needs an agent subnet that is peered with Kadmo's network, and agents launch only in that subnet's region. Kadmo sets up the peering with you: book a call before you plan the account. Until the subnet is set, the AWS card reads "Not set: agents cannot launch until it is". See The agent subnet.
Before you start
- An AWS account in which you can create IAM users and policies, with console or CLI access.
- The admin role on your Kadmo account: cloud connections are admin-only.
- About ten minutes.
Run agents away from your production workloads: set up a dedicated AWS account first, then do Steps 1 to 4 inside it.
Recommended: a dedicated AWS account
The policy below grants its actions on Resource: "*". In a shared account that means the Kadmo user could describe or terminate any EC2 instance there, not only agents. An account of their own removes that risk and keeps your existing setup untouched.
| Benefit | Why it matters |
|---|---|
| Blast-radius isolation | Resource: "*" then reaches only agent resources; your production instances live in an account these credentials cannot see |
| No interference | Kadmo creates security groups, key pairs and tags; in a clean account they never collide with existing infrastructure or drift detection |
| Cost separation | The account's bill is the agent spend: filter by linked account in Cost Explorer, or set an AWS Budget on it alone |
| Quota isolation | vCPU quotas are per account and region, so agents cannot use up production launch capacity, and the other way round |
| Clean teardown | Close the account and everything in it is gone |
Create the member account (AWS Organizations)
- In your management account, open AWS Organizations → AWS accounts → Add an AWS account → Create an AWS account.
- Name it, for example
kadmo-agents, and give it a unique e-mail address. Plus-addressing works well, for exampleaws+kadmo-agents@example.com. - Keep the default IAM role name
OrganizationAccountAccessRole.
Or with the CLI:
bash
aws organizations create-account \
--email aws+kadmo-agents@example.com \
--account-name "Kadmo Agents"
# repeat until the state is SUCCEEDED, then note the new account ID
aws organizations list-create-account-status --states SUCCEEDEDTo work in the new account, use Switch role in the console (the account ID and the role OrganizationAccountAccessRole), or add a CLI profile:
toml
# ~/.aws/config
[profile kadmo-agents]
role_arn = arn:aws:iam::<member-account-id>:role/OrganizationAccountAccessRole
source_profile = managementThen do Steps 1 to 4 inside that account. Do not reuse an IAM user or access key from another account.
First-run checklist for a fresh account
The app checks these before every launch, but fixing them first avoids a failed first agent:
| Check | Why | Fix |
|---|---|---|
| vCPU quotas | A new account can start at or near 0, and a quota of 0 blocks the launch | In the agents' region, Service Quotas → Amazon EC2: raise Running On-Demand Standard instances (L-1216C47A) and, for spot agents, All Standard Spot Instance Requests (L-34B43A08). Agents use 2 to 4 vCPUs each |
| Region opt-in | Newer regions are disabled by default | Enable the region under Billing → Account → AWS Regions |
| Root user | A new member account has only a root user | Turn on MFA for root, then stop using it: do Steps 1 to 3 through OrganizationAccountAccessRole |
Without AWS Organizations
You can still open a separate AWS account and use it only for agents. If a second account is not an option, the dedicated IAM user below is the minimum: it separates credentials, but not blast radius, quotas or billing.
Step 1: Create the IAM policy
- Open the IAM console → Policies → Create policy.
- On the JSON tab, paste this policy. It is exactly the set of actions the app checks for:
json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "KadmoAgentManagement",
"Effect": "Allow",
"Action": [
"ec2:DescribeRegions",
"ec2:DescribeInstances",
"ec2:DescribeInstanceTypes",
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:RebootInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:DescribeSpotInstanceRequests",
"ec2:CancelSpotInstanceRequests",
"ec2:CreateSecurityGroup",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:RevokeSecurityGroupIngress",
"ec2:DeleteSecurityGroup",
"ec2:DescribeSecurityGroups",
"ec2:CreateKeyPair",
"ec2:DeleteKeyPair",
"ec2:DescribeKeyPairs",
"ec2:CreateTags",
"ec2:DescribeImages",
"ec2:DescribeSubnets",
"sts:GetCallerIdentity"
],
"Resource": "*"
}
]
}- Click Next, name the policy
KadmoAgentManagement, and click Create policy.
Optional permissions
Everything works without these. Each one turns a check the app otherwise skips into a real answer:
| Action | What it adds |
|---|---|
iam:SimulatePrincipalPolicy | Check permissions (Settings → Cloud) dry-runs every action above and lists the missing ones by name. Without it, the check confirms the credentials only |
servicequotas:GetServiceQuota | The launch check reads your vCPU quota (on-demand or spot). Without it you see a warning instead |
ec2:DescribeInstanceTypeOfferings | The wizard marks sizes your region does not offer and reveals more sizes. Without it, sizes are not checked and AWS decides at launch |
ec2:GetSpotPlacementScores | The wizard warns when spot capacity for your size is scarce right now |
Add them in the same statement's Action list.
Step 2: Create the IAM user
- Open IAM → Users → Create user.
- Enter a name, for example
kadmo-agent-manager. - On Permissions, choose Attach policies directly, find
KadmoAgentManagementand select it. - Finish creating the user.
Step 3: Create an access key
- Open the new user → Security credentials.
- Click Create access key and choose Application running outside AWS.
- Click Create access key.
- Copy the Access key ID and the Secret access key. AWS shows the secret only once.
Never commit access keys to a repository. Paste them only into the app.
Step 4: Connect in the app
- In the app, open Integrations and, in the Cloud group, open the AWS card. (On an empty Agent Fleet page, Connect next to AWS goes to the same place.)
- Click Connect AWS account. The Connect AWS account panel opens.
- Fill in:
| Field | What to enter |
|---|---|
| Display name | A name for this connection, for example kadmo-agents |
| Access key ID | From Step 3 (starts with AKIA) |
| Secret access key | From Step 3 |
| Default region | The region your agents run in: the region of the agent subnet |
| Agent subnet | The subnet agents launch in, as subnet-… (see below). You can also add it later |
- Click Connect & validate. The app checks the key against AWS, stores it encrypted, and then reads the subnet. "AWS account connected with its agent subnet." means you are done.
The agent subnet
"The subnet agents launch in: the one peered with Kadmo, in the default region. Agents cannot launch until it is set."
- The subnet must be in the connection's default region, and every agent of this connection launches in that region.
- When you save it, the app reads the subnet with
ec2:DescribeSubnetsand records its VPC and address range. Agents never launch in a default VPC. - Change or clear it later with Agent subnet on the AWS card (Save subnet).
The AWS card
Once connected, the card shows the Connection, Region, Status, when it was Validated, and the Agent subnet with its address range. Its buttons:
| Button | What it does |
|---|---|
| Validate | Checks the stored credentials again: "Credentials valid ✓" |
| Agent subnet | Sets, changes or clears the subnet |
| Rotate credentials | Replaces the access key (Rotate & validate) and keeps the connection's name |
| Disconnect | Removes the connection. Refused while agents still use it |
Settings → Cloud has the same connection under Providers, with Check permissions, which lists every missing action from Step 1.
What Kadmo creates in your account
| Resource | Name and tags | When |
|---|---|---|
| Security group, one per account and VPC, shared by every agent | kadmo-acct-<account-id> | At the first launch in the subnet's VPC |
| Key pair, one per agent | kadmo-agent-<agent-name> | At launch. The private key is kept, encrypted, for Settings → Agents → SSH Access |
| EC2 instance | Name kadmo-agent-<agent-name>; tags kadmo:managed, kadmo:agent, kadmo:tier | At launch: Ubuntu 24.04 LTS, a 40 GB gp3 disk deleted with the instance, a public address, in your agent subnet |
| Spot request (spot agents only) | Tags kadmo:managed, kadmo:agent | At launch. Persistent: an interrupted spot agent stops and starts again when capacity returns |
The security group admits:
| Port | From | Why |
|---|---|---|
| 9876 (TCP) and ICMP | Kadmo's app network only | The app talks to the agent runtime at the agent's private address |
| 22 (SSH) and 3389 (RDP) | The addresses on your firewall allowlist and, where Kadmo's deployment names them, Kadmo's operations ranges | So people can reach the machine directly |
The address you launch from is added to the allowlist automatically. Edit the list under Settings → Cloud → Firewall allowlist (Add, Add my current IP, Save allowlist). You never type a Kadmo address into AWS: the app writes the rules.
Destroy on an agent's page terminates its instance, cancels its spot request and deletes its key pair. Disconnecting the account removes the shared security group.
Troubleshooting
Each row is a message the app shows and its fix.
When you connect or validate
| Message | Cause | Fix |
|---|---|---|
"Credential validation failed" with InvalidClientTokenId | The access key ID is wrong or deleted | Create a new access key (Step 3) and connect again, or use Rotate credentials |
"Credential validation failed" with SignatureDoesNotMatch | The secret access key is wrong | Copy the secret again, or create a new key |
"Credential validation failed" with AuthFailure | The key is inactive | Check the user under IAM → Users |
"Credential validation failed" with UnauthorizedOperation | The policy is not attached, or lacks ec2:DescribeRegions or sts:GetCallerIdentity | Attach the full Step 1 policy |
| "Missing permissions: …" (Check permissions) | The policy lacks the listed actions; the connection is marked invalid | Add the listed actions, or re-attach the Step 1 policy, then Check permissions again |
"⚠ Legacy connection: missing ec2:RevokeSecurityGroupIngress …" | An older policy | Add the action; until then the firewall allowlist cannot remove entries |
| "Validation failed: …" (AWS card) | The stored key no longer works | Rotate credentials with a working key |
When you set the agent subnet
| Message | Fix |
|---|---|
| "Agent subnet must be a subnet id (subnet-…)" | Enter the subnet ID, not its name or address range |
| "Pick the default region the agent subnet is in" / "Set the connection's default region before its agent subnet" | Choose the Default region first |
| "Subnet … was not found in … with this connection's credentials" | The subnet is in another region or another account; pick the right default region or subnet |
| "Could not read the subnet from AWS" | The policy lacks ec2:DescribeSubnets; add it |
| "Account connected, but the agent subnet was not saved" | The connection exists; fix the subnet and click Save subnet |
When you create an agent
These appear in the wizard's Machine step or on Launch:
| Message | Fix |
|---|---|
| "This connection names no agent subnet — set one on the connection before launching" | Set the agent subnet |
| "Agents launch in the connection's subnet, in … — pick that region" | Pick the connection's default region in the wizard |
| "Region not enabled — opt in at …" | Enable the region under Billing → Account → AWS Regions |
| "vCPU quota is 0 — request increase via Service Quotas console" | Raise L-1216C47A (on-demand) or L-34B43A08 (spot) in that region |
| "Could not verify vCPU quota — proceed with caution or check Service Quotas console" | A warning only. Add servicequotas:GetServiceQuota to get a real answer |
| "… is not offered in … — pick another machine size or region." | Pick another size or region, or Load N more sizes |
| "Could not verify instance type availability: …" | A warning only. Add ec2:DescribeInstanceTypeOfferings to get a real answer |
| "Spot capacity for … scores N/10 right now — elevated reclaim risk." | A warning: choose on-demand or another region for a steadier agent |
"Could not check spot capacity score — connection lacks the optional ec2:GetSpotPlacementScores permission." | A warning only; add the action if you want the check |
| "Ubuntu 24.04 LTS AMI not found — provider may not stock it yet" | Pick another region |
UnauthorizedOperation on launch, reboot, stop or destroy | The policy lacks the action; re-attach the full Step 1 policy |
| "Cannot delete connection: agents are still referencing it" | Destroy or move the agents first, then disconnect |
Security notes
- Credentials are stored encrypted (AES-256-GCM) and never returned by the app.
- Use one IAM user per environment, and prefer a dedicated account.
- Rotate the access key regularly: create a new key in IAM, then Rotate credentials in the app, then delete the old key.
Next step
Create your first agent with the create-agent wizard.