0.3_Hardened_Jump_Hosts_OCI_AWS_DigitalOcean
Hardened Jump Hosts on OCI, AWS, and DigitalOcean
BLUF: If you need a "jump point" for legitimate administration, make it a hardened bastion host with narrowly scoped ingress, strong identity controls, centralized logging, and no direct trust beyond what is required.
This note covers defensive bastion/jump-host architecture for approved administrative access. It does not cover offensive redirectors, covert proxying, or C2 infrastructure.
1. Safe Architecture
graph TD
Admin[Admin laptop
VPN or allowlisted IP] --> Bastion[Bastion / Jump Host]
Bastion --> Private1[Private workload subnet]
Bastion --> Private2[Internal admin endpoint]
Bastion --> Logs[Central logs / SIEM]
Bastion --> Patch[Patch + config management]
FW[Cloud firewall / SG / NSG] --> BastionCore Pattern
- Put the bastion in its own subnet or isolate it with strict firewall policy.
- Allow inbound access only from your admin IP range or VPN.
- Use SSH keys only or a managed access service.
- Send auth, audit, and network logs to a central location.
- Treat the bastion as ephemeral infrastructure, not a snowflake box.
2. Best Option by Cloud
| Cloud | Preferred approach | Good fallback |
|---|---|---|
| OCI | OCI Bastion service for private SSH sessions | Small hardened compute instance with NSG-restricted SSH |
| AWS | SSM Session Manager with no inbound SSH if possible | EC2 bastion with SG allowlisting and SSH keys only |
| DigitalOcean | Hardened Droplet with Cloud Firewall and private networking | Same, plus WireGuard/Tailscale if you want no public SSH from the internet |
Rule: If the cloud gives you a managed access path, prefer that over a permanently exposed VM.
3. Shared Hardening Checklist
- Disable password authentication.
- Disable direct root login.
- Restrict inbound access to a fixed source IP or VPN only.
- Use the smallest VM size that satisfies the admin task.
- Enable automatic security updates.
- Forward logs off-host.
- Use a separate admin user and
sudo; do not work as root. - Remove anything not needed: compilers, unused services, sample packages.
- Rotate SSH keys and review authorized keys regularly.
- Rebuild from code or image when possible instead of hand-tuning forever.
Minimal sshd_config Baseline
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
MaxAuthTries 3
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
Re-enable
AllowTcpForwardingonly if you explicitly need it for legitimate admin workflows.
4. GitHub Resources
These are useful as reference material for bastions, reverse proxies, and hardening patterns:
| Resource | Use |
|---|---|
| BastionBox | Simple bastion host setup ideas for cloud labs |
| docker-bastion | Minimal OpenSSH bastion container reference |
| jumpbox | Multi-user SSH jumpbox reference |
| secured-bastion-host-terraform | AWS sample for secured bastion infrastructure |
| reproxy | Lightweight reverse-proxy reference |
| ansible-cis-nginx-hardening | NGINX hardening examples |
5. Step-by-Step Walkthrough
Step 1 — Decide whether you need a VM at all
Use this decision rule:
- OCI: use OCI Bastion if the target is private and you only need admin SSH access.
- AWS: use SSM Session Manager if you can avoid inbound SSH completely.
- DigitalOcean: if no managed equivalent is available, use a hardened Droplet plus Cloud Firewall.
If you only need a short-lived admin path, avoid creating a permanent public bastion.
Step 2 — Build isolated network boundaries
Before you launch anything:
- Create or identify the target VPC/VCN/project network.
- Put the bastion in a separate subnet or isolate it with dedicated firewall rules.
- Allow inbound admin access only from:
- your static office/home IP
- a corporate VPN
- a private overlay like WireGuard or Tailscale
- Allow outbound traffic only to:
- package mirrors
- logging destinations
- the specific internal systems you administer
Do not allow 0.0.0.0/0 to SSH unless this is a temporary lab and you understand the risk.
Step 3 — Launch the smallest possible host
Preferred baseline:
- OS: Ubuntu LTS or another minimal supported image
- Size: smallest size that still handles your admin workload
- Storage: encrypted boot volume
- Identity: SSH key injection at launch, no password auth
- Metadata: do not store secrets in user-data unless you must
After first boot:
sudo apt update && sudo apt -y upgrade
sudo apt -y install fail2ban unattended-upgrades auditd
Create a dedicated admin user:
sudo adduser adminops
sudo usermod -aG sudo adminops
sudo mkdir -p /home/adminops/.ssh
sudo cp /home/ubuntu/.ssh/authorized_keys /home/adminops/.ssh/authorized_keys
sudo chown -R adminops:adminops /home/adminops/.ssh
sudo chmod 700 /home/adminops/.ssh
sudo chmod 600 /home/adminops/.ssh/authorized_keys
Step 4 — Harden SSH immediately
Edit /etc/ssh/sshd_config and apply the baseline above.
Then restart SSH:
sudo systemctl restart ssh
sudo systemctl status ssh --no-pager
Enable Fail2ban:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status
Keep one working session open while testing SSH changes so you do not lock yourself out.
Step 5 — Enable logging and updates
At minimum:
- auth logs
- sudo logs
- Fail2ban logs
- cloud flow logs / VPC flow logs / NSG logs
- auditd for privileged activity
Also enable automatic updates:
sudo dpkg-reconfigure --priority=low unattended-upgrades
If you have a SIEM or log collector, ship logs off-host so compromise of the bastion does not erase the trail.
Step 6 — Test the path like an operator
Validate all of the following:
- You can log in from the approved admin source.
- You cannot log in from an unapproved source.
- Password auth is rejected.
- Root login is rejected.
- Logs arrive centrally.
- The bastion can reach only the internal systems it is supposed to manage.
Useful checks:
ssh -o PreferredAuthentications=password adminops@bastion.example
ssh adminops@bastion.example
sudo tail -n 50 /var/log/auth.log
sudo ufw status verbose
6. OCI Walkthrough
Preferred: OCI Bastion Service
- Create or identify a private subnet for the target host.
- In OCI, create a Bastion in the same VCN.
- Create a session scoped to the target private instance.
- Restrict session lifetime and allowed CIDR/source where possible.
- Use the generated SSH command to connect through the managed bastion path.
Why this is best: no permanently exposed public SSH service is required.
If you must use a bastion VM
- Launch a small compute instance in a subnet with a public IP.
- Create an NSG or Security List rule allowing TCP/22 only from your admin IP.
- Block all other inbound ports unless there is a documented need.
- Permit outbound traffic only to required private subnets and update/logging endpoints.
- Apply the shared hardening checklist.
OCI quick checks
- NSG ingress: only TCP/22 from your IP or VPN
- Instance access: SSH key only
- Logging: VCN flow logs + instance logs if available
- Session preference: OCI Bastion over direct exposure
7. AWS Walkthrough
Preferred: SSM Session Manager
- Launch EC2 in a private subnet if possible.
- Attach an IAM role with the minimum SSM permissions needed.
- Ensure the SSM Agent is installed and online.
- Create VPC endpoints or controlled outbound internet access so the instance can reach SSM.
- Connect with Session Manager instead of exposing inbound SSH.
Why this is best: no inbound port 22 required.
If you must use an EC2 bastion
- Place the EC2 bastion in a public subnet.
- Assign a Security Group that allows:
- inbound TCP/22 from your admin IP only
- no other inbound rules unless documented
- Use private Security Groups on internal workloads so only the bastion can reach them.
- Enable CloudTrail, VPC Flow Logs, and instance logs.
- Apply the shared SSH hardening baseline.
AWS quick checks
- Security Group:
22/tcpfrom your IP only - Prefer SSM over public SSH
- CloudTrail enabled for account and region
- Session logging enabled if using Session Manager
8. DigitalOcean Walkthrough
DigitalOcean usually means you will run a real bastion host, so be stricter with boundaries.
- Create a Droplet with a minimal Ubuntu image.
- Inject your SSH public key at creation time.
- Put the Droplet behind a Cloud Firewall:
- inbound TCP/22 from your admin IP or VPN only
- deny all other inbound by default
- Use VPC networking for private traffic to internal systems.
- Apply SSH hardening, Fail2ban, and automatic updates.
- If possible, place admin access behind WireGuard or Tailscale and remove broad public exposure.
DigitalOcean quick checks
- Cloud Firewall: strict source allowlist
- VPC networking enabled for east-west traffic
- Backups/snapshots configured if the bastion is important
- Monitoring and alerts enabled
9. Reverse Proxy Guidance
Only use a reverse proxy if you need controlled application-layer access, not just SSH administration.
Safe baseline:
- TLS enabled
- only required hostnames/routes exposed
- rate limits where possible
- access logs shipped centrally
- upstreams restricted to explicit internal services
If you do not need HTTP(S) application access, do not add a reverse proxy just because it seems flexible.
10. Operator Notes
- Bastions are for access control and auditability, not convenience.
- The best bastion is often the one you can replace quickly.
- Managed access services usually beat self-managed exposed SSH.
- Keep the jump host boring, small, logged, and easy to rebuild.