import requests
url = "https://platform.ankra.app/org/clusters/aws"
payload = {
"name": "<string>",
"credential_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ssh_key_credential_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"region": "<string>",
"vpc_id": "<string>",
"node_subnet_ids": ["<string>"],
"bastion_subnet_id": "<string>",
"bastion_allowed_ips": ["<string>"]
}
headers = {
"cookie": "ankra_session=",
"X-Ankra-CSRF": "<x-ankra-csrf>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
cookie: 'ankra_session=',
'X-Ankra-CSRF': '<x-ankra-csrf>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: '<string>',
credential_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
ssh_key_credential_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
region: '<string>',
vpc_id: '<string>',
node_subnet_ids: ['<string>'],
bastion_subnet_id: '<string>',
bastion_allowed_ips: ['<string>']
})
};
fetch('https://platform.ankra.app/org/clusters/aws', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));curl --request POST \
--url https://platform.ankra.app/org/clusters/aws \
--header 'Content-Type: application/json' \
--header 'X-Ankra-CSRF: <x-ankra-csrf>' \
--cookie ankra_session= \
--data '
{
"name": "<string>",
"credential_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ssh_key_credential_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"region": "<string>",
"vpc_id": "<string>",
"node_subnet_ids": [
"<string>"
],
"bastion_subnet_id": "<string>",
"bastion_allowed_ips": [
"<string>"
]
}
'{
"cluster_id": "11111111-2222-4333-8444-555555555555",
"name": "aws-prod",
"kind": "aws",
"state": "creating",
"operation_id": null
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}{
"detail": "Cluster not found"
}Create an AWS EC2 cluster
Browser session authentication; RBAC permission clusters.create. Creates a self-managed k3s / kubeadm cluster on EC2 in the customer’s VPC (ADR 0015). The preflight runs first and the first error item is the refusal. Defaults: t3.medium nodes, a t3.small bastion, Ubuntu 24.04 on amd64, a 40 GiB encrypted gp3 root volume, one control plane and one worker, Cilium for either distribution. egress_mode omitted is resolved by preflight (existing when every node subnet already has egress, bastion_nat when none has and none carries a foreign instance). Flannel is accepted but cannot enforce the IMDS guard, so the preflight reports a warning for it; the AWS cloud-controller-manager is always installed. Answers 404 while the organisation’s aws_provider feature flag is off.
import requests
url = "https://platform.ankra.app/org/clusters/aws"
payload = {
"name": "<string>",
"credential_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ssh_key_credential_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"region": "<string>",
"vpc_id": "<string>",
"node_subnet_ids": ["<string>"],
"bastion_subnet_id": "<string>",
"bastion_allowed_ips": ["<string>"]
}
headers = {
"cookie": "ankra_session=",
"X-Ankra-CSRF": "<x-ankra-csrf>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
cookie: 'ankra_session=',
'X-Ankra-CSRF': '<x-ankra-csrf>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: '<string>',
credential_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
ssh_key_credential_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
region: '<string>',
vpc_id: '<string>',
node_subnet_ids: ['<string>'],
bastion_subnet_id: '<string>',
bastion_allowed_ips: ['<string>']
})
};
fetch('https://platform.ankra.app/org/clusters/aws', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));curl --request POST \
--url https://platform.ankra.app/org/clusters/aws \
--header 'Content-Type: application/json' \
--header 'X-Ankra-CSRF: <x-ankra-csrf>' \
--cookie ankra_session= \
--data '
{
"name": "<string>",
"credential_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ssh_key_credential_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"region": "<string>",
"vpc_id": "<string>",
"node_subnet_ids": [
"<string>"
],
"bastion_subnet_id": "<string>",
"bastion_allowed_ips": [
"<string>"
]
}
'{
"cluster_id": "11111111-2222-4333-8444-555555555555",
"name": "aws-prod",
"kind": "aws",
"state": "creating",
"operation_id": null
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": "Cluster not found"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}{
"detail": "Cluster not found"
}Authorizations
Browser session. Mutations also require X-Ankra-CSRF.
Headers
Must match the ankra_csrf browser cookie.
Body
POST /clusters/aws body. Nodes never receive a public IP; the bastion holds the elastic IP and is the SSH hop (and the NAT instance in bastion_nat mode).
An organisation aws credential: a keys credential, or a role onboarded with scope provisioning or self_managed (cost-scoped roles are refused).
Region slug, validated against ec2:DescribeRegions.
Private subnets the nodes spread across; one or more, their zones become the cluster's zone pool.
1A public subnet (internet-gateway default route) for the bastion.
IPv4 CIDRs allowed to SSH to the bastion; 0.0.0.0/0 and ::/0 are refused.
1Omitted: resolved by preflight. existing keeps the subnets' NAT routing; bastion_nat makes the bastion the NAT instance behind one Ankra-owned route table and is refused when a node subnet carries instances Ankra did not create.
existing, bastion_nat At least 3 when the node subnets span more than one availability zone.
1 <= x <= 90 <= x <= 100Show child attributes
Show child attributes
k3s, kubeadm stacked, external Defaults to cilium for both distributions: the AWS stack's IMDS guard is a network policy only Cilium and Calico enforce. flannel is accepted with a preflight warning; kubeadm requires cilium.
flannel, calico, cilium Show child attributes
Show child attributes
arm64 is refused with a 422 naming the pending image-catalogue audit (ADR 0015 §6).
amd64 Encrypted gp3 root volume of every instance.
20 <= x <= 2000delete, retain Must be true when present: the AWS cloud-controller-manager is mandatory.