This repository contains reusable Terraform modules to manage a secure, resilient, and self-healing bastion host on Amazon Web Services (AWS), Google Cloud Platform (GCP), or Microsoft Azure.
Below is the conceptual architecture of how the Bastion host manages secure external access to your private infrastructure:
graph TD
Client["💻 Client (SSH)"] -->|"1. SSH:22 (Allowed CIDRs Only)"| NSG["🛡️ Firewall / SG / NSG"]
NSG -->|Allows access| Bastion["🚀 Bastion Host (Public Subnet)"]
subgraph VPC_VNet ["🌐 VPC / VNet (Cloud Provider)"]
Bastion
subgraph Private_Subnet ["🔒 Private Subnet"]
AppVM["🖥️ Internal App Servers (No Public IP)"]
DB["🗄️ Private Databases (RDS/Cloud SQL/No Public IP)"]
end
subgraph Key_Storage ["📦 External Storage"]
Keys["🔑 SSH Host Keys Storage (S3 / GCS / Azure Blob)"]
end
subgraph Logging ["📊 Logs Monitoring"]
LogsService["📈 CloudWatch / Cloud Logging / Log Analytics"]
end
end
Bastion <-->|2. Sync SSH Host Keys| Keys
Bastion -->|3. Ship auth.log & syslog| LogsService
Bastion -->|4. Access via SSH Tunneling| AppVM
Bastion -->|4. Access via Port Forwarding| DB
- Self-Healing (Auto Scaling): The bastion is deployed inside a Managed Instance Group (GCP), Auto Scaling Group (AWS), or Virtual Machine Scale Set (Azure) of size 1. If the instance fails or its Availability Zone experiences an outage, a new bastion is immediately provisioned.
- Persistent Host Keys: SSH host keys are stored externally in an S3 (AWS), GCS (GCP) bucket, or Storage Account Blob Container (Azure). When the instance is recycled, the host keys are synchronized back, ensuring that SSH clients do not encounter "Remote Host Identification Changed" warnings.
- Unattended Security Upgrades: The operating system (Ubuntu) is automatically configured to install security patches and perform a reboot at a scheduled quiet hour if a kernel update requires it.
- Central Logging: The instance ships critical authentication logs (
/var/log/auth.logand/var/log/syslog) to external services (AWS CloudWatch Logs, Google Cloud Logging, or Azure Log Analytics Workspace) so that access logs are retained even after the bastion is recycled. - Dynamic DNS / Public IP: Upon booting, the bastion automatically registers its new public IP in Route53 (AWS) or Cloud DNS (GCP), or utilizes a dynamic Azure Public IP with a custom DNS label.
- User Management: You can disable root/sudo permissions for the default
ubuntu/azureuseruser and define a list of additional local or external users with their own SSH public keys.
- aws/: Terraform module for AWS Bastion.
- gcp/: Terraform module for GCP Bastion.
- azure/: Terraform module for Azure Bastion.
- examples/: Example configurations demonstrating how to invoke the modules.
- Terraform:
>= 1.0(Latest tested version is1.9.0) - AWS Provider:
~> 4.0(To retain support for S3 bucket objects and launch configurations) - GCP Provider:
~> 4.0 - AzureRM Provider:
~> 3.0 - Template Provider:
>= 2.1.2
Before deploying these modules, ensure the following infrastructure and settings are prepared:
- AWS Credentials: Configure your AWS CLI or set environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_DEFAULT_REGION). - Target Network: Prepare an existing VPC and at least one public subnet ID (
vpc_subnet_ids). - S3 Bucket: Pre-create an S3 bucket (
infrastructure_bucket) for persistent SSH host keys. - SSH Key: Have an SSH public key content ready to associate with the default
ubuntuuser (ssh_public_key_file). - (Optional) Route53 Zone: If you wish to enable automatic A-record registration, provide the Hosted Zone ID (
route53_zone_id).
- GCP Project: Configure access to your GCP project (
gcloud auth application-default login). - Target Network: Ensure a VPC network (
network_name) and public subnetwork (subnetwork_name) are configured. - GCS Bucket: Pre-create a Google Cloud Storage bucket (
infrastructure_bucket) for persistent SSH host keys. - SSH Key: Provide the public key content (
ssh_public_key_file). - (Optional) Cloud DNS Zone: Provide the Managed Zone name (
dns_zone_name) to enable Dynamic DNS updates on boot.
- Azure Credentials: Log in to Azure via Azure CLI (
az login). - Target Network: Ensure an existing Resource Group (
resource_group_name), Virtual Network, and Subnet (subnet_id) are ready. - Storage Account: Pre-create an Azure Storage Account (
infrastructure_storage_account_id) and a private blob container (infrastructure_storage_container_name) to store SSH host keys. - SSH Key: Provide the public key content (
ssh_public_key_file) to assign to the default VM administrator. - Log Analytics Workspace: Pre-create a Log Analytics Workspace (
log_analytics_workspace_id) to gather syslog and auth logs.
This repository has a built-in CI/CD pipeline managed via GitHub Actions (.github/workflows/terraform.yml):
- Lint & Validate (CI): On every push and Pull Request, the pipeline runs code format check (
terraform fmt) and code validation (terraform validate) using Terraform 1.9.0 for AWS, GCP, and Azure examples. - Deploy (CD Mock): When changes are merged into the
masterbranch and the validation step passes, the pipeline initiates a simulated deploy job (deploy_mock). This step mocks out theterraform planandterraform applystages, printing deployment step logs and mock output variables for demonstration.