{"id":16078005,"url":"https://github.com/cashier-go/cashier","last_synced_at":"2026-01-11T23:56:08.570Z","repository":{"id":7879848,"uuid":"56542476","full_name":"cashier-go/cashier","owner":"cashier-go","description":"A self-service CA for OpenSSH","archived":false,"fork":false,"pushed_at":"2025-02-06T10:05:28.000Z","size":11645,"stargazers_count":711,"open_issues_count":39,"forks_count":46,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-02-06T21:30:32.093Z","etag":null,"topics":["certificate","certificate-authority","openssh","ssh","ssh-key"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cashier-go.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-04-18T21:11:30.000Z","updated_at":"2025-02-06T11:19:46.000Z","dependencies_parsed_at":"2023-11-26T14:52:50.790Z","dependency_job_id":"bee91ae9-b8c3-4df4-8ef3-f02f5c699a39","html_url":"https://github.com/cashier-go/cashier","commit_stats":{"total_commits":296,"total_committers":11,"mean_commits":26.90909090909091,"dds":"0.10472972972972971","last_synced_commit":"681997c28972f6d56509603e43b59007629432f1"},"previous_names":["cashier-go/cashier"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cashier-go%2Fcashier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cashier-go%2Fcashier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cashier-go%2Fcashier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cashier-go%2Fcashier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cashier-go","download_url":"https://codeload.github.com/cashier-go/cashier/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237739846,"owners_count":19358624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["certificate","certificate-authority","openssh","ssh","ssh-key"],"created_at":"2024-10-09T10:05:45.899Z","updated_at":"2025-10-22T20:30:55.292Z","avatar_url":"https://github.com/cashier-go.png","language":"Go","funding_links":[],"categories":["others","Go"],"sub_categories":[],"readme":"# Cashier\n\n- [Cashier](#cashier)\n\t- [How it works](#how-it-works)\n- [Installing](#installing)\n  - [Docker](#docker)\n- [Requirements](#requirements)\n\t- [Server](#server)\n\t- [Client](#client)\n- [Configuration](#configuration)\n\t- [server](#server-1)\n\t\t- [database](#database)\n\t- [auth](#auth)\n\t\t- [Provider-specific options](#provider-specific-options)\n\t- [ssh](#ssh)\n\t- [aws](#aws)\n\t- [vault](#vault)\n- [Usage](#usage)\n\t- [Using cashier client](#using-cashier-client)\n\t- [Configuring SSH](#configuring-ssh)\n\t- [Revoking certificates](#revoking-certificates)\n- [Future Work](#future-work)\n- [Contributing](#contributing)\n\nCashier is a SSH Certificate Authority (CA).\n\nOpenSSH supports authentication using SSH certificates.\nCertificates contain a public key, identity information and are signed with a standard SSH key.\n\nUnlike ssh keys, certificates can contain additional information:\n- Which user(s) may use the certificate\n- When the certificate is valid from\n- When the certificate expires\n- Permissions\n\nOther benefits of certificates:\n-  Unlike keys certificates don't need to be distributed to every machine - the sshd just needs to trust the key that signed the certificate.\n- This also works for host keys - machines can get new (signed) host certs which clients can authenticate. No more blindly typing \"yes\".\n- Certificates can be revoked.\n\nSee also the `CERTIFICATES` [section](http://man.openbsd.org/OpenBSD-current/man1/ssh-keygen.1#CERTIFICATES) of `ssh-keygen(1)`\n\n## How it works\nThe user wishes to ssh to a production machine.\n\nThey run a command which opens the CA site (e.g. https://sshca.exampleorg.com) in a browser and they login.\n\nThe CA displays a token which the user copies.\n\nThe user provides the token to the client. The client generates a new ssh key-pair.\n\nThe client sends the ssh public key to the CA along with the token.\n\nThe CA verifies the token and signs the public key with the signing key and returns the signed certificate.\n\nThe client receives the certificate and loads it and the private key into the ssh agent.\n\nThe 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.\n\n# Installing\nStable versions can be obtained from [the release page](https://github.com/cashier-go/cashier/releases).\n\nNote that installing using standard Go tools is possible, but the master branch should be considered unstable.\n\nThe server requires a configuration file ([sample config](example-server.conf)).\n\nSee [the configuration section](#configuration) for more detail.\n\n## Docker\nA [docker image is available](https://hub.docker.com/r/cashier-go/cashier). Example usage:\n```\ndocker run -it --rm -p 10000:10000 --name cashier -v ${PWD}:/cashier cashier-go/cashier\n```\n\n# Requirements\nGo 1.23 or later\n\n## Server\n\n## Client\n- OpenSSH 5.6 or newer.\n- A working SSH agent (note that the GPG agent does not handle certificates)\n\nNote: Cashier has only been tested on macOS and Linux.\n\n# Configuration\nConfiguration is divided into different sections: `server`, `auth`, `ssh`, and `aws`.\n\n## A note on files:\nFor 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:\n\n- A relative or absolute filesystem path e.g. `/data/ssh_signing_key`, `tls/server.key`.\n- An AWS S3 bucket + object path starting with `/s3/` e.g. `/s3/my-bucket/ssh_signing_key`. You should add an [aws](#aws) config as needed.\n- A Google GCS bucket + object path starting with `/gcs/` e.g. `/gcs/my-bucket/ssh_signing_key`.\n- A [Vault](https://www.vaultproject.io) path + key starting with `/vault/` e.g. `/vault/secret/cashier/ssh_signing_key`. You should add a [vault](#vault) config as needed.\n\nException to this: the `http_logfile` option **ONLY** writes to local files.\n\n## server\n- `use_tls` : boolean. If this is set then either `tls_key` and `tls_cert` are required, or `letsencrypt_servername` is required.\n- `tls_key` : string. Path to the TLS key. See the [note](#a-note-on-files) on files above.\n- `tls_cert` : string. Path to the TLS cert. See the [note](#a-note-on-files) on files above.\n- `letsencrypt_servername`: string. If set will request a certificate from LetsEncrypt. This should match the expected FQDN of the server.\n- `letsencrypt_cachedir`: string. Directory to cache the LetsEncrypt certificate. See the [note](#a-note-on-files) on files above.\n- `address` : string. IP address to listen on. If unset the server listens on all addresses.\n- `port` : int. Port to listen on.\n- `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](https://github.com/golang/go/issues/1435).\n- `cookie_secret`: string. Authentication key for the session cookie. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/cookie_secret`.\n- `csrf_secret`: string. Authentication key for CSRF protection. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/csrf_secret`.\n- `http_logfile`: string. Path to the HTTP request log. Logs are written in the [Common Log Format](https://en.wikipedia.org/wiki/Common_Log_Format). The only valid destination for logs is a local file path.\n- `require_reason`: bool. Require the client to provide a reason when requesting a certificate. Defaults to `false`.\n- `database`: See below.\n\n### database\n\nThe database is used to record issued certificates for audit and revocation purposes.\n\n- `type` : string. One of `mysql`, `sqlite` or `mem`.\n- `address` : string. (`mysql` only) Hostname and optional port of the database server.\n- `username` : string. Database username.\n- `password` : string. Database password. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/mysql_password`.\n- `filename` : string. (`sqlite` only). Path to sqlite database.\n- `dbname`: string (`mysql` only). Name of database to use.\n\nExamples:\n```\nserver {\n  database {\n    type = \"mysql\"\n    address = \"my-db-host.corp\"\n    username = \"user\"\n    password = \"passwd\"\n    dbname = \"cashier_production\"\n  }\n\n  database {\n    type = \"mem\"\n  }\n\n  database {\n    type = \"sqlite\"\n    filename = \"/data/cashier.db\"\n  }\n}\n```\n\nCashierd **will not** create the database for you - you need to create this. On startup cashierd will execute any schema changes.\nObviously you should setup a role user for running in prodution.\n\n## auth\n- `provider` : string. Name of the oauth provider. Valid providers are currently \"google\", \"github\" and \"gitlab\".\n- `oauth_client_id` : string. Oauth Client ID. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/oauth_client_id`.\n- `oauth_client_secret` : string. Oauth secret. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/oauth_client_secret`.\n- `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.\n- `provider_opts` : object. Additional options for the provider.\n- `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.\n\n### Provider-specific options\n\nOauth providers can support provider-specific options - e.g. to ensure organization membership.\nOptions are set in the `provider_opts` hash.\n\nExample:\n\n```\nauth {\n  provider = \"google\"\n  provider_opts {\n    domain = \"example.com\"\n  }\n}\n```\n\nSupported options:\n\n\n|  Provider |             Option | Notes                                                                                                                                                                                                |\n|----------:|-------------------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n|    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.                                      |\n|    Gitlab |           allusers | Allow all valid users to get signed keys. Only allowed if siteurl set.                                                                                                                               |\n|    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. |\n|    Gitlab |            siteurl | Optional. The url of the Gitlab site. Default: `https://gitlab.com/`                                                                                                                                 |\n|    Google |             domain | If this is unset then you must whitelist individual email addresses using `users_whitelist`.                                                                                                         |\n| Microsoft |             groups | Comma separated list of valid groups.                                                                                                                                                                |\n| Microsoft |             tenant | The domain name of the Office 365 account.                                                                                                                                                           |\n\n## ssh\n- `signing_key`: string. Path to the certificate signing ssh private key. Use `ssh-keygen` to create the key and store it somewhere safe. See also the [note](#a-note-on-files) on files above.\n- `additional_principals`: array of string. By default certificates will have one principal set - the username portion of the requester's email address. If `additional_principals` is set, these will be added to the certificate e.g. if your production machines use shared user accounts.\n- `max_age`: string. If set the server will not issue certificates with an expiration value longer than this, regardless of what the client requests. Must be a valid Go [`time.Duration`](https://golang.org/pkg/time/#ParseDuration) string.\n- `permissions`: array of string. Specify the actions the certificate can perform. See the [`-O` option to `ssh-keygen(1)`](http://man.openbsd.org/OpenBSD-current/man1/ssh-keygen.1) for a complete list. e.g. `permissions = [\"permit-pty\", \"permit-port-forwarding\", force-command=/bin/ls\", \"source-address=192.168.0.0/24\"]`\n\n## aws\nAWS configuration is only needed for accessing signing keys stored on S3, and isn't totally necessary even then.  \nThe S3 client can be configured using any of [the usual AWS-SDK means](https://github.com/aws/aws-sdk-go/wiki/configuring-sdk) - environment variables, IAM roles etc.  \nIt's strongly recommended that signing keys stored on S3 be locked down to specific IAM roles and encrypted using KMS.  \n\n- `region`: string. AWS region the bucket resides in, e.g. `us-east-1`.\n- `access_key`: string. AWS Access Key ID. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/aws_access_key`.\n- `secret_key`: string. AWS Secret Key. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/aws_secret_key`.\n\n## vault\nVault support is currently a work-in-progress.\n\n- `address`: string. URL to the vault server.\n- `token`: string. Auth token for the vault.\n\n# Usage\nCashier comes in two parts, a [cli](cmd/cashier) and a [server](cmd/cashierd).  \nThe server is configured using a HCL configuration file - [example](example-server.conf).\n\nFor the server you need the following:\n- A new ssh private key. Generate one using `ssh-keygen` - e.g. `ssh-keygen -f ssh_ca` - this is your CA signing key. At this time Cashier supports RSA, ECDSA and Ed25519 keys. *Important* This key should be kept safe - *ANY* ssh key signed with this key will be able to access your machines.\n- OAuth (Google or GitHub) credentials. You may also need to set the callback URL when creating these.\n\n## Using cashier client\nOnce the server is up and running you'll need to configure your client.  \nThe client is configured using either a [HCL](https://github.com/hashicorp/hcl) configuration file - [example](example-client.conf) - or command-line flags.\n\n- `--ca`          CA server (default \"http://localhost:10000\").\n- `--config`      Path to config file (default \"~/.cashier.conf\").\n- `--key_size`    Key size. Ignored for ed25519 keys (default 2048).\n- `--key_type`    Type of private key to generate - rsa, ecdsa or ed25519 (default \"rsa\").\n- `--key_file_prefix` Prefix for filename for SSH keys and cert (optional, no default). The public key is put in a file with `id_\u003cid\u003e.pub` appended to it; the public cert file in a file with `id_\u003cid\u003e-cert.pub` appended to it. The private key is stored in a file with `id_\u003cid\u003e` appended to it. \u003cid\u003e is taken from the id stored on the server.\n- `--validity`    Key validity (default 24h).\n\nRunning the `cashier` cli tool will open a browser window at the configured CA address.\nThe CA will redirect to the auth provider for authorisation, and redirect back to the CA where the access token will printed.  \nCopy the access token. In the terminal where you ran the `cashier` cli paste the token at the prompt.  \nThe client will then generate a new ssh key-pair and send the public part to the server (along with the access token).  \nOnce signed the client will install the key and signed certificate in your ssh agent. When the certificate expires it will be removed automatically from the agent.\n\nIf you set `key_file_prefix` then the public key and public cert will be written to the files that start with `key_file_prefix` and end with `.pub` and `-cert.pub` respectively.\n\nIn your `ssh_config` you can load these for a given host with the `IdentityFile` and `CertificateFile`. However prior to OpenSSH version 7.2p1 the latter option didn't exist.\nIn that case you could specify `~/.ssh/some-identity` as your `IdentityFile` and OpenSSH would look in `~/.ssh/some-identity.pub` and `~/.ssh/some-identity-cert.pub`.\n\nStarting with 7.2p1 the two options exist in the `ssh_config` and you'll need to use the full paths to them.\nNote that like these `ssh_config` options, the `key_file_prefix` supports tilde expansion.\n\n## Configuring SSH\nThe ssh client needs no special configuration, just a running `ssh-agent`.  \nThe ssh server needs to trust the public part of the CA signing key. Add something like the following to your `sshd_config`:  \n```\nTrustedUserCAKeys /etc/ssh/ca.pub\n```\nwhere `/etc/ssh/ca.pub` contains the public part of your signing key.\n\nIf you wish to use certificate revocation you need to set the `RevokedKeys` option in sshd_config - see the next section.\n\n## Revoking certificates\nWhen a certificate is signed a record is kept in the configured database. You can view issued certs at `http(s)://\u003cca url\u003e/admin/certs` and also revoke them.  \nThe revocation list is served at `http(s)://\u003cca url\u003e/revoked`. To use it your sshd_config must have `RevokedKeys` set:\n```\nRevokedKeys /etc/ssh/revoked_keys\n```\nSee the [`RevokedKeys` option in the sshd_config man page](http://man.openbsd.org/OpenBSD-current/man5/sshd_config) for more.  \nKeeping the revoked list up to date can be done with a cron job like:\n```\n*/10 * * * * * curl -s -o /etc/ssh/revoked_keys https://sshca.example.com/revoked\n```\n\nRemember that the `revoked_keys` file **must** exist and **must** be readable by the sshd or else all ssh authentication will fail.\n\n# Future Work\n\n- Host certificates - only user certificates are supported at present.\n\n# Contributing\nPull requests are welcome but forking Go repos can be a pain. [This is a good guide to forking and creating pull requests for Go projects](https://splice.com/blog/contributing-open-source-git-repositories-go/).  \nDependencies are vendored with [govendor](https://github.com/kardianos/govendor).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcashier-go%2Fcashier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcashier-go%2Fcashier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcashier-go%2Fcashier/lists"}