AWS Setup
This guide covers the AWS configuration required for Stratos to manage EC2 instances.
Prerequisites
- AWS CLI installed and configured
- EKS cluster or self-managed Kubernetes on EC2
- Permissions to create IAM roles and policies
Controller IAM Policy
The Stratos controller needs permissions to manage EC2 instances.
Basic Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "StratosEC2Operations",
"Effect": "Allow",
"Action": [
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:CreateTags",
"ec2:DescribeTags"
],
"Resource": "*"
},
{
"Sid": "EC2ResourceDiscovery",
"Effect": "Allow",
"Action": [
"ec2:DescribeImages",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups"
],
"Resource": "*"
}
]
}
The EC2ResourceDiscovery statement is required when using dynamic resource selectors (amiSelector, subnetSelector, securityGroupSelector). If you only use static IDs, this statement can be omitted. If you use Spot replacement, see Spot Replacement Permissions for additional required permissions.
Policy with Instance Profile Management
If you use the role field in AWSNodeClass (automatic instance profile management), add IAM permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "StratosEC2Operations",
"Effect": "Allow",
"Action": [
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:CreateTags",
"ec2:DescribeTags"
],
"Resource": "*"
},
{
"Sid": "EC2ResourceDiscovery",
"Effect": "Allow",
"Action": [
"ec2:DescribeImages",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups"
],
"Resource": "*"
},
{
"Sid": "IAMInstanceProfileManagement",
"Effect": "Allow",
"Action": [
"iam:CreateInstanceProfile",
"iam:DeleteInstanceProfile",
"iam:GetInstanceProfile",
"iam:AddRoleToInstanceProfile",
"iam:RemoveRoleFromInstanceProfile"
],
"Resource": "arn:aws:iam::*:instance-profile/stratos-*"
},
{
"Sid": "IAMPassRole",
"Effect": "Allow",
"Action": [
"iam:PassRole"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"iam:PassedToService": "ec2.amazonaws.com"
}
}
}
]
}
Spot Replacement Permissions
When using spotReplacement on a NodePool, the controller requires additional EC2 permissions for creating fleets and launch templates:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "StratosSpotOperations",
"Effect": "Allow",
"Action": [
"ec2:CreateFleet",
"ec2:CreateLaunchTemplate",
"ec2:DescribeLaunchTemplates",
"ec2:DeleteLaunchTemplate"
],
"Resource": "*"
}
]
}
The CreateFleet API is used instead of RunInstances with Spot market options. This enables diversified Spot instance launches across multiple instance types for better availability.
The IAMInstanceProfileManagement statement is scoped to instance profiles prefixed with stratos-, matching the naming convention used by the controller. The Helm chart includes a complete IAM policy template at deploy/charts/stratos/templates/iam-policy.yaml.
Scoped Policy (Recommended)
For better security, scope the policy to Stratos-managed resources:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "StratosEC2Describe",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus",
"ec2:DescribeTags",
"ec2:DescribeImages",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups"
],
"Resource": "*"
},
{
"Sid": "StratosEC2Mutate",
"Effect": "Allow",
"Action": [
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:CreateTags"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/managed-by": "stratos"
}
}
},
{
"Sid": "StratosEC2MutateExisting",
"Effect": "Allow",
"Action": [
"ec2:TerminateInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:CreateTags"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/managed-by": "stratos"
}
}
}
]
}
Create the Policy
aws iam create-policy \
--policy-name stratos-controller-policy \
--policy-document file://stratos-controller-policy.json
IRSA Configuration (EKS)
For EKS, use IAM Roles for Service Accounts (IRSA) to provide credentials to the controller.
Step 1: Create OIDC Provider
If not already created for your cluster:
eksctl utils associate-iam-oidc-provider \
--cluster=your-cluster \
--approve
Step 2: Create IAM Service Account
eksctl create iamserviceaccount \
--cluster=your-cluster \
--namespace=stratos-system \
--name=stratos \
--role-name=stratos-controller-role \
--attach-policy-arn=arn:aws:iam::YOUR_ACCOUNT:policy/stratos-controller-policy \
--approve
Step 3: Verify Configuration
kubectl -n stratos-system get serviceaccount stratos -o yaml
You should see the IAM role annotation:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::YOUR_ACCOUNT:role/stratos-controller-role
Node IAM Role
Nodes launched by Stratos need permissions to join the Kubernetes cluster and pull container images.
EKS Node Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EKSWorkerNode",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeRegions"
],
"Resource": "*"
},
{
"Sid": "ECRReadOnly",
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:GetRepositoryPolicy",
"ecr:DescribeRepositories",
"ecr:ListImages",
"ecr:BatchGetImage"
],
"Resource": "*"
}
]
}
Create Node Role
# Create the role
aws iam create-role \
--role-name stratos-node-role \
--assume-role-policy-document file://trust-policy.json
# Attach AWS managed policies
aws iam attach-role-policy \
--role-name stratos-node-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
aws iam attach-role-policy \
--role-name stratos-node-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
aws iam attach-role-policy \
--role-name stratos-node-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
# Create instance profile
aws iam create-instance-profile \
--instance-profile-name stratos-node
aws iam add-role-to-instance-profile \
--instance-profile-name stratos-node \
--role-name stratos-node-role
The trust policy (trust-policy.json):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Network Configuration
Security Group
Create a security group for Stratos-managed nodes:
aws ec2 create-security-group \
--group-name stratos-nodes \
--description "Security group for Stratos-managed nodes" \
--vpc-id vpc-12345678
Required inbound rules:
| Type | Protocol | Port | Source | Description |
|---|---|---|---|---|
| Custom TCP | TCP | 10250 | Control plane SG | Kubelet API |
| Custom TCP | TCP | 10256 | Cluster CIDR | Kube-proxy health |
| Custom UDP | UDP | 8472 | Cluster CIDR | VXLAN (Flannel/Cilium) |
| Custom TCP | TCP | 4240 | Cluster CIDR | Cilium health |
# Allow kubelet API from control plane
aws ec2 authorize-security-group-ingress \
--group-id sg-stratos-nodes \
--protocol tcp \
--port 10250 \
--source-group sg-control-plane
# Allow pod-to-pod communication
aws ec2 authorize-security-group-ingress \
--group-id sg-stratos-nodes \
--protocol all \
--source-group sg-stratos-nodes
Subnet Requirements
Subnets for Stratos nodes must have:
- Route to the Kubernetes API server
- Route to container registries (ECR, Docker Hub)
- NAT gateway or Internet gateway for outbound traffic
For high availability, use subnets in multiple availability zones:
subnetIds:
- subnet-12345678 # us-east-1a
- subnet-87654321 # us-east-1b
- subnet-abcdefgh # us-east-1c
Alternatively, use dynamic resource selectors to discover subnets by tags:
subnetSelector:
tags:
stratos.sh/discovery: my-cluster
Stratos round-robins instance launches across subnets, providing automatic AZ distribution. This works with both static subnetIds and dynamic subnetSelector.
EKS Authentication
For nodes to join an EKS cluster, the node IAM role must be in the aws-auth ConfigMap:
eksctl create iamidentitymapping \
--cluster your-cluster \
--arn arn:aws:iam::YOUR_ACCOUNT:role/stratos-node-role \
--group system:bootstrappers \
--group system:nodes
Or manually edit the ConfigMap:
kubectl edit configmap aws-auth -n kube-system
Add:
mapRoles:
- rolearn: arn:aws:iam::YOUR_ACCOUNT:role/stratos-node-role
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
AMI Selection
Use EKS-optimized AMIs for best compatibility:
# Get the latest EKS-optimized AMI (Amazon Linux 2)
aws ssm get-parameter \
--name /aws/service/eks/optimized-ami/1.34/amazon-linux-2/recommended/image_id \
--query "Parameter.Value" \
--output text
# For AL2023 (x86_64)
aws ssm get-parameter \
--name /aws/service/eks/optimized-ami/1.34/amazon-linux-2023/x86_64/standard/recommended/image_id \
--query "Parameter.Value" \
--output text
# For AL2023 (ARM64/Graviton)
aws ssm get-parameter \
--name /aws/service/eks/optimized-ami/1.34/amazon-linux-2023/arm64/standard/recommended/image_id \
--query "Parameter.Value" \
--output text
# For Bottlerocket (x86_64)
aws ssm get-parameter \
--name /aws/service/bottlerocket/aws-k8s-1.34/x86_64/latest/image_id \
--query "Parameter.Value" \
--output text
Verifying Setup
Step 1: Create an AWSNodeClass
First, create an AWSNodeClass with your AWS configuration:
apiVersion: stratos.sh/v1alpha1
kind: AWSNodeClass
metadata:
name: test-nodes
spec:
bootstrapTemplate: AL2023
region: us-east-1
instanceType: t3.small
subnetSelector:
tags:
stratos.sh/discovery: your-cluster
securityGroupSelector:
tags:
stratos.sh/discovery: your-cluster
role: stratos-node-role
blockDeviceMappings:
- deviceName: /dev/xvda
volumeSize: 20
volumeType: gp3
encrypted: true
kubectl apply -f awsnodeclass-test.yaml
With bootstrapTemplate: AL2023, Stratos automatically generates the complete bootstrap script. You no longer need to provide a custom userData script. The controller uses cluster configuration from Helm values to generate the correct bootstrap commands.
Step 2: Create a Test NodePool
Create a minimal NodePool referencing the AWSNodeClass:
apiVersion: stratos.sh/v1alpha1
kind: NodePool
metadata:
name: test
spec:
poolSize: 1
minStandby: 1
template:
nodeClassRef:
kind: AWSNodeClass
name: test-nodes
labels:
stratos.sh/pool: test
kubectl apply -f nodepool-test.yaml
Step 3: Verify Node Creation
Watch for the node to appear:
kubectl get nodes -l stratos.sh/pool=test -w
Check NodePool status:
kubectl get nodepools
kubectl describe nodepool test
Troubleshooting
Check controller logs:
kubectl -n stratos-system logs deployment/stratos
Check if AWSNodeClass is found:
kubectl get awsnodeclasses
kubectl describe awsnodeclass test-nodes
Check instance console output:
aws ec2 get-console-output --instance-id i-0123456789abcdef0
Common issues:
- NodeClassNotFound: The AWSNodeClass doesn't exist or has a different name
- IAM permissions: Controller or node missing required permissions
- Network: Subnets can't reach the EKS API server
- AMI: Wrong architecture (x86_64 vs arm64) for the instance type
Next Steps
- Quickstart - Create your first NodePool
- Dynamic Resource Selectors - Use tag-based discovery instead of hardcoded IDs
- AWSNodeClass Reference - Complete API reference
- Bottlerocket Setup - Using Bottlerocket with Stratos
- Monitoring - Set up monitoring and alerts