Cashier
A self-service CA for OpenSSH
Install / Use
/learn @cashier-go/CashierREADME
Cashier
Cashier is a SSH Certificate Authority (CA).
OpenSSH supports authentication using SSH certificates. Certificates contain a public key, identity information and are signed with a standard SSH key.
Unlike ssh keys, certificates can contain additional information:
- Which user(s) may use the certificate
- When the certificate is valid from
- When the certificate expires
- Permissions
Other benefits of certificates:
- Unlike keys certificates don't need to be distributed to every machine - the sshd just needs to trust the key that signed the certificate.
- This also works for host keys - machines can get new (signed) host certs which clients can authenticate. No more blindly typing "yes".
- Certificates can be revoked.
See also the CERTIFICATES section of ssh-keygen(1)
How it works
The user wishes to ssh to a production machine.
They run a command which opens the CA site (e.g. https://sshca.exampleorg.com) in a browser and they login.
The CA displays a token which the user copies.
The user provides the token to the client. The client generates a new ssh key-pair.
The client sends the ssh public key to the CA along with the token.
The CA verifies the token and signs the public key with the signing key and returns the signed certificate.
The client receives the certificate and loads it and the private key into the ssh agent.
The user can now ssh to the production machine, and continue to ssh to any machine that trusts the CA signing key until the certificate is revoked or expires or is removed from the agent.
Installing
Stable versions can be obtained from the release page.
Note that installing using standard Go tools is possible, but the master branch should be considered unstable.
The server requires a configuration file (sample config).
See the configuration section for more detail.
Docker
A docker image is available. Example usage:
docker run -it --rm -p 10000:10000 --name cashier -v ${PWD}:/cashier cashier-go/cashier
Requirements
Go 1.23 or later
Server
Client
- OpenSSH 5.6 or newer.
- A working SSH agent (note that the GPG agent does not handle certificates)
Note: Cashier has only been tested on macOS and Linux.
Configuration
Configuration is divided into different sections: server, auth, ssh, and aws.
A note on files:
For any option that takes a file path as a parameter (e.g. SSH signing key, TLS key, TLS cert), the path can be one of:
- A relative or absolute filesystem path e.g.
/data/ssh_signing_key,tls/server.key. - An AWS S3 bucket + object path starting with
/s3/e.g./s3/my-bucket/ssh_signing_key. You should add an aws config as needed. - A Google GCS bucket + object path starting with
/gcs/e.g./gcs/my-bucket/ssh_signing_key. - A Vault path + key starting with
/vault/e.g./vault/secret/cashier/ssh_signing_key. You should add a vault config as needed.
Exception to this: the http_logfile option ONLY writes to local files.
server
use_tls: boolean. If this is set then eithertls_keyandtls_certare required, orletsencrypt_servernameis required.tls_key: string. Path to the TLS key. See the note on files above.tls_cert: string. Path to the TLS cert. See the note on files above.letsencrypt_servername: string. If set will request a certificate from LetsEncrypt. This should match the expected FQDN of the server.letsencrypt_cachedir: string. Directory to cache the LetsEncrypt certificate. See the note on files above.address: string. IP address to listen on. If unset the server listens on all addresses.port: int. Port to listen on.user: string. User to which the server drops privileges to. Note Dropping privileges might not work as expected as some threads may retain their privileges due to the limitations of the Go runtime.cookie_secret: string. Authentication key for the session cookie. This can be a secret stored in a vault using the form/vault/path/keye.g./vault/secret/cashier/cookie_secret.csrf_secret: string. Authentication key for CSRF protection. This can be a secret stored in a vault using the form/vault/path/keye.g./vault/secret/cashier/csrf_secret.http_logfile: string. Path to the HTTP request log. Logs are written in the Common Log Format. The only valid destination for logs is a local file path.require_reason: bool. Require the client to provide a reason when requesting a certificate. Defaults tofalse.database: See below.
database
The database is used to record issued certificates for audit and revocation purposes.
type: string. One ofmysql,sqliteormem.address: string. (mysqlonly) Hostname and optional port of the database server.username: string. Database username.password: string. Database password. This can be a secret stored in a vault using the form/vault/path/keye.g./vault/secret/cashier/mysql_password.filename: string. (sqliteonly). Path to sqlite database.dbname: string (mysqlonly). Name of database to use.
Examples:
server {
database {
type = "mysql"
address = "my-db-host.corp"
username = "user"
password = "passwd"
dbname = "cashier_production"
}
database {
type = "mem"
}
database {
type = "sqlite"
filename = "/data/cashier.db"
}
}
Cashierd will not create the database for you - you need to create this. On startup cashierd will execute any schema changes. Obviously you should setup a role user for running in prodution.
auth
provider: string. Name of the oauth provider. Valid providers are currently "google", "github" and "gitlab".oauth_client_id: string. Oauth Client ID. This can be a secret stored in a vault using the form/vault/path/keye.g./vault/secret/cashier/oauth_client_id.oauth_client_secret: string. Oauth secret. This can be a secret stored in a vault using the form/vault/path/keye.g./vault/secret/cashier/oauth_client_secret.oauth_callback_url: string. URL that the Oauth provider will redirect to after user authorisation. The path is hardcoded to"/auth/callback"in the source.provider_opts: object. Additional options for the provider.users_whitelist: array of strings. Optional list of whitelisted usernames. If missing, all users of your current domain/organization are allowed to authenticate against cashierd. For Google auth a user is an email address. For GitHub auth a user is a GitHub username.
Provider-specific options
Oauth providers can support provider-specific options - e.g. to ensure organization membership.
Options are set in the provider_opts hash.
Example:
auth {
provider = "google"
provider_opts {
domain = "example.com"
}
}
Supported options:
| Provider | Option | Notes |
|----------:|-------------------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Github | organization | If this is unset then you must whitelist individual users using users_whitelist. The oauth client and secrets should be issued by the specified organization. |
| Gitlab | allusers | Allow all valid users to get signed keys. Only allowed if siteurl set. |
| Gitlab | groups | Comma separated list of valid groups. If allusers and this are unset then you must whitelist individual users using users_whitelist. Otherwise the user must be a member of one of these groups. |
| Gitlab | siteurl | Optional. The url of the Gitlab site. Default: https://gitlab.com/ |
| Google | domain | If this is unset then you must whitelist individual email addresses using users_whitelist. |
| Microsoft | groups | Comma separated list of valid groups. |
| Microsoft | tenant | The domain name of the Office 365 account.
