Skip to main content
By default boxes run in Tesser’s AWS account and the org is charged per awake second. An org can instead run its boxes in its own account: Tesser still hosts the control plane, the CLI, and the dashboard, but every EC2 instance is yours, in your VPC, on your bill. Owners set this up with tesser cloud.

How Tesser reaches your account

Tesser never holds a credential for your account. The control plane is an OpenID Connect issuer, and you create an IAM role that trusts it for exactly one org id. Each time the org cell needs EC2 it signs a token that lives five minutes, trades it for one hour of temporary credentials with AssumeRoleWithWebIdentity, and uses those. Another org’s cell cannot assume your role: the trust policy names the org in sub, and the token carries the org that signed it. tesser cloud template prints the trust policy with the org id filled in:

What you create

  1. An OIDC provider for https://api.tesser.sh with the audience sts.amazonaws.com. AWS fetches the signing keys from api.tesser.sh/.well-known/jwks.json; no thumbprint is needed.
  2. A role with the trust policy above and a permissions policy fenced to instances tagged tesser:managed=true: RunInstances only when the launch carries that tag, Stop/Start/Terminate/CreateTags/ ModifyInstanceMetadataOptions only on instances that already have it, and Describe* for instances, subnets, and security groups. Add an ec2:InstanceType condition to the RunInstances statement to cap the sizes the org may launch. No iam:PassRole unless you use Session Manager (below): otherwise a box has no AWS identity.
  3. A subnet for the boxes. A public subnet that assigns public IPs works like Tesser’s own cloud. A private subnet works too: the CLI then reaches boxes at their private IP, which needs a VPN or subnet router of yours, and the subnet needs a route to the internet so a box can reach api.tesser.sh.
  4. A security group in the same VPC: port 22 from wherever you SSH (sshd only accepts the per-box keys), the mesh port from the group itself, egress open.
  5. The box AMI. Tesser publishes its own image publicly in each supported region (Ubuntu with Node, Docker, and rsync); search public AMIs owned by Tesser for tesser-box-* in your region and pass its id. Any image with the same tools works too.

Connecting the org

connect assumes the role once and describes the subnet and security group. A role that does not trust the org, an id that does not exist, a group in a different VPC than the subnet, or --private disagreeing with whether the subnet assigns public IPs all fail before anything is stored. --max-boxes is the org’s own cap. tesser cloud status shows the current config. From then on every tesser make, dev, and exec launches in your account. Tesser creates no security group of its own, the org’s compute meter keeps counting but nothing is charged, and the beta credit gate does not apply. Boxes sleep, wake, and are reaped exactly as before.

No inbound port: Session Manager

With --ssm <instance-profile> boxes take no inbound port 22 at all. Each box launches with that IAM instance profile, and the CLI reaches sshd by tunneling through AWS Session Manager: every ssh, sync, and daemon tunnel runs aws ssm start-session --target <instance id> as its ProxyCommand, and the host key is filed under the instance id.
What it needs:
  • The instance profile must carry AmazonSSMManagedInstanceCore (the SSM agent ships in the Tesser AMI). The role tesser assumes also needs iam:PassRole on that profile’s role for RunInstances.
  • Every org member needs AWS credentials for the account with ssm:StartSession on the boxes, the AWS CLI, and the session-manager-plugin installed. tesser cloud aws-profile <name> tells the CLI which AWS CLI profile to use for this org; it lives in the laptop’s tesser config, not in the control plane.
  • The security group no longer needs port 22 open; boxes still need egress to reach SSM and api.tesser.sh.
Bulk transfers (the first sync of a large worktree) are slower through Session Manager than over a direct connection; the steady-state edit-sync loop is fine.

Changing or leaving

Where boxes run cannot change while any exist. Remove them, then connect again with the new ids, or tesser cloud disconnect to return the org to Tesser’s cloud. --max-boxes can change at any time.