PromptHub
DevOps Cybersecurity

Stop Managing SSH Keys Manually! Bastillion Is the Browser Tool You Need

B

Bright Coding

Author

15 min read
181 views
Stop Managing SSH Keys Manually! Bastillion Is the Browser Tool You Need

Stop Managing SSH Keys Manually! Bastillion Is the Browser Tool You Need

What if I told you that every time you manually copy an SSH key to a server, you're rolling the dice on your entire infrastructure's security?

Here's the brutal truth that keeps DevOps engineers awake at night: SSH key sprawl is a silent killer. You've got hundreds—maybe thousands—of servers. Keys scattered across laptops, shared drives, and who-knows-where. One compromised developer machine, and your entire cloud estate becomes an attacker's playground. The traditional bastion host approach? It's secure, sure, but configuring OpenSSH, managing authorized_keys files across dozens of systems, and tracking who has access to what? It's a nightmare of bash scripts, cron jobs, and prayer.

But what if securing SSH access didn't require a PhD in Linux administration? What if you could manage keys, launch terminal sessions, and enforce multi-factor authentication—all from a clean, modern web dashboard?

Enter Bastillion.

This isn't just another open-source tool gathering dust on GitHub. It's a modern, web-based SSH console and key management platform that's rapidly becoming the secret weapon of infrastructure teams who refuse to compromise between security and usability. Think of it as your bastion host reimagined for 2024: browser-based terminals, automatic key distribution, 2FA baked in from day one, and a dashboard that actually makes sense.

Ready to stop the SSH chaos? Let's dive deep into why Bastillion deserves a permanent place in your security stack.


What Is Bastillion?

Bastillion is an open-source, web-based SSH console and SSH key management tool created by Sean Kavanagh of Loophole, LLC. Built on a modern Java stack and recently upgraded to Java 21 and Jakarta EE 11, it delivers exactly what overworked infrastructure teams crave: centralized SSH access control without the configuration hell.

The project's philosophy is elegantly simple. Instead of logging into a jump server and manually juggling keys, you open a browser. Instead of tracking authorized_keys across hundreds of machines, Bastillion distributes and rotates keys automatically. Instead of hoping your team enabled 2FA everywhere, it's enforced at the entry point.

Why it's trending now: The recent v4.x releases brought game-changing updates. Full Ed25519 and Ed448 SSH key support (with Ed25519 now the default) addresses modern cryptographic standards. A new daemon mode for Jetty enables proper background service operation. And with dependencies refreshed for improved security posture, Bastillion is positioning itself as the go-to replacement for aging solutions like Teleport's heavier footprint or the complexity of HashiCorp Boundary.

The project sits at a sweet spot: more feature-rich than basic SSH certificate authorities, yet lighter and more focused than full-blown privileged access management suites costing thousands per user. For teams running 50-5000 servers who need enterprise-grade SSH security without enterprise-grade bloat, Bastillion hits the mark.


Key Features That Make Bastillion Stand Out

Let's dissect what makes this tool genuinely powerful for real-world operations:

🔐 Browser-Based SSH Console No more PuTTY configurations, no more terminal emulator juggling. Bastillion renders full terminal sessions in your browser using proven components (built on term.js foundations). Multiple concurrent sessions? Check. Command sharing across sessions? Absolutely. The web shell experience feels surprisingly native—responsive, with proper color support and keyboard handling.

🗝️ Intelligent SSH Key Management This is where Bastillion shines. It doesn't just store keys; it orchestrates them. Generate Ed25519 key pairs (now default), distribute public keys to managed systems, and refresh authorized_keys automatically on configurable intervals. The keyManagementEnabled toggle lets you choose between Bastillion-controlled keys or append-mode coexistence with existing infrastructure.

🛡️ Mandatory Two-Factor Authentication Built-in TOTP support using Authy or Google Authenticator. Not bolted-on. Not optional. This is enforced at the authentication layer, meaning even if credentials leak, your infrastructure has a second gate. For compliance-minded teams (SOC 2, ISO 27001), this is audit-friendly out of the box.

🔒 TLS/SSL Over SSH Stacking Defense in depth isn't just a buzzword here. Bastillion supports encrypting your SSH connections inside TLS/SSL tunnels. In hostile network environments or when traversing untrusted segments, this double-wrapping provides meaningful additional protection without client-side complexity.

👥 LDAP/AD Integration Enterprise environments don't live in isolation. The jaas.conf configuration supports OpenLDAP, Active Directory, and custom schemas. Role-to-profile mapping means your existing group structures automatically translate into Bastillion access controls. First-time LDAP logins auto-provision admin accounts with configurable profile assignment.

📊 Comprehensive Auditing Disabled by default (performance-conscious), but enable enableInternalAudit=true and configure log4j2 appenders, and you get full session and command audit trails. Critical for forensics, compliance reporting, and understanding who touched what when.

⚡ Modern Cryptography Ed25519 default keys offer ~128-bit security with faster operations than RSA-4096. Need more? Ed448 provides ~224-bit security equivalent. RSA and ECDSA remain available for legacy compatibility, but the trajectory is clear: Bastillion embraces modern, post-quantum-resistant curve foundations.


Real-World Use Cases Where Bastillion Dominates

1. The Multi-Cloud MSP Nightmare

You're managing AWS, Azure, and on-premise servers for 15 clients. Each has different key practices, some use shared keys (shudder), and onboarding a new engineer means manually configuring access across 200+ machines. Bastillion collapses this to: one dashboard, role-based profiles per client, automatic key distribution, and 2FA that travels with the engineer—not the machine.

2. Compliance-Driven Financial Services

Your CISO demands: 2FA on all administrative access, key rotation every 90 days, command logging for SOX audits, and no shared credentials. Implementing this natively across 800 Linux servers would require a dedicated team. Bastillion delivers: enforced TOTP, configurable key refresh intervals, audit logging to SIEM, and individual accountability through named accounts.

3. Rapidly Scaling Startup Infrastructure

You went from 20 to 200 servers in six months. Your "SSH keys in 1Password" approach is breaking. Engineers are copying keys manually, leaving orphan access on terminated instances, and nobody knows who has access to production databases. Bastillion provides: centralized key lifecycle management, automatic cleanup through refresh intervals, and instant visibility into all access relationships.

4. Secure Contractor and Vendor Access

External consultants need temporary production access for migrations. Traditional approaches: create local accounts (dangerous), share jump host credentials (worse), or deploy complex VPN setups (slow). Bastillion enables: time-bounded profile assignments, full session recording, immediate revocation through profile removal, and no direct credential exposure.


Step-by-Step Installation & Setup Guide

Ready to deploy? Here's your complete path from zero to secure SSH management.

Prerequisites

Java 21 is non-negotiable for current versions. Install OpenJDK:

# Debian/Ubuntu
apt-get install openjdk-21-jdk

# Verify installation
java -version  # Should report 21.x.x

For Oracle JDK, download from Oracle's official site.

Maven 3+ (for source builds):

apt-get install maven

2FA Application: Install Authy or Google Authenticator on your mobile device before first login.

Download and Configure

Grab the latest release from GitHub Releases or the AWS Marketplace for one-click cloud deployment.

Set your Java environment:

# Linux/macOS
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64  # Adjust path as needed
export PATH=$JAVA_HOME/bin:$PATH

# Windows (Command Prompt)
set JAVA_HOME=C:\Program Files\Java\jdk-21
set PATH=%JAVA_HOME%\bin;%PATH%

Launch Bastillion

Foreground mode (development, troubleshooting):

./startBastillion.sh

Daemon mode (production, background service):

./startBastillion.sh --daemon

Logs write to jetty/logs/YYYY_MM_DD.jetty.log. Need verbose output for debugging?

./startBastillion.sh -d

Stop the service:

./stopBastillion.sh

First Access and Hardening

Navigate to https://<your-server-ip>:8443 (or https://<instance-ip>:443 for AWS AMI deployments).

Default credentials (change immediately!):

username: admin
password: changeme

You'll be prompted to configure 2FA on first login. Scan the QR code with your authenticator app, store backup codes securely, and you're operational.

Build from Source (Developers/Contributors)

# Clone the repository
git clone https://github.com/bastillion-io/Bastillion.git
cd Bastillion

# Build and run with embedded Jetty
mvn package jetty:run

⚠️ Critical Warning: mvn clean destroys the embedded H2 database and all user data. Never run clean in production without verified backups.


REAL Code Examples from Bastillion

Let's examine actual configuration patterns from the repository, with detailed explanations of how to wield them effectively.

Example 1: SSH Key Type Selection and Custom Key Pair

This configuration from BastillionConfig.properties controls the cryptographic identity Bastillion uses when connecting to managed systems:

# Regenerate and import SSH keys on next startup
# Set to true when rotating keys or initial setup
resetApplicationSSHKey=true

# SSH key type selection - critical for security/performance balance
# Supported options:
#   rsa     - Classic compatibility, configurable length (default 4096)
#   ecdsa   - Faster operations, smaller keys (P-256/384/521 curves)
#   ed25519 - DEFAULT and RECOMMENDED (≈128-bit security, fast, compact)
#   ed448   - Extra-strength (≈224-bit security, slower, limited support)
sshKeyType=ed25519

# Optional: Use existing key pair instead of generating
# Comment out these lines to auto-generate
# privateKey=/Users/you/.ssh/id_ed25519
# publicKey=/Users/you/.ssh/id_ed25519.pub

# Passphrase for private key (leave empty if unencrypted)
# Remove from config after registration for security
defaultSSHPassphrase=myPa$$w0rd

Why this matters: The sshKeyType=ed25519 default reflects modern best practices. Ed25519 keys are faster to generate, smaller to transmit, and resist side-channel attacks better than RSA. The resetApplicationSSHKey=true flag is your key rotation mechanism—set it, restart, and Bastillion generates fresh credentials. Security tip: After initial registration, remove privateKey, publicKey, and defaultSSHPassphrase from the configuration file. Bastillion stores these securely in its database; leaving paths in plaintext configs is unnecessary exposure.

Example 2: Database Configuration with Encryption

Bastillion uses H2 by default, but production deployments need proper security. Here's the encrypted embedded configuration:

# Database credentials for H2 embedded mode
# CHANGE THESE from defaults before production use
dbUser=bastillion
dbPassword=p@$$w0rd!!

# H2 driver class - required for JDBC connectivity
dbDriver=org.h2.Driver

# Connection URL with AES encryption for data-at-rest protection
# CIPHER=AES enables transparent database encryption
# Store the password separately from backups for true security
dbConnectionURL=jdbc:h2:keydb/bastillion;CIPHER=AES;

For remote H2 (separate database server or container):

# TCP mode for externalized database - enables HA configurations
dbConnectionURL=jdbc:h2:tcp://db-server.internal:9092/~/bastillion;CIPHER=AES;

Implementation insight: The CIPHER=AES parameter is crucial. Without it, your H2 database file is plaintext on disk—any filesystem access exposes all SSH keys and audit logs. For production, consider migrating to PostgreSQL or MySQL (supported through JDBC) for better concurrency and backup tooling.

Example 3: LDAP Integration with Role Mapping

Enterprise authentication requires careful JAAS configuration. Here's the role-aware LDAP setup:

# In BastillionConfig.properties: specify which JAAS module to load
jaasModule=ldap-ol-with-roles
// In jaas.conf - LDAP with automatic role-to-profile mapping
ldap-ol-with-roles {
    org.eclipse.jetty.jaas.spi.LdapLoginModule required
    debug="false"                          // Set true for troubleshooting only
    useLdaps="false"                       // Set true and configure port 636 for TLS
    contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
    hostname="ldap.company.internal"       // Your LDAP server FQDN
    port="389"                             // 636 for LDAPS
    bindDn="cn=bastillion-service,ou=service-accounts,dc=company,dc=com"
    bindPassword="<SERVICE_ACCOUNT_PASSWORD>"  // Use environment variable injection in production
    authenticationMethod="simple"
    forceBindingLogin="true"               // Validates credentials via bind, not compare
    
    // User search configuration
    userBaseDn="ou=employees,dc=company,dc=com"
    userRdnAttribute="uid"                 // Attribute forming user's RDN
    userIdAttribute="uid"                  // Attribute matching login username
    userPasswordAttribute="userPassword"   // Where password hash lives
    userObjectClass="inetOrgPerson"        // LDAP object class for users
    
    // Group/role mapping - THIS IS THE MAGIC
    roleBaseDn="ou=groups,dc=company,dc=com"
    roleNameAttribute="cn"                 // Group CN becomes Bastillion profile name
    roleMemberAttribute="member"           // Attribute linking user to group
    roleObjectClass="groupOfNames";        // LDAP object class for groups
};

How this works: When jdoe logs in, Bastillion binds to LDAP, finds jdoe in ou=employees, then searches ou=groups for entries where member=jdoe. If jdoe is in cn=linux-admins,ou=groups, Bastillion automatically grants the "linux-admins" profile. First login creates the admin account—no manual provisioning needed. This syncs continuously, so removing someone from the LDAP group revokes access on next authentication.

Example 4: Enabling Comprehensive Auditing

Security without audit trails is faith, not verification. Enable full auditing:

# In BastillionConfig.properties
enableInternalAudit=true

Then in log4j2.xml, uncomment these critical lines:

<!-- Uncomment to capture all system audit events -->
<Logger name="io.bastillion.manage.util.SystemAudit" level="info" additivity="false">
    <AppenderRef ref="audit-appender"/>
</Logger>

<!-- Ensure this appender exists and is configured -->
<Appender name="audit-appender" class="org.apache.logging.log4j.core.appender.RollingFileAppender">
    <!-- File path, rotation policy, and formatting details -->
</Appender>

What gets captured: Every command executed, every key distributed, every login attempt (success and failure), profile changes, and system modifications. Feed this to your SIEM via filebeat or fluentd for real-time security monitoring.


Advanced Usage & Best Practices

🔥 Production Hardening Checklist

  • Replace default admin/changeme before first internet exposure
  • Switch from embedded H2 to PostgreSQL for team deployments
  • Enable LDAPS (port 636) with valid certificates, not useLdaps=false
  • Mount jetty/logs/ to persistent storage for container deployments
  • Restrict firewall rules: only bastion hosts need 8443/tcp access

⚡ Performance Optimization

  • The authKeysRefreshInterval=120 (minutes) balances freshness with LDAP load. Increase for stable environments; decrease during active provisioning periods.
  • Daemon mode (--daemon) with systemd integration provides proper service management:
# /etc/systemd/system/bastillion.service
[Unit]
Description=Bastillion SSH Management
After=network.target

[Service]
Type=forking
User=bastillion
ExecStart=/opt/bastillion/startBastillion.sh --daemon
ExecStop=/opt/bastillion/stopBastillion.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target

🔄 Key Rotation Strategy Set resetApplicationSSHKey=true, restart, then set back to false. Document rotation dates. For maximum security, automate this quarterly via your configuration management tool.


Comparison with Alternatives

Feature Bastillion Teleport HashiCorp Boundary Traditional Jump Host
Deployment Complexity Low (single JAR) Medium (multiple services) High (HashiCorp stack) High (manual config)
Browser-Based Shell ✅ Native ✅ Native ✅ Native ❌ Requires client
2FA Enforcement ✅ Built-in TOTP ✅ Multiple methods ✅ Multiple methods ❌ Manual PAM config
SSH Key Management ✅ Automatic distribution ✅ Certificate-based ✅ Session-based ❌ Manual
Open Source Core ✅ Prosperity License ✅ Apache 2.0 (partial) ✅ MPL 2.0 N/A
Enterprise Pricing Free / AWS Marketplace $$$ Per-user pricing $$$ Enterprise tier Hardware + labor
Protocol Support SSH only SSH, K8s, DB, RDP Multiple protocols SSH only
Resource Footprint ~512MB RAM ~2GB+ RAM ~1GB+ RAM Variable

When to choose Bastillion: You need robust SSH access management without the operational overhead of a service mesh. Your team is 5-50 engineers managing hundreds of Linux servers. You want 2FA and key management now, not after a three-month implementation project.

When to look elsewhere: You need Kubernetes-native access, database protocol support, or deep identity provider integrations (Okta, Azure AD with SAML). For pure SSH at scale, Bastillion punches far above its weight.


Frequently Asked Questions

Q: Is Bastillion really free for commercial use? A: Bastillion uses the Prosperity Public License, which permits free use for non-commercial and small commercial purposes. Larger enterprises should review license terms or contact Loophole, LLC for commercial licensing. The AWS Marketplace offers supported deployments.

Q: Can I use my existing SSH keys with Bastillion? A: Absolutely. Specify privateKey and publicKey paths in BastillionConfig.properties, or let Bastillion generate fresh Ed25519 keys. Existing authorized_keys files can be preserved with keyManagementEnabled=false.

Q: How does Bastillion compare to SSH certificate authorities? A: SSH CAs (like Vault's) use short-lived certificates instead of keys. Bastillion uses traditional key pairs with automated distribution and rotation. Certificates offer theoretical advantages; Bastillion's approach is simpler to understand, debug, and recover from when things go wrong.

Q: Is the browser-based terminal secure? A: Yes. All traffic flows over HTTPS (TLS 1.2+). The SSH connection itself can be wrapped in additional TLS (TLS/SSL over SSH). The terminal uses established libraries (term.js heritage) with no persistent client-side storage of credentials.

Q: Can I run Bastillion in Docker or Kubernetes? A: While not officially distributed as a container, the JAR-based deployment containers easily. Mount configuration files and the H2 database (or use external PostgreSQL) as volumes. The daemon mode (--daemon) suits Kubernetes deployments with proper liveness probes.

Q: What happens if the Bastillion server is compromised? A: This is your critical dependency—design accordingly. Use full-disk encryption, restrict server access severely, enable comprehensive auditing, and maintain offline backups of configuration. The database encryption (CIPHER=AES) protects data-at-rest. Consider Bastillion itself as your most protected bastion host.

Q: Does Bastillion support SSH agent forwarding? A: No, and this is intentional security design. Agent forwarding creates attack surfaces. Bastillion manages keys centrally and uses its own identity for connections, preventing lateral movement if a user's local machine is compromised.


Conclusion: Your SSH Infrastructure Deserves Better

Let's be honest: manual SSH key management is a relic of a simpler time. In an era of automated infrastructure, instant scaling, and relentless security threats, copying id_rsa.pub between servers is not just inefficient—it's reckless.

Bastillion offers a genuinely better path. It combines the security rigor of a properly configured bastion host with the operational sanity of a modern web application. Ed25519 cryptography by default. Two-factor authentication that actually works. Key distribution that happens automatically, not by ticket request. And a browser interface that your team will actually use instead of circumventing.

Is it perfect? No tool is. The Prosperity License requires attention for large deployments. The H2 default database needs replacement for serious scale. But as a foundation for SSH access management—especially for teams transitioning from chaos to control—Bastillion delivers exceptional value with minimal friction.

My recommendation? Deploy it this week. Start with a non-production environment. Experience what it's like to onboard a new engineer in five minutes instead of five hours. Feel the relief of knowing that when someone leaves, their access disappears with a profile change, not a frantic grep through /home/*/.ssh/authorized_keys.

Your future self—debugging a 3 AM production incident with clean audit trails and secure access—will thank you.

👉 Get Bastillion on GitHub | AWS Marketplace Deployment


Have you deployed Bastillion in your environment? Found clever configurations or hit unexpected challenges? Share your experience in the comments—let's build better SSH practices together.

Comments (0)

Comments are moderated before appearing.

No comments yet. Be the first to share your thoughts!

Support us! ☕