top of page
Search

SSH Agents

An SSH key is a pair of cryptographic keys, consisting of a public key and a private key, used for secure communication and authentication over the Secure Shell (SSH) protocol. Keys are generated with  a tool like `ssh-keygen`. The public key is shared with the server or service being accessed. It's often added to a file called `authorized_keys` on the server. When an SSH connection is initialized, the server sends a challenge. The SSH client uses the private key to create a signature, proving an identity. The server then verifies the signature using its stored public key and if the keypair matches, the admin is granted access.



This is more secure than traditional passwords, which can be compromised. Keys are difficult to crack and offer protection against brute-force attacks. Once set up, you don't need to enter passwords for subsequent connections, although the configuration can be made where a key and a password are required. But if not, SSH keys are ideal for automated tasks like remote backups and server management. Or on premesis git version control.


However, this means the private key must be kept secure and never shared it with anyone. Administrators can use a passphrase to protect your private key in case it's compromised. Keys should also be regularly updated. This makes the process of managing SSH keys and passprhases for every server somewhat tedius. This is where SSH agents come into play.


Secret Chest can be an SSH agent. This means we can securely store  SSH keys in encrypted vaults. This protects the keys from unauthorized access, even if a device is compromised. It also provides more granular policy-based controls over how and when SSH keys can be used. Effectively, when it’s time to use an SSH key, Secret Chest interacts with the system's SSH agent, a background program that manages SSH keys in memory. Secret Chest then assembles shards and decrypts the chosen SSH key and loads the decrypted key into the SSH agent.


When administrators logging into an SSH server attempt to establish a connection using a command-line tool like ssh, the tool automatically checks with our SSH agent for available keys. If a matching key is found, the agent provides it to the SSH client without prompting for the key's passphrase again. This is convenient, as there’s no need to manually enter passphrases for each SSH connection. It’s also more secure, as keys are stored securely and only decrypted when needed. It also surfaces other options like agent forwarding, granular timeouts for key usage, and if enabled, multi-peer sharing of shards.


SSH agents live in the background, diligently holding  precious SSH keys, ready to unlock server doors at your command. No more typing passphrases for each login; we streamlines workflows with single sign-on convenience. Then keys vanish from memory once used. That’s a critical aspect of how Secret Chest’s SSH agent works. Keys are stored securely in memory, as there’s ample garbage collection done when methods to add, remove, list, and retrieve keys are run. This is more than the traditional Unix domain socket for communication with SSH clients, even though libraries like  SwiftNIO are used for efficient network communication.


At Secret Chest, we believe in transparency. We also believe that administrators should be able to do things with or without us - but choose to do so with us because we do things more securely. In that spirit, let’s look at a basic implementation of an SSH agent in Swift. The following code uses SwiftNIO for non-blocking network programming and socket handling, CryptoSwift for cryptographic operations like signature verification, and KeychainAccess for secure storage of keys in the Keychain:


import SwiftNIO
import CryptoSwift
import KeychainAccess

class SSHAgent {
    // Properties for key storage, socket, etc.
    init() {
        // Create Unix domain socket
    }

    func addKey(key: String, passphrase: String) throws {
        // Decrypt key, store in memory, add to Keychain
    }

    func authenticate(challenge: Data) -> Data? {
        // Find matching key, sign challenge, return signature
    }

    func forwardAgent() -> Bool {
        // Implement agent forwarding logic
    }

    // Other methods for key management, communication, etc.
}

If building a custom agent, make sure it’s secure by prioritizing secure key storage and memory management.  Also implement robust error handling for key operations, authentication, and communication, thoroughly testing the agent with various SSH clients and scenarios. Also check out other projects, like Shout, available at https://github.com/jakeheis/Shout. It’s fairly straight forward to use SSH agents to further secure keys, but also before going there, check out what we’ve built by joining us for our private beta!

9 views0 comments

Recent Posts

See All
bottom of page