Skip to main content

AWS

AWS Self-Hosted (Vanilla) K8s Cluster Provisioner

The Astro platform deploys a Kubernetes cluster on EC2 instances on your behalf, allowing you to select the instance type, size, zone, region, and other configurations. This approach is beneficial when you require a cluster that is not managed by the cloud provider, providing you with full control over the cluster, including the control plane.

Prerequisites

To create a self-hosted cluster on AWS, ensure the following CLI tools are installed on your local machine:

  • AWS CLI for AWS cluster communication
  • kubectl (optional) for AWS cluster interaction
  • astroctl for cluster management

CLI Workflow

The astroctl cloud aws selfHosted command group manages the full lifecycle of AWS self-hosted prerequisites. There are five subcommands:

CommandPurposeUsed By
setupCreate IAM user, policies, S3 bucket and auto-store credentials in vaultPlatform team
connectValidate existing credentials and store in vaultDeveloper
disconnectRevoke stored credentials from vault (keeps infrastructure)Platform team
validatePre-flight validation only (no storage)CI/CD, troubleshooting
cleanupDelete CloudFormation stack and purge vault credentialsPlatform team

Setup (Platform Team)

The platform team creates all AWS prerequisites and auto-stores credentials in the vault with a single command:

# Create IAM user, policies, and S3 state store bucket via CloudFormation
astroctl cloud aws selfHosted setup \
--account-id <aws-account-id> \
--region <region> \
--cluster-name <cluster-name>

Connect (Developer / BYOC)

For existing credentials (Bring Your Own Credentials), validate and store them in the vault:

# Connect with auto-detected credentials (env vars or ~/.aws/credentials)
astroctl cloud aws selfHosted connect \
--region <region> \
--bucket <bucket-name> \
--cluster-name <cluster-name>

# Connect with a named AWS profile
astroctl cloud aws selfHosted connect \
--profile <aws-profile> \
--region <region> \
--bucket <bucket-name> \
--cluster-name <cluster-name>

# Connect with explicit credentials
astroctl cloud aws selfHosted connect \
--account-id <aws-account-id> \
--region <region> \
--access-key <access-key> \
--secret-key <secret-key> \
--bucket <bucket-name> \
--cluster-name <cluster-name>

On success, credentials are stored in the platform vault and the command outputs the provisioner block to paste into your cluster YAML:

provisioner:
type: selfHosted
selfHosted:
accountId: "<detected-account-id>"
bucketName: "<bucket-name>"
credentials:
type: vault
Credential Resolution

The connect command auto-detects credentials in this order:

  1. Explicit --access-key / --secret-key flags
  2. --profile flag (reads from ~/.aws/credentials)
  3. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
  4. Default credential chain (~/.aws/credentials default profile, EC2 instance role, etc.)

Validate

Run validations without generating output — useful for CI/CD pipelines or troubleshooting:

# Validate using AWS profile
astroctl cloud aws selfHosted validate \
--profile <aws-profile> \
--region <region> \
--bucket <bucket-name>

# Or validate with explicit credentials
astroctl cloud aws selfHosted validate \
--account-id <aws-account-id> \
--region <region> \
--access-key <access-key> \
--secret-key <secret-key> \
--bucket <bucket-name>

Disconnect

Revoke stored credentials from the vault without removing infrastructure — useful for credential rotation:

astroctl cloud aws selfHosted disconnect --cluster-name <cluster-name>

After disconnecting, run connect with new credentials to re-store them in the vault.

Cleanup

When you no longer need the self-hosted prerequisites:

astroctl cloud aws selfHosted cleanup \
--account-id <aws-account-id> \
--region <region> \
--cluster-name <cluster-name>

This deletes the CloudFormation stack (IAM user, policies, S3 bucket) and purges vault credentials.

Cleanup Impact

This is a destructive operation. Ensure no clusters depend on these resources before running cleanup.

Complete Field Reference

The selfHosted type represents the spec for the AWS self-hosted provisioner. This is the authoritative reference for all available fields.

Core Fields

FieldTypeRequiredDefaultDescription
accountIdstringYes-AWS account ID where the cluster will be created
bucketNamestringYes-S3 bucket name for storing cluster configuration. Must be in the same region as the cluster.
credentialsobjectYes-AWS credentials. Use type: vault (recommended for self-hosted) or type: static for inline credentials. The vault type is only supported for the selfHosted provisioner.

Networking Fields

FieldTypeRequiredDefaultDescription
networkIdstringNo-VPC ID for BYOVPC. If not provided, platform creates a new VPC

Cluster Configuration Fields

FieldTypeRequiredDefaultDescription
kubernetesVersionstringNoPlatform defaultKubernetes version. Must be full semantic version (e.g., 1.30.14)

Field Validation Rules

FieldValidation
accountIdMust be a valid AWS account ID
bucketNameMust be a valid S3 bucket name
networkIdMust start with vpc- followed by alphanumeric characters
kubernetesVersionMust be full semantic version format: 1.30.14 (major.minor.patch)
Version Format

Self-hosted clusters require the full semantic version format (e.g., 1.30.14). The major.minor format (e.g., 1.30) is not supported for self-hosted clusters.

BYOA (Bring Your Own Account)

Run setup or connect to store credentials in the platform vault, then reference them with type: vault — no sensitive data in your YAML:

provider: aws
provisioner:
type: selfHosted
selfHosted:
accountId: "<account-id>"
bucketName: "<bucket-name>"
credentials:
type: vault
How vault works

The setup command automatically stores credentials in the vault after creating AWS prerequisites. For existing credentials, run connect to store them manually. The platform retrieves credentials from the vault at provision time — no secrets in YAML files.

Option 2: Credentials in YAML (explicit)

If you cannot use the vault, you can still provide credentials inline:

provider: aws
provisioner:
type: selfHosted
selfHosted:
accountId: "<account-id>"
bucketName: "<bucket-name>"
credentials:
type: static
data:
AWS_ACCESS_KEY_ID: "<access-key>"
AWS_SECRET_ACCESS_KEY: "<secret-key>"
Security

Avoid committing credentials to version control. Prefer type: vault (Option 1) or ensure your YAML files are in .gitignore.

Bring Your Own VPC (BYOVPC)

Add the networkId field to your cluster YAML to use an existing VPC:

provider: aws
provisioner:
type: selfHosted
selfHosted:
accountId: "<account-id>"
networkId: "vpc-xxxx" # your existing VPC ID
bucketName: "<bucket-name>"
credentials:
type: vault

Requirements for the VPC:

  • Must be in the same region as the cluster
  • Internet gateway must be attached
  • DNS hostnames and DNS resolution must be enabled

You can generate a VPC CloudFormation template using the CLI:

# Generate VPC template
astroctl cloud aws generate-vpc --region us-east-1 --vpc-cidr 10.0.0.0/16 --cluster-name prod

# Generate subnet configuration for an existing VPC
astroctl cloud aws generate-subnets --region us-east-1 --vpc-cidr 10.0.0.0/16

KubeConfig

With simple command like below, you can set the context to the cluster and have the access to the cluster. You need to make sure to install the kubectl CLI as required.

astroctl infra k8s set-context <cluster-name>

The cluster uses the client authentication type mutual TLS authentication to authenticate the kubeconfig. The platform lets you to configure the duration for the kubeconfig to be valid. Only the platform admin or admin of the organization can export the kubeconfig.

Cluster Updates

Self-hosted clusters support updates to Kubernetes version and node group configurations. You can use either the Console UI or the CLI.

Version Format

Self-hosted clusters require the full semantic version format (e.g., 1.30.14). The major.minor format (e.g., 1.30) is not supported.

Option 1: Console (Upgrade Wizard)

The Console provides a guided 5-step upgrade wizard:

  1. Preflight Check - Validates upgrade paths and checks for issues
  2. Readiness Report - Generates comprehensive upgrade analysis with risk score
  3. Pre-Upgrade Checklist - Interactive checklist with verification commands
  4. Configuration - Select target version and rolling update settings
  5. Confirmation - Review summary and confirm by typing cluster name

To access: Go to Clusters → Select cluster → Click Upgrade button

The wizard shows:

  • Visual version timeline (current → next → locked future versions)
  • Node group scaling controls (min/max nodes)
  • Control plane configuration (self-hosted only)
  • Rolling update settings (maxSurge, maxUnavailable)
  • Impact summary before execution

Option 2: CLI Commands

Version Discovery

# List available versions for this cluster
astroctl infra k8s upgrade <cluster-name> --list-versions

# Check self-hosted versions
astroctl cloud aws k8s-versions --self-hosted
astroctl cloud aws k8s-versions --self-hosted --show-upgrade-paths

Kubernetes Version Upgrade

# Dry-run validation first
astroctl infra k8s upgrade <cluster-name> 1.30.14 --dry-run

# Generate readiness report
astroctl infra k8s upgrade <cluster-name> 1.30.14 --generate-report

# Execute upgrade
astroctl infra k8s upgrade <cluster-name> 1.30.14

# Skip confirmation (for automation)
astroctl infra k8s upgrade <cluster-name> 1.30.14 --yes

Scaling Node Groups

# List node groups
astroctl infra k8s scale <cluster-name> --list

# Scale a node group
astroctl infra k8s scale <cluster-name> <nodegroup-name> --min 3 --max 10

# Preview changes
astroctl infra k8s scale <cluster-name> <nodegroup-name> --min 5 --max 20 --dry-run

Advanced Updates (YAML)

# Show YAML examples for your cluster
astroctl infra k8s update <cluster-name> --example

# Apply update
astroctl infra k8s update <cluster-name> -f update.yaml

# Dry-run validation
astroctl infra k8s update <cluster-name> -f update.yaml --dry-run

# Skip confirmation
astroctl infra k8s update <cluster-name> -f update.yaml --auto-approve

Monitor Progress

# Stream real-time progress
astroctl infra k8s progress stream <cluster-name>

# Get current status
astroctl infra k8s progress get <cluster-name>

# View operation history
astroctl infra k8s progress history <cluster-name>

Update File Reference

apiVersion: platform.astropulse.io/v1
kind: K8sClusterUpdate
spec:
# Kubernetes version (full semver required)
kubernetesVersion: "1.30.14"

# Rolling update configuration
updateConfig:
maxSurge: "1" # Nodes added during update (number or %)
maxUnavailable: "1" # Nodes down during update (number or %)
dryRun: false # Validate without applying
generateReport: false # Generate readiness report

# Worker node groups
nodeGroups:
- name: "worker-ng-0"
minNode: 2
maxNode: 6
machineTypes: ["t3.large"]
instanceType: "ondemand" # or "spot"
labels:
workload: "general"

# Control plane configuration (self-hosted only)
selfHosted:
controlPlane:
name: "control-plane"
minNode: 3
maxNode: 3
machineTypes: ["t3.medium"]

Upgrade Process

  1. Control plane nodes are upgraded first (one at a time for HA)
  2. etcd cluster is upgraded
  3. Worker nodes are upgraded using rolling replacement
  4. Progress is tracked and reported in real-time
Upgrade Considerations
  • Self-hosted clusters only support upgrades to sequential minor versions (cannot skip versions)
  • Ensure you have recent etcd backups before upgrading
  • Always test upgrades in a non-production environment first

Rollback

Self-hosted clusters support full rollback including control plane downgrade — unlike managed providers (EKS/GKE/AKS) which only downgrade node pools.

# List valid rollback versions
astroctl infra k8s rollback <cluster-name> --list-versions

# Dry-run validation
astroctl infra k8s rollback <cluster-name> <target-version> --dry-run

# Execute rollback
astroctl infra k8s rollback <cluster-name> <target-version>

# Skip confirmation (automation)
astroctl infra k8s rollback <cluster-name> <target-version> --yes
Rollback Impact
  • Control plane + worker nodes are all downgraded via rolling update
  • Workloads will be drained and migrated to new nodes
  • Ensure workloads are compatible with the older Kubernetes version
Zero-Downtime Updates

When changing machine types, nodes are replaced using a rolling strategy. Ensure your maxSurge and maxUnavailable settings allow for the desired replacement behavior.