Introduction
Managing SSH keys in a growing environment can be a challenging and time-consuming task. As the number of keys increases, so does the complexity of managing and securing them. Longstanding SSH keys, in particular, pose several security risks due to their static nature and potential for unauthorized access if not properly managed. To address these challenges and enhance the security of your remote access, BastionZero offers an innovative solution that streamlines key management and enforces robust security measures.
In this technical guide, we will explore the benefits of managing SSH keys with BastionZero and demonstrate how its approach mitigates the risks associated with longstanding SSH keys. By the end of this guide, you will have a clear understanding of how BastionZero simplifies the key management process while ensuring the highest level of security for your remote infrastructure.
Let’s get started.
Preparing our Account
For the purposes of this post, I’lll assume you have already signed up for a BastionZero account, have your BastionZero account integrated with your IDP, and have the ZLI installed on your local machine. We’ll do a few things in our BastionZero account to set ourselves up for success as outlined below:
- Log into BastionZero web interface at cloud.bastionzero.com
- Create a registration key
- (optional) Create an environment which we can associate our targets with
We can grab a registration key from the BastionZero web interface at cloud.bastionzero.com. Once you sign in, select "Create" in the upper righthand corner and choose "API Key."
For Registration keys, you must select the Registration Key box below the name field. Clicking "Generate API Key" will then display the new registration key ID and secret. Hang onto this secret for later! It won’t be available in the UI again once you close the dialogue.
After we have generated our registration key, we can optionally create an environment to associate our targets with. Creating an environment will allow us to group targets together so that later we can manage access policies more efficiently; when you bring up a target, you can associate it with an environment which should give access to anyone who has been granted permissions to that environment.
We’ll once again hit “Create” in the top right corner and select “Environment”. Give this environment a name (I’ll be using “test-environment” for this guide) and a description. You can configure the BastionZero platform to automatically remove offline targets after a certain period, which I’ve set to 7 days in our case.
After the environment has been created, you’ll want to find its UUID and save this for later. You can do this by checking the “Display: UUID” box and making note of the new environment’s UUID.
We’re now ready to install the agent on our target! We should have both our registration key and optional environment UUID at hand.
Install the BastionZero Agent on your target
There are a number of ways we can install the BastionZero agent on our target. Of note, you can install BastionZero alongside any current access technologies (like SSH) without issue. The primary installation methods are described here. For this blog post, we’ll assume you’re using a Debian based operating system for your target. We can take advantage of the Apt package manager for installation.
Let’s install the BastionZero agent on our target. Gain access to your target as a user with root privileges and run the following commands:
- Install the BastionZero public key from the Ubuntu key-server:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E5C358E613982017 - Add the BastionZero repo:
sudo add-apt-repository 'deb https://download-apt.bastionzero.com/production/apt-repo stable main' - Update the apt cache:
sudo apt update - Install the agent bzero:
sudo apt install -y bzero - Register your agent:
sudo bzero -registrationKey *registration key secret* -environmentId *UUID* -targetname *nameyourtarget*
You should be greeted with a prompt confirming success! Check that the target has become available in the web interface’s Targets section.
Configuring Policy
Before connecting to our new target through the ZLI, we need to create an access policy which allows us to assume a role on our target. We’ll point our browsers to the Policy section of BastionZero’s web interface and once again click “Create” in the top right hand corner. We can then build an access policy for our new target.
- Policy Type: use “Target Access” which allows us to login directly to the target
- Policy Action: use the “Shell” action to allow us to log in with the ZLI, and the “SSH Tunnel” action for SSH tunneling.
- Users: select yourself here
- Environment: select test-environment (or, if you skipped creating an environment, click “Targets” and select your registered target here)
- Allowed Target Users: select which roles you’d like to be able to assume on the target. You may want to include root or the user you logged into as when installing the agent above.
Click “Save”. You should now be ready to connect to our target!
Connecting to your BastionZero Target using the ZLI
Let’s head to our terminal and substantiate a connection to our new target. You can login to the ZLI using the zli login command.
Once you’re logged in, you should run the zli lt command to check which targets are registered and available for connection.
Next, we’ll want to try connecting to our target using a classic SSH tunnel. We’ll run the zli generate sshConfig command:
This automatically inserts an Include statement into your /.ssh/config file as shown below:
This Include statement points at /.ssh/bzero-bz-config/:
The ~/.ssh/bzero-bz-config/ file generated by zli generate sshConfig enables seamless connections to any target for which we have been granted access via the "SSH Tunnel" action in BastionZero policy.
Once the file has been generated we can then substantiate a connection to our example target using the traditional ssh bzero-user@example-target. Note: SSH tunnels are opaque to BastionZero. As a result, unlike shells, BastionZero is unable to perform command extraction when using ssh tunnels. Commands will not appear in the BastionZero logs.
You can refer to the connection events log and see that a connection was made.
Awesome! We can now SSH into targets just like we might in a more traditional environment, but with a central policy enforcement engine and without the need for longstanding credentials.
Reaching Services through SSH
Sometimes, we need to reach services through SSH tunnels, especially when dealing with databases and web services. This approach allows us to securely access remote resources without exposing them to the public internet, adding an extra layer of protection.
We can create an SSH tunnel for web services or databases that are available to targets in particular environments. For example, if we’d like to reach a service that is available on a remote target’s port 8080, we can substantiate the following command:
ssh -L 8080:localhost:8080 {username}@{target-name}
If the web service or database is not running on the same remote server as the SSH target but is still accessible from the SSH target, you can create an SSH tunnel by specifying the hostname or IP address instead of using localhost. For example, if your web service or database is running on port 5432 and is accessible via the address {remote-hostname} from the SSH target, you can use the following command:
ssh -L 5432:{remote-hostname}:5432 {username}@{target-name}
After establishing the tunnel, you can connect to the remote web service or database using a local client as if the database were running on your local machine.
Shortcuts
The ~/.ssh/config file allows you to configure various options that can make connecting to remote infrastructure easier and more efficient so that you don’t have to remember “long winded” SSH commands. Here are some useful examples that may prove helpful when you’re hoping to access services proxied through a BastionZero agent via SSH Tunnels:
- Local port forwarding:
Suppose you have a remote server running a web application on port 8080, but you cannot access it directly from your local machine. You can use local port forwarding with BastionZero to create a secure tunnel to the remote server and access the web service or database through a local port.
Add the following configuration to your ~/.ssh/config file:
Host example-service
HostName {target-name}
User {username}
Port 22
LocalForward 8080 localhost:8080
With this configuration, you can simply run ssh example-service to create a secure tunnel. The web application running on the remote server's port 8080 will be accessible via http://localhost:8080 on your local machine.
- Local port forwarding with remote host:
If the web service or database is not running on the same remote server as the SSH target but is still accessible from the SSH target, you can create an SSH tunnel by specifying the hostname or IP address instead of using localhost. You can use local port forwarding to create a secure tunnel to the remote server and access the web application or database through a local port.
Add the following configuration to your ~/.ssh/config file:
Host example-service
HostName {target-name}
User {username}
Port 22
LocalForward 8080 {remote-host}:8080
With this configuration, you can simply run ssh example-service to create a secure tunnel. The web application running on the remote server's port 8080 will be accessible via http://localhost:8080 on your local machine.
- Dynamic port forwarding (SOCKS proxy tunneling):
Dynamic port forwarding can be used to create a SOCKS proxy, which routes all traffic through the remote server. This can be helpful for browsing the web securely or accessing resources within a private network.
Add the following configuration to your ~/.ssh/config file:
Host example-service
HostName {target-name}
User {username}
Port 22
DynamicForward 1080
With this configuration, you can run ssh example-service to create a SOCKS proxy on port 1080 of your local machine. To use the proxy, configure your browser or other applications to use the SOCKS proxy at localhost:1080.
These are just a few examples of how you can utilize the ~/.ssh/config file for port forwarding and SOCKS proxy tunneling to simplify and enhance your remote infrastructure connections.
Conclusion
By adopting BastionZero for SSH key management, we've embraced a Zero Trust access approach that eliminates the need for longstanding keys or credentials. This modern solution offers enhanced security, streamlined key management, and adherence to the principle of least privilege, significantly reducing the risks associated with traditional SSH key management practices. In a future blog post, we’ll cover how to further improve our access to remote services using the zli and Bastionzero’s proxy policies, which increases visibility into what actions are being performed by users and negates the need to manually modify our ~/.ssh/config file.