DOCS / AWS PROVISIONING

Create and configure AWS instances

A role can create EC2 instances and configure them in one run. You write what the machines are for; the manager chooses the image, network, SSH key and security group, shows its choices in the plan, and creates them on approval.

# AWS instance
- name: web
- count: 2

# Firewall
- open 443/tcp from anywhere

# Packages
- nginx

# Services
- nginx started, enabled
korta roles create --file web.md --name web
korta roles run role_ID

In the console: Roles > New role, insert AWS instance, save, then Run. The instances appear under Instances and can then be used by other roles and by database or application deployments.

Set up the manager once

Add AWS accounts under Settings > AWS > Accounts. No restart is needed, and roles never contain credentials. Each account signs in one of three ways:

Sign in by Use when Korta stores
Assume a role (recommended) Production, and several accounts The role ARN and an optional external ID. Korta gets short-lived credentials for each run
Access key A quick start, or a manager outside AWS The access key ID, and the secret access key sealed in the vault, never shown again
Manager's environment The manager has its own IAM role or AWS variables Nothing; environment variable changes need a restart

For Assume a role, create an IAM role in the target account with the policy below, and let the manager's identity assume it. That identity is the manager's own IAM role, or an access key you enter on the same account entry:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "AWS": "arn:aws:iam::MANAGER_ACCOUNT_ID:role/korta-manager" },
    "Action": "sts:AssumeRole",
    "Condition": { "StringEquals": { "sts:ExternalId": "YOUR_EXTERNAL_ID" } }
  }]
}

Give each account a default region. Mark one account default: roles without a network use it. Networks name their account, so a role reaches the prod account by saying network: prod. With no accounts at all, the manager's environment applies (AWS_REGION and its IAM role or variables), as in earlier releases.

Test on an account signs in and shows which AWS account it reaches. Plans record the account entry they used: instances stay with it, and a role whose network or default would move them to another account is refused until that is undone.

Each account's credentials need this IAM policy. Terminating and deleting are limited to resources Korta tagged:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "KortaRead",
      "Effect": "Allow",
      "Action": [
        "sts:GetCallerIdentity",
        "ec2:DescribeInstances", "ec2:DescribeImages", "ec2:DescribeInstanceTypes",
        "ec2:DescribeVpcs", "ec2:DescribeSubnets", "ec2:DescribeKeyPairs",
        "ec2:DescribeSecurityGroups", "ec2:DescribeSecurityGroupRules"
      ],
      "Resource": "*"
    },
    {
      "Sid": "KortaCreate",
      "Effect": "Allow",
      "Action": [
        "ec2:RunInstances", "ec2:CreateTags", "ec2:ImportKeyPair",
        "ec2:CreateSecurityGroup", "ec2:AuthorizeSecurityGroupIngress",
        "ec2:RevokeSecurityGroupIngress"
      ],
      "Resource": "*"
    },
    {
      "Sid": "KortaDestroyInstances",
      "Effect": "Allow",
      "Action": "ec2:TerminateInstances",
      "Resource": "*",
      "Condition": { "Null": { "aws:ResourceTag/korta:launch": "false" } }
    },
    {
      "Sid": "KortaDestroyGroupsAndKeys",
      "Effect": "Allow",
      "Action": ["ec2:DeleteSecurityGroup", "ec2:DeleteKeyPair"],
      "Resource": "*",
      "Condition": { "Null": { "aws:ResourceTag/korta:role": "false" } }
    }
  ]
}

Narrow RunInstances further if your installation should only use certain instance types, subnets or AMI owners. The manager also reaches https://checkip.amazonaws.com to learn its public address for SSH rules.

What Korta chooses

Field Default Notes
name required With count, instances are web, web-2, web-3
count 1 Up to 20. Raise it later to add instances; it never shrinks
os ubuntu 24.04 Ubuntu 22.04/24.04, Debian 12/13, RHEL, Rocky or AlmaLinux 8 to 10, CentOS Stream 9/10
size t3.micro Any instance type; Arm types such as t4g.small get Arm images
network the region's default VPC A network defined under Settings > AWS
region the manager's Must match the network's region when both are set
address public Or the network's address
static ip no yes gives each instance an Elastic IP that survives stop and start, for DNS and allow-lists. Switching it off later releases the IPs and the instances get new public addresses
  • Image: the newest official image of os from its publisher (Canonical, Debian, Red Hat, Rocky, AlmaLinux, CentOS), matching the instance type's CPU, and that image's login user. The plan names the exact AMI, and approval launches exactly that one; later runs plan a newer image only for new instances.
  • Network: instances are spread over the network's subnets, or the default VPC's default subnets, one per zone in turn.
  • SSH key: Korta creates an Ed25519 key in its vault and imports the public half as EC2 key pair korta-<role>-<id>.
  • Security group: korta-<role>-<id>, allowing SSH from the manager (its public address; the VPC for private addresses; or the network's SSH from) and each port the role's # Firewall section opens. Korta keeps the group's rules equal to that on every run, so removing a firewall line closes the port in AWS too.

To use your own resources instead, set them in the role: image with user, subnet, security-groups (Korta then creates no group), or key-pair with the vault ssh-key holding its private key (import it under SSH keys).

Load balancers

Add an # AWS load balancer section right after # AWS instance to put an Application Load Balancer in front of the role's instances:

# AWS instance
- name: web
- count: 3
- network: prod
- address: private

# AWS load balancer
- certificate: arn:aws:acm:eu-west-1:123456789012:certificate/…
- forward: 8080
- health check: /health
Field Default Meaning
listen http, or https with a certificate https serves port 443 with the certificate and redirects port 80 to it
certificate none The ARN of an ACM certificate in the instances' region
forward 80 The instances' port
health check / A path that answers 200-399 on healthy instances
from 0.0.0.0/0 Networks that may reach the load balancer
internal no yes keeps it inside the VPC

Korta creates the load balancer in two or more zones (an internet-facing one in the network's public subnets, so instances can stay private), its target group and listeners, and a security group that lets only the load balancer reach the instances' forward port. It does this after the instances are configured, registers new instances as count grows, and keeps listeners and the health check in step with the section. Removing the section deletes the load balancer; Destroy does too. The role's page shows its address, which DNS names can point to. With your own security-groups, allow the forward port from the load balancer's group yourself. Changing internal later needs the section removed and added back.

Load balancers need elasticloadbalancing:CreateLoadBalancer, DescribeLoadBalancers, DeleteLoadBalancer, CreateTargetGroup, DescribeTargetGroups, ModifyTargetGroup, DeleteTargetGroup, RegisterTargets, DeregisterTargets, DescribeTargetHealth, CreateListener, DescribeListeners, ModifyListener, DeleteListener and AddTags, plus iam:CreateServiceLinkedRole the first time an account uses Elastic Load Balancing.

DNS names and certificates

An # AWS DNS section, after # AWS instance and its load balancer, lists names for the role, one per bullet:

# AWS load balancer
- certificate: auto
- forward: 8080

# AWS DNS
- shop.example.com
- www.shop.example.com

Each name goes in the Route 53 hosted zone of the account whose name is its longest match: a public zone, or a private one when only the VPC can reach the role (an internal load balancer, or private addresses). With a load balancer, names are alias records pointing at it; otherwise they list the instances' addresses, so use static ip: yes for public instances. certificate: auto asks ACM for a certificate for these names, proves them with validation records in Route 53, waits until it is issued (usually a few minutes) and serves it on port 443.

Korta only changes records it created. A name that already has a record Korta did not make stops the plan; delete it in Route 53 or choose another name. Removing a name deletes its record; replacing names gets a new certificate and deletes the old one once the load balancer stops using it. Destroy deletes the records and the certificate. Wildcards such as *.shop.example.com work for records and certificates.

DNS needs route53:ListHostedZones, route53:ListResourceRecordSets and route53:ChangeResourceRecordSets; certificates need acm:RequestCertificate, acm:DescribeCertificate, acm:DeleteCertificate and acm:AddTagsToCertificate.

Networks

Instances go to the region's default VPC unless their role names a network. There are two kinds:

Built by a role. A role with only an # AWS network section creates a VPC with public and private subnets across zones, an internet gateway, NAT gateways and routes, or adopts an existing VPC:

# AWS network
- name: prod
- region: eu-west-1
- cidr: 10.20.0.0/16
- zones: 3
# AWS network
- name: legacy
- vpc: vpc-0123456789abcdef0
- public subnets: subnet-0aaa…, subnet-0bbb…
- private subnets: 10.1.10.0/24, 10.1.11.0/24

Plan it to see every resource it would create, then approve. In an adopted VPC, Korta only adds its own tagged subnets, gateways, routes and NAT gateways; it never changes or deletes what was there, and existing subnets keep their routes. Once built, a network can gain zones, NAT gateways and SSH sources; its region, account, VPC and ranges are fixed. Destroy deletes what Korta created, after the instance roles that use the network are destroyed. NAT gateways are billed hourly; nat: none leaves private subnets without internet access, and nat: one shares one gateway across zones.

Defined in Settings. For subnets that already exist, an admin adds a network under Settings > AWS with its account, region, subnets, address, optional SSH from networks (such as your VPN range) and extra security groups attached to every instance (such as a monitoring group).

Instance roles use either kind the same way:

# AWS instance
- name: api
- count: 3
- network: prod
- address: private

address: private places instances in the private subnets and connects over their private addresses, so the manager must reach the VPC through VPN, peering or by running inside it. Otherwise instances go to the public subnets.

Networks need these permissions as well: ec2:DescribeAvailabilityZones, ec2:DescribeTags, ec2:CreateVpc, ec2:ModifyVpcAttribute, ec2:DeleteVpc, ec2:DescribeInternetGateways, ec2:CreateInternetGateway, ec2:AttachInternetGateway, ec2:DetachInternetGateway, ec2:DeleteInternetGateway, ec2:CreateSubnet, ec2:ModifySubnetAttribute, ec2:DeleteSubnet, ec2:CreateRouteTable, ec2:DescribeRouteTables, ec2:CreateRoute, ec2:AssociateRouteTable, ec2:DisassociateRouteTable, ec2:DeleteRouteTable, ec2:AllocateAddress, ec2:ReleaseAddress, ec2:CreateNatGateway, ec2:DescribeNatGateways and ec2:DeleteNatGateway. Static IPs also need ec2:DescribeAddresses, ec2:AssociateAddress and ec2:DisassociateAddress.

Run, approve, destroy

Run plans, then approves on the same screen. The plan creates nothing: it shows the image, subnets, security group rules and the configuration that will run, and checks launch permission with a dry run. Approval creates the key pair and security group, launches the instances, waits for SSH and applies the rest of the role. With four-eyes approval on (the default), the person who changed or planned the role cannot approve it; the plan waits on the role's page for someone else.

Running the role again configures the instances, keeps the security group in step with the Firewall section, and launches any instances a larger count adds. Launch settings (os, size, network, region, address and your own resources) are fixed once instances exist.

Destroy on the role's page (or korta roles destroy role_ID --confirm NAME) plans removing what the role created and, once approved with the role's name typed in, terminates the instances, then deletes the security group, key pair and vault key. A role with AWS instances cannot be deleted until they are destroyed, and instances used by a deployment cannot be destroyed until the deployment is deleted.

Creating, approving and destroying AWS roles need a global admin or owner grant.

Retries

Korta saves a launch reservation before calling AWS. If a launch response is lost or the manager restarts, run the role again: Korta recovers the instance with the same client token instead of launching a second one. Failed configuration keeps the instances for inspection; running the role again retries. Keep the manager's state backed up: it holds the reservations.

BUILT WITH KORTAAll documentation ↗