aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.drone.yml24
-rw-r--r--Dockerfile12
-rw-r--r--Makefile56
-rw-r--r--README.md134
-rw-r--r--example-server.conf23
5 files changed, 24 insertions, 225 deletions
diff --git a/.drone.yml b/.drone.yml
deleted file mode 100644
index fc79de0..0000000
--- a/.drone.yml
+++ /dev/null
@@ -1,24 +0,0 @@
----
-kind: pipeline
-name: build
-
-steps:
-- name: run tests
- image: golang
- commands:
- - sleep 5
- - make dep
- - make test
- environment:
- MYSQL_TEST: true
- MYSQL_TEST_HOST: mysql-server
- MYSQL_TEST_USER: root
-
-services:
-- name: mysql-server
- image: mysql
- environment:
- MYSQL_ALLOW_EMPTY_PASSWORD: yes
- MYSQL_DATABASE: certs
- ports:
- - 3306
diff --git a/Dockerfile b/Dockerfile
index b9ab104..e8f03ae 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,14 +1,12 @@
FROM golang:latest as build
-LABEL maintainer="nsheridan@gmail.com"
WORKDIR /build
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
-RUN CGO_ENABLED=1 GOOS=linux make install-cashierd
+RUN make cashierd
-FROM gcr.io/distroless/static
-LABEL maintainer="nsheridan@gmail.com"
-WORKDIR /cashier
-COPY --from=build /go/bin/cashierd /
-ENTRYPOINT ["/cashierd"]
+FROM alpine:latest
+WORKDIR /
+COPY --from=build /build/cashierd /
+CMD ["/cashierd"]
diff --git a/Makefile b/Makefile
index 278ed8d..1e398df 100644
--- a/Makefile
+++ b/Makefile
@@ -1,54 +1,20 @@
-CASHIER_CMD := ./cmd/cashier
-CASHIERD_CMD := ./cmd/cashierd
-SRC_FILES = $(shell find * -type f -name '*.go' -not -path 'vendor/*' -not -name 'a_*-packr.go')
+SOURCES=$(shell find . -type f -name '*.go')
VERSION_PKG := github.com/nsheridan/cashier/lib.Version
VERSION := $(shell git describe --tags --always --dirty)
+IMAGE_NAME=benburwell/cashier
-STATIC_LINKER_FLAGS ?= -linkmode external -extldflags -static -w
-GOOS ?= $(shell go env GOOS)
-GOARCH ?= $(shell go env GOARCH)
-CGO_ENABLED ?= $(shell go env CGO_ENABLED)
+all: cashier cashierd
-all: test build
+cashier: $(SOURCES)
+ go build -o $@ -ldflags="-X $(VERSION_PKG)=$(VERSION)" ./cmd/$@
-test:
- go test -coverprofile=coverage.txt -covermode=count ./...
- go install -race $(CASHIER_CMD) $(CASHIERD_CMD)
+cashierd: $(SOURCES)
+ go build -o $@ -ldflags="-X $(VERSION_PKG)=$(VERSION)" ./cmd/$@
-lint: dep
- go vet ./...
- go list ./... |xargs -L1 golint -set_exit_status
- gofmt -s -d -l -e $(SRC_FILES)
- $(MAKE) generate
- @[ -z "`git status --porcelain`" ] || (echo "unexpected files: `git status --porcelain`" && exit 1)
-
-build: cashier cashierd
-install: install-cashierd install-cashier
-cashier: cashier-bin
-cashierd: cashierd-bin
-
-generate:
- go generate ./...
-
-%-bin:
- CGO_ENABLED=$(CGO_ENABLED) GOARCH=$(GOARCH) GOOS=$(GOOS) go build -ldflags="-X $(VERSION_PKG)=$(VERSION) $(STATIC_LINKER_FLAGS)" ./cmd/$*
-install-%: generate
- CGO_ENABLED=$(CGO_ENABLED) GOARCH=$(GOARCH) GOOS=$(GOOS) go install -ldflags="-X $(VERSION_PKG)=$(VERSION) $(STATIC_LINKER_FLAGS)" ./cmd/$*
-
-docker-image:
- docker build -f Dockerfile .
+.PHONY: docker
+docker:
+ docker build -t "$(IMAGE_NAME)" .
+.PHONY: clean
clean:
rm -f cashier cashierd
-
-# usage: make migration name=whatever
-migration:
- go run ./generate/migration/migration.go $(name)
-
-dep:
- go get -u golang.org/x/lint/golint
-
-version:
- @echo $(VERSION)
-
-.PHONY: all build dep generate test cashier cashierd clean migration
diff --git a/README.md b/README.md
index 8387e5b..76953cd 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,5 @@
# Cashier
-[![Build Status](https://travis-ci.org/nsheridan/cashier.svg?branch=master)](https://travis-ci.org/nsheridan/cashier)
-
- [Cashier](#cashier)
- [How it works](#how-it-works)
- [Installing](#installing)
@@ -10,17 +8,9 @@
- [Server](#server)
- [Client](#client)
- [Configuration](#configuration)
- - [server](#server-1)
- - [database](#database)
- - [auth](#auth)
- - [Provider-specific options](#provider-specific-options)
- - [ssh](#ssh)
- - [aws](#aws)
- - [vault](#vault)
- [Usage](#usage)
- [Using cashier client](#using-cashier-client)
- [Configuring SSH](#configuring-ssh)
- - [Revoking certificates](#revoking-certificates)
- [Future Work](#future-work)
- [Contributing](#contributing)
@@ -88,103 +78,20 @@ 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](#aws) config as needed.
-- A Google GCS bucket + object path starting with `/gcs/` e.g. `/gcs/my-bucket/ssh_signing_key`.
-- 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.
-
-Exception to this: the `http_logfile` option **ONLY** writes to local files.
-
## server
-- `use_tls` : boolean. If this is set then either `tls_key` and `tls_cert` are required, or `letsencrypt_servername` is required.
-- `tls_key` : string. Path to the TLS key. See the [note](#a-note-on-files) on files above.
-- `tls_cert` : string. Path to the TLS cert. See the [note](#a-note-on-files) 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](#a-note-on-files) 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](https://github.com/golang/go/issues/1435).
- `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`.
- `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`.
- `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.
-- `require_reason`: bool. Require the client to provide a reason when requesting a certificate. Defaults to `false`.
-- `database`: See below.
-
-### database
-
-The database is used to record issued certificates for audit and revocation purposes.
-
-- `type` : string. One of `mysql`, `sqlite` or `mem`.
-- `address` : string. (`mysql` only) 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](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/mysql_password`.
-- `filename` : string. (`sqlite` only). Path to sqlite database.
-- `dbname`: string (`mysql` only). 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](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/oauth_client_id`.
-- `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`.
+## github
+- `oauth_client_id` : string. Oauth Client ID.
+- `oauth_client_secret` : string. Oauth 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 | group | If `allusers` and this are unset then you must whitelist individual users using `users_whitelist`. Otherwise the user must be a member of this group. |
-| 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. |
+- `users_whitelist` : array of strings. Optional list of whitelisted GitHub usernames.
+- `orgs_whitelist` : array of strings. Optional list of whitelisted GitHub orgs.
## ssh
- `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.
@@ -192,21 +99,6 @@ Supported options:
- `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.
- `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"]`
-## aws
-AWS configuration is only needed for accessing signing keys stored on S3, and isn't totally necessary even then.
-The 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.
-It's strongly recommended that signing keys stored on S3 be locked down to specific IAM roles and encrypted using KMS.
-
-- `region`: string. AWS region the bucket resides in, e.g. `us-east-1`.
-- `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`.
-- `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`.
-
-## vault
-Vault support is currently a work-in-progress.
-
-- `address`: string. URL to the vault server.
-- `token`: string. Auth token for the vault.
-
# Usage
Cashier comes in two parts, a [cli](cmd/cashier) and a [server](cmd/cashierd).
The server is configured using a HCL configuration file - [example](example-server.conf).
@@ -248,22 +140,6 @@ TrustedUserCAKeys /etc/ssh/ca.pub
```
where `/etc/ssh/ca.pub` contains the public part of your signing key.
-If you wish to use certificate revocation you need to set the `RevokedKeys` option in sshd_config - see the next section.
-
-## Revoking certificates
-When a certificate is signed a record is kept in the configured database. You can view issued certs at `http(s)://<ca url>/admin/certs` and also revoke them.
-The revocation list is served at `http(s)://<ca url>/revoked`. To use it your sshd_config must have `RevokedKeys` set:
-```
-RevokedKeys /etc/ssh/revoked_keys
-```
-See the [`RevokedKeys` option in the sshd_config man page](http://man.openbsd.org/OpenBSD-current/man5/sshd_config) for more.
-Keeping the revoked list up to date can be done with a cron job like:
-```
-*/10 * * * * * curl -s -o /etc/ssh/revoked_keys https://sshca.example.com/revoked
-```
-
-Remember that the `revoked_keys` file **must** exist and **must** be readable by the sshd or else all ssh authentication will fail.
-
# Future Work
- Host certificates - only user certificates are supported at present.
diff --git a/example-server.conf b/example-server.conf
index 795acc5..52d534d 100644
--- a/example-server.conf
+++ b/example-server.conf
@@ -10,15 +10,12 @@ server {
}
# Oauth2 configuration
-auth {
- provider = "google" # Oauth provider to use
+github {
oauth_client_id = "nnnnnnnnnnnnnnnn.apps.googleusercontent.com" # Oauth client ID
oauth_client_secret = "yyyyyyyyyyyyyyyyyyyyyy" # Oauth client secret
oauth_callback_url = "https://sshca.example.com/auth/callback" # Oauth callback url
- provider_opts {
- domain = "example.com" # Oauth-provider specific options
- }
- users_whitelist = ["marco@gmail.com", "niall@gmail.com", "patrick@gmail.com"] # Optional
+ users_whitelist = ["marco@gmail.com", "niall@gmail.com", "patrick@gmail.com"]
+ orgs_whitelist = ["org1", "org2"]
}
# Configuration for the certificate signer.
@@ -28,17 +25,3 @@ ssh {
max_age = "720h" # Maximum lifetime of a ssh certificate
permissions = ["permit-pty", "permit-X11-forwarding", "permit-agent-forwarding", "permit-port-forwarding", "permit-user-rc", "force-command=/bin/ls"] # Permissions associated with a certificate
}
-
-# Optional AWS config. if an aws config is present, then files (e.g. signing key or tls cert) can be read from S3 using the syntax `/s3/bucket/path/to/signing.key`.
-# These can also be set configured using the standard aws-sdk environment variables, IAM roles etc. https://github.com/aws/aws-sdk-go/wiki/configuring-sdk
-aws {
- region = "eu-west-1"
- access_key = "abcdef"
- secret_key = "xyz123"
-}
-
-# Optional Vault config. If a vault config is present then files (e.g. signing key or tls cert) can be read from a vault server using the syntax `/vault/secret/service/key_name`.
-vault {
- address = "https://127.0.0.1:8200"
- token = "83f01274-c6f0-4dae-aab9-13a6fc62772e"
-}