/ysshra

Primary LanguageGoApache License 2.0Apache-2.0

YSSHRA

YSSHRA is the registration authority of YSSHCA (Yahoo SSHCA).

A service to authenticate the client and provision ephemeral SSH user certificate. Note: Features for attestation check during authentication, yubikey based touch-to-login and touch-to-sudo are coming up next.

Crypki can be used as the CA signing backend of the service.

Table of Contents

Install

This installation guide assumes the use of Crypki as the signing backend.

Disclaimer: The following guidelines are to help you to get started with YSSHCA;

they should be used only for testing/development purposes.

1. Add authorized users

  • Add your username into docker/ysshra/user_allowlist.txt.

2. Build ysshra docker image

docker build -f ./docker/Dockerfile -t ysshra-local .

Password authentication is disabled (PermitEmptyPasswords yes, AuthenticationMethods none) in sshd config file at docker/ysshra/ssh/sshd_config.ysshra. You can customize it or pull in PAM modules for your own environments.

3. Generate host certificates and user keys

pushd ./docker

# Generate sshd host certificates.
./gen-ssh-crt.sh

# Generate ssh user keys.
./gen-user-key.sh ./ysshra/user_allowlist.txt

popd

4. Setup CA signing backend (Crypki)

Please refer to the section Install in Crypki readme.

Copy ca.crt client.crt and client.key to the folder docker/tls-crt in this repo.

CRYPKI_CRT_PATH=${PATH_TO_CRYPKI_REPO}/docker-softhsm/tls-crt

mkdir -p ./docker/tls-crt
cp ${CRYPKI_CRT_PATH}/ca.crt ${CRYPKI_CRT_PATH}/client.crt ${CRYPKI_CRT_PATH}/client.key ./docker/tls-crt

Note: These steps configure Crypki to use SoftHSM. For production setup, a physical HSM or cloud HSM should be used.

5. Run ysshra container

pushd ./docker

docker run -d -p :222:222 -v $PWD/log:/var/log/ysshra -v $PWD/tls-crt:/opt/ysshra/tls-crt:ro \
-v $PWD/ssh-crt:/opt/ysshra/ssh-crt:ro -v $PWD/config.sample.json:/opt/ysshra/config.json \
-v $PWD/ssh-user:/etc/ssh/authorized_public_keys/ \
--rm --name ysshra -h "localhost" ysshra-local 

# setup network for ysshra container and crypki container. 
docker network create pki
docker network connect pki ysshra
docker network connect pki crypki

popd

6. Verify the YSSHRA server is up and running

$telnet localhost 222 
Trying ::1...
Connected to localhost.
Escape character is '^]'.
SSH-2.0-OpenSSH_8.9p1 Debian-3

You may then refer to the regular-cert steps to request a user certificate from the YSSHRA container.

Configuration

We include a valid gensign configuration file here in the YSSHRA docker.

Some default values are also provided in config.go.

Usage

SSH Certificate

YSSHCA utilizes Go SSH library to generate SSH certificates and CSRs, which conforms to the format defined in OpenSSH.
YSSHCA defines an extensible key ID format for user certificates, and uses it to identify the types and usages of SSH certificates for different PAM modules.

The Key ID field in a SSH certificate is typically used to identify in human-readable form the specific certificate signing key (potentially stored in an HSM), the specific user key wrapped by the certificate, or both. However, YSSHCA Key ID is in JSON format, which enables gensign and different CSR handlers (or modules) to fill detailed information into CSR and certificates. Compared to other certificate attributes (e.g. critical options), Key ID can be logged in OpenSSH during SSH handshake and in YSSHRA gensign easily.

Following is a regular SSH certificate generated by YSSHRA. The certificate principals (prins), transaction ID (transID), request user (reqUser), request IP (reqIP), request host (reqHost) and Key ID version (ver) can be found in the parsed certificate.

Type: ssh-rsa-cert-v01@openssh.com user certificate
Public key: RSA-CERT SHA256:psiQqqfGzADw4NR83WeJgTbnZ5oOlqbnC3ggncdGHHI
Signing CA: RSA SHA256:mho4TPD8zXYmXT1Zx5EelKi4imBjwgyIBqYTm9X9YB0 (using rsa-sha2-256)
Key ID: "{"prins":["user_a"],"transID":"15537d7b63","reqUser":"user_a","reqIP":"172.17.0.1","reqHost":"localhost","isFirefighter":false,"isHWKey":false,"isHeadless":false,"isNonce":false,"usage":0,"touchPolicy":1,"ver":1}"
...

Other fields are defined as follows:

Type Meaning Values Remark
isFirefighter Bool Whether the cert is for emergency situation True/False Firefighter certs usually have longer validity (e.g. 30 days) for emergency situation.
isHWKey Bool Whether the private key of the cert is backed in a hardware (e.g. yubikey, HSM) True/False Usually a hardware certificate requires a touch (or a 2nd authN) during challenge response.
isHeadless Bool Whether the cert is provisioned for headless user (CICD tools) True/False Usually a headless certificate doesn't require a touch (or a 2nd authN) during challenge response.
isNonce Bool Whether the cert is a short living one-time authN password True/False
usage Enum (uint) Usage limitation on the certificate 0: all usage; 1: SSH only
touchPolicy Enum (uint) Indicate whether the cert require a touch or not during challenge response. 0: Default; 1: Never; 2: Always; 3: Cached

Certificate Type

YSSHRA declares Handler interface to define the behaviors that handle users' SSH certificate requests. A handler generate various types of CSRs for a particular scenario usage. The handler can be configured in gensign config path (/opt/ysshra/config.json).

Certificate Type: Regular

YSSHRA provides Regular Handler to generate regular CSRs for a non-yubikey scenario. That is, a user presents the regular certificate to a SSH/SUDO PAM module. Then the module authenticate the user by key challenge against the priv key in the user's SSH agent without a touch. The key ID fields of a regular certificate are shown as follows:

Value
isFirefighter F
isHWKey F
isHeadless F
isNonce F
usage 0 (All Usages)
touchPolicy 1 (Never Touch)

Request a regular user certificate from the ysshra container

Note: user_a exists in docker/ysshra/user_allowlist.txt, and the corresponding linux user was created in ysshra container during the docker build.

  • Add user_a's private key to the ssh-agent
ssh-add -K ./docker/ssh-user/user_a
  • ssh against the ysshra container
ssh -A user_a@localhost -p 222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
'{"ifVer":7, "username":"user_a", "hostname":"localhost", "sshClientVersion":"0.0"}'

Note: You may encounter The authenticity of host '[localhost]:222 ([::1]:222)' can't be established error when performing SSH against localhost without options -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no. To get rid of it, please append the CA public key ./docker/ssh-crt/host_ca_key.pub to your known host file ~/.ssh/known_hosts.

echo "@cert-authority *" $(cat ./docker/ssh-crt/host_ca_key.pub) >> ~/.ssh/known_hosts
 
ssh -A user_a@localhost -p 222 '{"ifVer":7, "username":"user_a", "hostname":"localhost", "sshClientVersion":"0.0"}'
  • Check the requested certificate
$ssh-keygen -Lf <(ssh-add -L)
...
/dev/fd/63:14:
        Type: ssh-rsa-cert-v01@openssh.com user certificate
        Public key: RSA-CERT SHA256:psiQqqfGzADw4NR83WeJgTbnZ5oOlqbnC3ggncdGHHI
        Signing CA: RSA SHA256:mho4TPD8zXYmXT1Zx5EelKi4imBjwgyIBqYTm9X9YB0 (using rsa-sha2-256)
        Key ID: "{"prins":["user_a"],"transID":"15537d7b63","reqUser":"user_a","reqIP":"172.17.0.1","reqHost":"localhost","isFirefighter":false,"isHWKey":false,"isHeadless":false,"isNonce":false,"usage":0,"touchPolicy":1,"ver":1}"
        Serial: 0
        Valid: from 2022-03-03T17:31:48 to 2022-03-04T06:31:48
        Principals: 
                user_a
        Critical Options: (none)
        Extensions: 
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc

Contribute

Please refer to Contributing.md for information about how to get involved. We welcome issues, questions, and pull requests.

License

This project is licensed under the terms of the Apache 2.0 open source license. Please refer to LICENSE for the full terms.