Merge branch 'master' into ssh-ca
This commit is contained in:
commit
10e7b81b9f
35 changed files with 632 additions and 387 deletions
28
.github/ISSUE_TEMPLATE/autocert_bug.md
vendored
28
.github/ISSUE_TEMPLATE/autocert_bug.md
vendored
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
name: Autocert Bug
|
||||
about: Report a bug you found in autocert
|
||||
labels: area/autocert bug
|
||||
---
|
||||
|
||||
### Subject of the issue
|
||||
Describe your issue here
|
||||
|
||||
### Environment
|
||||
* Kubernetes version:
|
||||
* Cloud provider or hardware configuration:
|
||||
* OS (e.g., from /etc/os-release):
|
||||
* Kernel (e.g., `uname -a`):
|
||||
* Install tools:
|
||||
* Other:
|
||||
|
||||
### Steps to reproduce
|
||||
Tell us how to reproduce this issue
|
||||
|
||||
### Expected behaviour
|
||||
Tell us what should happen
|
||||
|
||||
### Actual behaviour
|
||||
Tell us what happens instead
|
||||
|
||||
### Additional context
|
||||
Add any other context about the problem here
|
11
.github/ISSUE_TEMPLATE/autocert_enhancement.md
vendored
11
.github/ISSUE_TEMPLATE/autocert_enhancement.md
vendored
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
name: Autocert Enhancement
|
||||
about: Suggest an enhancement to autocert
|
||||
labels: area/autocert enhancement
|
||||
---
|
||||
|
||||
### What would you like to be added
|
||||
|
||||
|
||||
### Why this is needed
|
||||
|
11
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
11
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
name: Certificates Enhancement
|
||||
about: Suggest an enhancement to step certificates
|
||||
labels: area/cert-management enhancement
|
||||
---
|
||||
|
||||
### What would you like to be added
|
||||
|
||||
|
||||
### Why this is needed
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -18,3 +18,8 @@
|
|||
coverage.txt
|
||||
vendor
|
||||
output
|
||||
|
||||
# Ignore modules until switch from gopkg
|
||||
go.mod
|
||||
go.sum
|
||||
|
||||
|
|
68
.golangci.yml
Normal file
68
.golangci.yml
Normal file
|
@ -0,0 +1,68 @@
|
|||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
settings:
|
||||
printf:
|
||||
funcs:
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
|
||||
golint:
|
||||
min-confidence: 0
|
||||
gocyclo:
|
||||
min-complexity: 10
|
||||
maligned:
|
||||
suggest-new: true
|
||||
dupl:
|
||||
threshold: 100
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 2
|
||||
depguard:
|
||||
list-type: blacklist
|
||||
packages:
|
||||
# logging is allowed only by logutils.Log, logrus
|
||||
# is allowed to use only in logutils package
|
||||
- github.com/sirupsen/logrus
|
||||
misspell:
|
||||
locale: US
|
||||
lll:
|
||||
line-length: 140
|
||||
goimports:
|
||||
local-prefixes: github.com/golangci/golangci-lint
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- performance
|
||||
- style
|
||||
- experimental
|
||||
disabled-checks:
|
||||
- wrapperFunc
|
||||
- dupImport # https://github.com/go-critic/go-critic/issues/845
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- gofmt
|
||||
- golint
|
||||
- vet
|
||||
- misspell
|
||||
- ineffassign
|
||||
- deadcode
|
||||
|
||||
run:
|
||||
skip-dirs:
|
||||
- pkg
|
||||
|
||||
issues:
|
||||
exclude:
|
||||
- can't lint
|
||||
- declaration of "err" shadows declaration at line
|
||||
- should have a package comment, unless it's in another file for this package
|
||||
- error strings should not be capitalized or end with punctuation or a newline
|
||||
# golangci.com configuration
|
||||
# https://github.com/golangci/golangci/wiki/Configuration
|
||||
service:
|
||||
golangci-lint-version: 1.17.x # use the fixed version to not introduce new linters unexpectedly
|
||||
prepare:
|
||||
- echo "here I can run custom commands, but no preparation needed for this repo"
|
114
Gopkg.lock
generated
114
Gopkg.lock
generated
|
@ -9,21 +9,6 @@
|
|||
pruneopts = "UT"
|
||||
revision = "e2d15f34fcf99d5dbb871c820ec73f710fca9815"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:304cb78c285eaf02ab529ad02a257cad9b4845022915e6c82f87860ac53222d8"
|
||||
name = "github.com/alecthomas/gometalinter"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "bae2f1293d092fd8167939d5108d1b025eaef9de"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c198fdc381e898e8fb62b8eb62758195091c313ad18e52a3067366e1dda2fb3c"
|
||||
name = "github.com/alecthomas/units"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:454adc7f974228ff789428b6dc098638c57a64aa0718f0bd61e53d3cd39d7a75"
|
||||
|
@ -32,17 +17,6 @@
|
|||
pruneopts = "UT"
|
||||
revision = "2972be24d48e78746da79ba8e24e8b488c9880de"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:848ef40f818e59905140552cc49ff3dc1a15f955e4b56d1c5c2cc4b54dbadf0c"
|
||||
name = "github.com/client9/misspell"
|
||||
packages = [
|
||||
".",
|
||||
"cmd/misspell",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "b90dc15cfd220ecf8bbc9043ecb928cef381f011"
|
||||
version = "v0.3.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:21ac9938fb1098b3a7b0dd909fb30878d33231177fac11a2821114eb9c1088ff"
|
||||
name = "github.com/dgraph-io/badger"
|
||||
|
@ -82,17 +56,6 @@
|
|||
revision = "72cd26f257d44c1114970e19afddcd812016007e"
|
||||
version = "v1.4.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "travis-1.9"
|
||||
digest = "1:e8f5d9c09a7209c740e769713376abda388c41b777ba8e9ed52767e21acf379f"
|
||||
name = "github.com/golang/lint"
|
||||
packages = [
|
||||
".",
|
||||
"golint",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "883fe33ffc4344bad1ecd881f61afd5ec5d80e0a"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d"
|
||||
name = "github.com/golang/protobuf"
|
||||
|
@ -101,22 +64,6 @@
|
|||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:750e747d0aad97b79f4a4e00034bae415c2ea793fd9e61438d966ee9c79579bf"
|
||||
name = "github.com/google/shlex"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "6f45313302b9c56850fc17f99e40caebce98c716"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:824d147914b40e56e9e1eebd602bc6bb9761989d52fd8e4a498428467980eb17"
|
||||
name = "github.com/gordonklaus/ineffassign"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "1003c8bd00dc2869cb5ca5282e6ce33834fed514"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e51f40f0c19b39c1825eadd07d5c0a98a2ad5942b166d9fc4f54750ce9a04810"
|
||||
|
@ -145,7 +92,7 @@
|
|||
revision = "2d01aacdc34a083dca635ba869909f5fc0cd4f41"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2a2a76072bd413b3484a0b5bb2fbb078b0b7dd8950e9276c900e14dce2354679"
|
||||
digest = "1:2d2bc0f23cca6b59cec3fbece9abc102bdb19f548dd58d7667e57699074a2c76"
|
||||
name = "github.com/manifoldco/promptui"
|
||||
packages = [
|
||||
".",
|
||||
|
@ -153,8 +100,8 @@
|
|||
"screenbuf",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "20f2a94120aa14a334121a6de66616a7fa89a5cd"
|
||||
version = "v0.3.2"
|
||||
revision = "157c96fb638a14d268b305cf2012582431fcc410"
|
||||
version = "v0.3.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
|
||||
|
@ -210,27 +157,6 @@
|
|||
revision = "f5bce3387232559bcbe6a5f8227c4bf508dac1ba"
|
||||
version = "v1.11.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:07140002dbf37da92090f731b46fa47be4820b82fe5c14a035203b0e813d0ec2"
|
||||
name = "github.com/nicksnyder/go-i18n"
|
||||
packages = [
|
||||
"i18n",
|
||||
"i18n/bundle",
|
||||
"i18n/language",
|
||||
"i18n/translation",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "0dc1626d56435e9d605a29875701721c54bc9bbd"
|
||||
version = "v1.10.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
|
||||
name = "github.com/pkg/errors"
|
||||
|
@ -281,7 +207,7 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8eb842c27bca9dae16d77baeba7cf612135033da381faf833bb8c11c29a751c7"
|
||||
digest = "1:4998154cc4ffb0ab954b7ecaad6899dcdea8f8ec79c94a071994d1a3b332d493"
|
||||
name = "github.com/smallstep/cli"
|
||||
packages = [
|
||||
"command",
|
||||
|
@ -302,7 +228,7 @@
|
|||
"utils",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "98635d188cade54451e3997b530716297ce7fc00"
|
||||
revision = "3254c70079f798ee5f269c98fe27abd9a11c4aad"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -318,14 +244,6 @@
|
|||
pruneopts = "UT"
|
||||
revision = "a0934e12468769d8cbede3ed316c47a4b88de4ca"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ba52e5a5fb800ce55108b7a5f181bb809aab71c16736051312b0aa969f82ad39"
|
||||
name = "github.com/tsenart/deadcode"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "210d2dc333e90c7e3eedf4f2242507a8e83ed4ab"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:6743b69de0d73e91004e4e201cf4965b59a0fa5caf6f0ffbe0cb9ee8807738a7"
|
||||
|
@ -441,13 +359,6 @@
|
|||
revision = "54a98f90d1c46b7731eb8fb305d2a321c30ef610"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:39efb07a0d773dc09785b237ada4e10b5f28646eb6505d97bc18f8d2ff439362"
|
||||
name = "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9593bab40e981b1f90b7e07faeab0d09b75fe338880d08880f986a9d3283c53f"
|
||||
name = "gopkg.in/square/go-jose.v2"
|
||||
|
@ -461,23 +372,11 @@
|
|||
revision = "730df5f748271903322feb182be83b43ebbbe27d"
|
||||
version = "v2.3.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/alecthomas/gometalinter",
|
||||
"github.com/client9/misspell/cmd/misspell",
|
||||
"github.com/go-chi/chi",
|
||||
"github.com/golang/lint/golint",
|
||||
"github.com/gordonklaus/ineffassign",
|
||||
"github.com/newrelic/go-agent",
|
||||
"github.com/pkg/errors",
|
||||
"github.com/rs/xid",
|
||||
|
@ -491,13 +390,14 @@
|
|||
"github.com/smallstep/cli/crypto/x509util",
|
||||
"github.com/smallstep/cli/errs",
|
||||
"github.com/smallstep/cli/jose",
|
||||
"github.com/smallstep/cli/pkg/x509",
|
||||
"github.com/smallstep/cli/token",
|
||||
"github.com/smallstep/cli/token/provision",
|
||||
"github.com/smallstep/cli/usage",
|
||||
"github.com/smallstep/nosql",
|
||||
"github.com/smallstep/nosql/database",
|
||||
"github.com/tsenart/deadcode",
|
||||
"github.com/urfave/cli",
|
||||
"golang.org/x/crypto/ed25519",
|
||||
"golang.org/x/crypto/ocsp",
|
||||
"golang.org/x/crypto/ssh",
|
||||
"golang.org/x/net/http2",
|
||||
|
|
13
Gopkg.toml
13
Gopkg.toml
|
@ -23,19 +23,6 @@
|
|||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
required = [
|
||||
"github.com/alecthomas/gometalinter",
|
||||
"github.com/golang/lint/golint",
|
||||
"github.com/client9/misspell/cmd/misspell",
|
||||
"github.com/gordonklaus/ineffassign",
|
||||
"github.com/tsenart/deadcode",
|
||||
]
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/alecthomas/gometalinter"
|
||||
revision = "bae2f1293d092fd8167939d5108d1b025eaef9de"
|
||||
|
||||
[[override]]
|
||||
name = "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||
revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306"
|
||||
|
|
28
Makefile
28
Makefile
|
@ -22,25 +22,18 @@ all: build test lint
|
|||
bootstra%:
|
||||
$Q which dep || go get github.com/golang/dep/cmd/dep
|
||||
$Q dep ensure
|
||||
$Q GO111MODULE=on go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.17.1
|
||||
|
||||
|
||||
vendor: Gopkg.lock
|
||||
$Q dep ensure
|
||||
|
||||
BOOTSTRAP=\
|
||||
github.com/golang/lint/golint \
|
||||
github.com/client9/misspell/cmd/misspell \
|
||||
github.com/gordonklaus/ineffassign \
|
||||
github.com/tsenart/deadcode \
|
||||
github.com/alecthomas/gometalinter
|
||||
|
||||
define VENDOR_BIN_TMPL
|
||||
vendor/bin/$(notdir $(1)): vendor
|
||||
$Q go build -o $$@ ./vendor/$(1)
|
||||
VENDOR_BINS += vendor/bin/$(notdir $(1))
|
||||
endef
|
||||
|
||||
$(foreach pkg,$(BOOTSTRAP),$(eval $(call VENDOR_BIN_TMPL,$(pkg))))
|
||||
|
||||
.PHONY: bootstra% vendor
|
||||
|
||||
#################################################
|
||||
|
@ -126,24 +119,11 @@ integration: bin/$(BINNAME)
|
|||
# Linting
|
||||
#########################################
|
||||
|
||||
LINTERS=\
|
||||
gofmt \
|
||||
golint \
|
||||
vet \
|
||||
misspell \
|
||||
ineffassign \
|
||||
deadcode
|
||||
|
||||
$(patsubst %,%-bin,$(filter-out gofmt vet,$(LINTERS))): %-bin: vendor/bin/%
|
||||
gofmt-bin vet-bin:
|
||||
|
||||
$(LINTERS): %: vendor/bin/gometalinter %-bin vendor
|
||||
$Q PATH=`pwd`/vendor/bin:$$PATH gometalinter --tests --disable-all --vendor \
|
||||
--deadline=5m -s data -s pkg --enable $@ ./...
|
||||
fmt:
|
||||
$Q gofmt -l -w $(SRC)
|
||||
|
||||
lint: $(LINTERS)
|
||||
lint:
|
||||
$Q LOG_LEVEL=error golangci-lint run
|
||||
|
||||
.PHONY: $(LINTERS) lint fmt
|
||||
|
||||
|
|
323
README.md
323
README.md
|
@ -2,6 +2,10 @@
|
|||
|
||||
An online certificate authority and related tools for secure automated certificate management, so you can use TLS everywhere.
|
||||
|
||||
This repository is for `step-ca`, a certificate authority that exposes an API for automated certificate management. It also contains a [golang SDK](https://github.com/smallstep/certificates/tree/master/examples#basic-client-usage) for interacting with `step-ca` programatically. However, you'll probably want to use the [`step` command-line tool](https://github.com/smallstep/cli) to operate `step-ca` and get certificates, instead of using this low-level SDK directly.
|
||||
|
||||
**Questions? Find us [on gitter](https://gitter.im/smallstep/community).**
|
||||
|
||||
[Website](https://smallstep.com) |
|
||||
[Documentation](#documentation) |
|
||||
[Installation Guide](#installation-guide) |
|
||||
|
@ -21,6 +25,38 @@ An online certificate authority and related tools for secure automated certifica
|
|||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
It's super easy to get started and to operate `step-ca` thanks to [streamlined initialization](https://github.com/smallstep/certificates#lets-get-started) and [safe, sane defaults](https://github.com/smallstep/certificates/blob/master/docs/defaults.md). **Get started in 15 minutes.**
|
||||
|
||||
### A private certificate authority you run yourself
|
||||
|
||||
- Issue client and server certificates to VMs, containers, devices, and people using internal hostnames and emails
|
||||
- [RFC5280](https://tools.ietf.org/html/rfc5280) and [CA/Browser Forum](https://cabforum.org/baseline-requirements-documents/) compliant certificates that work **for TLS and HTTPS** (SSH coming soon!)
|
||||
- Choose key types (RSA, ECDSA, EdDSA) & lifetimes to suit your needs
|
||||
- [Short-lived certificates](https://smallstep.com/blog/passive-revocation.html) with **fully automated** enrollment, renewal, and revocation
|
||||
- Fast, stable, and capable of high availability deployment using [root federation](https://smallstep.com/blog/step-v0.8.3-federation-root-rotation.html) and/or multiple intermediaries
|
||||
- Operate as an online intermediate for an existing root CA
|
||||
- [Pluggable database backends](https://github.com/smallstep/certificates/blob/master/docs/database.md) for persistence
|
||||
- [Helm charts](https://hub.helm.sh/charts/smallstep/step-certificates), [autocert](https://github.com/smallstep/autocert), and [cert-manager integration](https://github.com/smallstep/step-issuer) for kubernetes
|
||||
|
||||
### Lots of (automatable) ways to get certificates
|
||||
|
||||
- [Single sign-on](https://smallstep.com/blog/easily-curl-services-secured-by-https-tls.html) using Okta, GSuite, Active Directory, or any other OAuth OIDC identity provider
|
||||
- Instance identity documents for VMs on AWS, GCP, and Azure
|
||||
- [Single-use short-lived tokens](https://smallstep.com/docs/design-doc.html#jwk-provisioner) issued by your CD tool — Puppet, Chef, Ansible, Terraform, etc.
|
||||
- Use an existing certificate from another CA (e.g., using a device certificate like [Twilio's Trust OnBoard](https://www.twilio.com/wireless/trust-onboard)) *coming soon*
|
||||
- ACMEv2 (RFC8555) support so you can **run your own private ACME server** *[coming soon](https://github.com/smallstep/certificates/tree/acme)*
|
||||
|
||||
### Easy certificate management and automation via [`step` CLI](https://github.com/smallstep/cli) [integration](https://smallstep.com/docs/cli/ca/)
|
||||
|
||||
- Generate key pairs where they're needed so private keys are never transmitted across the network
|
||||
- [Authenticate and obtain a certificate](https://smallstep.com/docs/cli/ca/certificate/) using any enrollment mechanism supported by `step-ca`
|
||||
- Securely [distribute root certificates](https://smallstep.com/docs/cli/ca/root/) and [bootstrap](https://smallstep.com/docs/cli/ca/bootstrap/) PKI relying parties
|
||||
- [Renew](https://smallstep.com/docs/cli/ca/renew/) and [revoke](https://smallstep.com/docs/cli/ca/revoke/) certificates issued by `step-ca`
|
||||
- [Install root certificates](https://smallstep.com/docs/cli/certificate/install/) so your CA is trusted by default (issue development certificates **that [work in browsers](https://smallstep.com/blog/step-v0-8-6-valid-HTTPS-certificates-for-dev-pre-prod.html)**)
|
||||
- [Inspect](https://smallstep.com/docs/cli/certificate/inspect/) and [lint](https://smallstep.com/docs/cli/certificate/lint/) certificates
|
||||
|
||||
## Motivation
|
||||
|
||||
Managing your own *public key infrastructure* (PKI) can be tedious and error
|
||||
|
@ -49,35 +85,22 @@ need.
|
|||
makes it much easier to implement good security practices early, and
|
||||
incrementally improve them as your system matures.
|
||||
|
||||
For more information and docs see [the Step
|
||||
For more information and [docs](https://smallstep.com/docs) see [the smallstep
|
||||
website](https://smallstep.com/certificates) and the [blog
|
||||
post](https://smallstep.com/blog/step-certificates.html) announcing Step
|
||||
Certificate Authority.
|
||||
|
||||
> ## 🆕 Autocert <a href="https://github.com/smallstep/autocert"><img width="50%" src="https://raw.githubusercontent.com/smallstep/autocert/master/autocert-logo.png"></a>
|
||||
>
|
||||
> If you're using Kubernetes, make sure you [check out
|
||||
> autocert](https://github.com/smallstep/autocert): a kubernetes add-on that builds on `step
|
||||
> certificates` to automatically inject TLS/HTTPS certificates into your containers.
|
||||
post](https://smallstep.com/blog/step-certificates.html) announcing this project.
|
||||
|
||||
## Installation Guide
|
||||
|
||||
These instructions will install an OS specific version of the `step-ca` binary on
|
||||
your local machine.
|
||||
|
||||
> NOTE: While `step` is not required to run the Step Certificate Authority (CA)
|
||||
> we strongly recommend installing both `step cli` and `step certificates`
|
||||
> because the Step CA is much easier to initialize, manage, and debug using
|
||||
> the `step cli` toolkit.
|
||||
While `step` is not required to run `step-ca`, it will make your life easier so you'll probably want to [install it](https://github.com/smallstep/cli#installation-guide) too.
|
||||
|
||||
### Mac OS
|
||||
|
||||
Install `step` via [Homebrew](https://brew.sh/). The
|
||||
[Homebrew Formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/step.rb)
|
||||
installs both `step cli` and `step certificates`.
|
||||
Install `step` and `step-ca` together via [Homebrew](https://brew.sh/):
|
||||
|
||||
<pre><code>
|
||||
<b>$ brew install step</b>
|
||||
<pre><code><b>$ brew install step</b>
|
||||
|
||||
# Test installation ...
|
||||
<b>$ step certificate inspect https://smallstep.com</b>
|
||||
|
@ -87,24 +110,24 @@ Certificate:
|
|||
Serial Number: 326381749415081530968054238478851085504954 (0x3bf265673332db2d0c70e48a163fb7d11ba)
|
||||
Signature Algorithm: SHA256-RSA
|
||||
Issuer: C=US,O=Let's Encrypt,CN=Let's Encrypt Authority X3
|
||||
...
|
||||
</code></pre>
|
||||
...</code></pre>
|
||||
|
||||
> Note: If you have installed `step` previously through the `smallstep/smallstep`
|
||||
> tap you will need to run the following commands before installing:
|
||||
```
|
||||
$ brew untap smallstep/smallstep
|
||||
$ brew uninstall step
|
||||
```
|
||||
>
|
||||
> ```
|
||||
> $ brew untap smallstep/smallstep
|
||||
> $ brew uninstall step
|
||||
> ```
|
||||
|
||||
### Linux
|
||||
|
||||
#### Debian
|
||||
|
||||
1. [Optional] Install `step cli`.
|
||||
1. [Optional] Install `step`.
|
||||
|
||||
Download the latest Debian package from
|
||||
[`step cli` releases](https://github.com/smallstep/cli/releases):
|
||||
[`step` releases](https://github.com/smallstep/cli/releases):
|
||||
|
||||
```
|
||||
$ wget https://github.com/smallstep/cli/releases/download/X.Y.Z/step_X.Y.Z_amd64.deb
|
||||
|
@ -116,10 +139,9 @@ $ brew uninstall step
|
|||
$ sudo dpkg -i step_X.Y.Z_amd64.deb
|
||||
```
|
||||
|
||||
2. Install `step certificates`.
|
||||
2. Install `step-ca`.
|
||||
|
||||
Download the latest Debian package from
|
||||
[`step certificates` releases](https://github.com/smallstep/certificates/releases):
|
||||
Download the latest Debian package from [releases](https://github.com/smallstep/certificates/releases):
|
||||
|
||||
```
|
||||
$ wget https://github.com/smallstep/certificates/releases/download/X.Y.Z/step-certificates_X.Y.Z_amd64.deb
|
||||
|
@ -136,29 +158,41 @@ $ brew uninstall step
|
|||
We are using the [Arch User Repository](https://aur.archlinux.org) to distribute
|
||||
`step` binaries for Arch Linux.
|
||||
|
||||
* [Optional] The `step-cli` binary tarball can be found [here](https://aur.archlinux.org/packages/step-cli-bin/).
|
||||
* [Optional] The `step` binary tarball can be found [here](https://aur.archlinux.org/packages/step-cli-bin/).
|
||||
* The `step-ca` binary tarball can be found [here](https://aur.archlinux.org/packages/step-ca-bin/).
|
||||
|
||||
You can use [pacman](https://www.archlinux.org/pacman/) to install the packages.
|
||||
|
||||
### Kubernetes
|
||||
|
||||
We publish [helm charts](https://hub.helm.sh/charts/smallstep/step-certificates) for easy installation on kubernetes:
|
||||
|
||||
```
|
||||
helm install step-certificates
|
||||
```
|
||||
|
||||
> <a href="https://github.com/smallstep/autocert"><img width="25%" src="https://raw.githubusercontent.com/smallstep/autocert/master/autocert-logo.png"></a>
|
||||
>
|
||||
> If you're using Kubernetes, make sure you [check out
|
||||
> autocert](https://github.com/smallstep/autocert): a kubernetes add-on that builds on `step
|
||||
> certificates` to automatically inject TLS/HTTPS certificates into your containers.
|
||||
|
||||
### Test
|
||||
|
||||
<pre><code>
|
||||
<b>$ step version</b>
|
||||
Smallstep CLI/0.8.5 (darwin/amd64)
|
||||
Release Date: 2019-02-13 22:17 UTC
|
||||
<pre><code><b>$ step version</b>
|
||||
Smallstep CLI/0.10.0 (darwin/amd64)
|
||||
Release Date: 2019-04-30 19:01 UTC
|
||||
|
||||
<b>$ step-ca version</b>
|
||||
Smallstep CA/0.8.4 (darwin/amd64)
|
||||
Release Date: 2019-02-18 18:56 UTC
|
||||
</code></pre>
|
||||
Smallstep CA/0.10.0 (darwin/amd64)
|
||||
Release Date: 2019-04-30 19:02 UTC</code></pre>
|
||||
|
||||
## Quickstart
|
||||
|
||||
In the following guide we'll run a simple `hello` server that requires clients
|
||||
to connect over an authorized and encrypted channel (HTTP over TLS). The Step
|
||||
Certificate Authority (CA) will issue an identity dial tone to our server
|
||||
enabling it to authenticate and encrypt communication. Let's get started!
|
||||
to connect over an authorized and encrypted channel using HTTPS. `step-ca`
|
||||
will issue certificates to our server, allowing it to authenticate and encrypt
|
||||
communication. Let's get started!
|
||||
|
||||
### Prerequisites
|
||||
|
||||
|
@ -167,152 +201,123 @@ enabling it to authenticate and encrypt communication. Let's get started!
|
|||
|
||||
### Let's get started!
|
||||
|
||||
1. Initialize and run the Step CA.
|
||||
#### 1. Run `step ca init` to create your CA's keys & certificates and configure `step-ca`:
|
||||
|
||||
`step ca init` initializes the CA and accomplishes two tasks.
|
||||
<pre><code><b>$ step ca init</b>
|
||||
✔ What would you like to name your new PKI? (e.g. Smallstep): <b>Example Inc.</b>
|
||||
✔ What DNS names or IP addresses would you like to add to your new CA? (e.g. ca.smallstep.com[,1.1.1.1,etc.]): <b>localhost</b>
|
||||
✔ What address will your new CA listen at? (e.g. :443): <b>127.0.0.1:8080</b>
|
||||
✔ What would you like to name the first provisioner for your new CA? (e.g. you@smallstep.com): <b>bob@example.com</b>
|
||||
✔ What do you want your password to be? [leave empty and we'll generate one]: <b>abc123</b>
|
||||
|
||||
1. Generate a Public Key Infrastructure (PKI) with Root and Intermediate
|
||||
X.509 Certificates and private keys.
|
||||
Generating root certificate...
|
||||
all done!
|
||||
|
||||
The root X.509 Certificate is a fancy public key that will be
|
||||
distributed to clients enabling them to authenticate all certificates
|
||||
generated by your PKI. The root private key should be kept in a very
|
||||
private place - but as this is just a demo we won't worry about that
|
||||
right now ([more info on storing sensitive
|
||||
data](./docs/GETTING_STARTED.md#passwords)). The intermediate
|
||||
private key will be used to sign new certificates ([Why is it more
|
||||
secure to use intermediate CA
|
||||
certificates?](https://security.stackexchange.com/questions/128779/why-is-it-more-secure-to-use-intermediate-ca-certificates))
|
||||
and the intermediate certificate will be distributed along with newly
|
||||
minted leaf certificates. In our demo, the server will present the
|
||||
intermediate certificate along with it's *server* (leaf) certificate
|
||||
allowing our client to validate the full chain using the root.
|
||||
Generating intermediate certificate...
|
||||
all done!
|
||||
|
||||
2. Generate the configuration file required by the Step CA.
|
||||
✔ Root certificate: /Users/bob/src/github.com/smallstep/step/.step/certs/root_ca.crt
|
||||
✔ Root private key: /Users/bob/src/github.com/smallstep/step/.step/secrets/root_ca_key
|
||||
✔ Root fingerprint: 702a094e239c9eec6f0dcd0a5f65e595bf7ed6614012825c5fe3d1ae1b2fd6ee
|
||||
✔ Intermediate certificate: /Users/bob/src/github.com/smallstep/step/.step/certs/intermediate_ca.crt
|
||||
✔ Intermediate private key: /Users/bob/src/github.com/smallstep/step/.step/secrets/intermediate_ca_key
|
||||
✔ Default configuration: /Users/bob/src/github.com/smallstep/step/.step/config/defaults.json
|
||||
✔ Certificate Authority configuration: /Users/bob/src/github.com/smallstep/step/.step/config/ca.json
|
||||
|
||||
See the [Getting Started](./docs/GETTING_STARTED.md) guide for an in depth
|
||||
explanation of the Step CA configuration file.
|
||||
Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.</code></pre>
|
||||
|
||||
<pre><code>
|
||||
<b>$ step ca init</b>
|
||||
✔ What would you like to name your new PKI? (e.g. Smallstep): <b>Example Inc.</b>
|
||||
✔ What DNS names or IP addresses would you like to add to your new CA? (e.g. ca.smallstep.com[,1.1.1.1,etc.]): <b>localhost</b>
|
||||
✔ What address will your new CA listen at? (e.g. :443): <b>127.0.0.1:8080</b>
|
||||
✔ What would you like to name the first provisioner for your new CA? (e.g. you@smallstep.com): <b>bob@example.com</b>
|
||||
✔ What do you want your password to be? [leave empty and we'll generate one]: <b>abc123</b>
|
||||
This command will:
|
||||
|
||||
Generating root certificate...
|
||||
all done!
|
||||
- Generate [password protected](https://github.com/smallstep/certificates/blob/master/docs/GETTING_STARTED.md#passwords) private keys for your CA to sign certificates
|
||||
- Generate a root and [intermediate signing certificate](https://security.stackexchange.com/questions/128779/why-is-it-more-secure-to-use-intermediate-ca-certificates) for your CA
|
||||
- Create a JSON configuration file for `step-ca` (see [getting started](./docs/GETTING_STARTED.md) for details)
|
||||
|
||||
Generating intermediate certificate...
|
||||
all done!
|
||||
You can find these artifacts in `$STEPPATH` (or `~/.step` by default).
|
||||
|
||||
✔ Root certificate: /Users/bob/src/github.com/smallstep/step/.step/certs/root_ca.crt
|
||||
✔ Root private key: /Users/bob/src/github.com/smallstep/step/.step/secrets/root_ca_key
|
||||
✔ Root fingerprint: 702a094e239c9eec6f0dcd0a5f65e595bf7ed6614012825c5fe3d1ae1b2fd6ee
|
||||
✔ Intermediate certificate: /Users/bob/src/github.com/smallstep/step/.step/certs/intermediate_ca.crt
|
||||
✔ Intermediate private key: /Users/bob/src/github.com/smallstep/step/.step/secrets/intermediate_ca_key
|
||||
✔ Default configuration: /Users/bob/src/github.com/smallstep/step/.step/config/defaults.json
|
||||
✔ Certificate Authority configuration: /Users/bob/src/github.com/smallstep/step/.step/config/ca.json
|
||||
#### 2. Start `step-ca`:
|
||||
|
||||
Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.
|
||||
You'll be prompted for your password from the previous step, to decrypt the CA's private signing key:
|
||||
|
||||
<b>$ step-ca $(step path)/config/ca.json</b>
|
||||
Please enter the password to decrypt /Users/bob/src/github.com/smallstep/step/.step/secrets/intermediate_ca_key: <b>abc123</b>
|
||||
2019/02/18 13:28:58 Serving HTTPS on 127.0.0.1:8080 ...
|
||||
</code></pre>
|
||||
<pre><code><b>$ step-ca $(step path)/config/ca.json</b>
|
||||
Please enter the password to decrypt /Users/bob/src/github.com/smallstep/step/.step/secrets/intermediate_ca_key: <b>abc123</b>
|
||||
2019/02/18 13:28:58 Serving HTTPS on 127.0.0.1:8080 ...</code></pre>
|
||||
|
||||
Now we've got an 'up and running' online CA!
|
||||
#### 3. Copy our `hello world` golang server.
|
||||
|
||||
2. Copy our `hello world` golang server.
|
||||
```
|
||||
$ cat > srv.go <<EOF
|
||||
package main
|
||||
|
||||
```
|
||||
$ cat > srv.go <<EOF
|
||||
package main
|
||||
import (
|
||||
"net/http"
|
||||
"log"
|
||||
)
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"log"
|
||||
)
|
||||
func HiHandler(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte("Hello, world!\n"))
|
||||
}
|
||||
|
||||
func HiHandler(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte("Hello, world!\n"))
|
||||
func main() {
|
||||
http.HandleFunc("/hi", HiHandler)
|
||||
err := http.ListenAndServeTLS(":8443", "srv.crt", "srv.key", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/hi", HiHandler)
|
||||
err := http.ListenAndServeTLS(":8443", "srv.crt", "srv.key", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
#### 4. Get an identity for your server from the Step CA.
|
||||
|
||||
3. Get an identity for your server from the Step CA.
|
||||
<pre><code><b>$ step ca certificate localhost srv.crt srv.key</b>
|
||||
✔ Key ID: rQxROEr7Kx9TNjSQBTETtsu3GKmuW9zm02dMXZ8GUEk (bob@example.com)
|
||||
✔ Please enter the password to decrypt the provisioner key: abc123
|
||||
✔ CA: https://localhost:8080/1.0/sign
|
||||
✔ Certificate: srv.crt
|
||||
✔ Private Key: srv.key
|
||||
|
||||
<pre><code>
|
||||
<b>$ step ca certificate localhost srv.crt srv.key</b>
|
||||
✔ Key ID: rQxROEr7Kx9TNjSQBTETtsu3GKmuW9zm02dMXZ8GUEk (bob@example.com)
|
||||
✔ Please enter the password to decrypt the provisioner key: abc123
|
||||
✔ CA: https://localhost:8080/1.0/sign
|
||||
✔ Certificate: srv.crt
|
||||
✔ Private Key: srv.key
|
||||
<b>$ step certificate inspect --bundle srv.crt</b>
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 140439335711218707689123407681832384336 (0x69a7a1d7f6f22f68059d2d9088307750)
|
||||
Signature Algorithm: ECDSA-SHA256
|
||||
Issuer: CN=Example Inc. Intermediate CA
|
||||
Validity
|
||||
Not Before: Feb 18 21:32:35 2019 UTC
|
||||
Not After : Feb 19 21:32:35 2019 UTC
|
||||
Subject: CN=localhost
|
||||
...
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 207035091234452090159026162349261226844 (0x9bc18217bd560cf07db23178ed90835c)
|
||||
Signature Algorithm: ECDSA-SHA256
|
||||
Issuer: CN=Example Inc. Root CA
|
||||
Validity
|
||||
Not Before: Feb 18 21:27:21 2019 UTC
|
||||
Not After : Feb 15 21:27:21 2029 UTC
|
||||
Subject: CN=Example Inc. Intermediate CA
|
||||
...</code></pre>
|
||||
|
||||
<b>$ step certificate inspect --bundle srv.crt</b>
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 140439335711218707689123407681832384336 (0x69a7a1d7f6f22f68059d2d9088307750)
|
||||
Signature Algorithm: ECDSA-SHA256
|
||||
Issuer: CN=Example Inc. Intermediate CA
|
||||
Validity
|
||||
Not Before: Feb 18 21:32:35 2019 UTC
|
||||
Not After : Feb 19 21:32:35 2019 UTC
|
||||
Subject: CN=localhost
|
||||
...
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 207035091234452090159026162349261226844 (0x9bc18217bd560cf07db23178ed90835c)
|
||||
Signature Algorithm: ECDSA-SHA256
|
||||
Issuer: CN=Example Inc. Root CA
|
||||
Validity
|
||||
Not Before: Feb 18 21:27:21 2019 UTC
|
||||
Not After : Feb 15 21:27:21 2029 UTC
|
||||
Subject: CN=Example Inc. Intermediate CA
|
||||
...
|
||||
</code></pre>
|
||||
Note that `step` and `step-ca` handle details like [certificate bundling](https://smallstep.com/blog/everything-pki.html#intermediates-chains-and-bundling) for you.
|
||||
|
||||
Notice that when you inspect `srv.crt` there are actually two certificates
|
||||
present. The first is your **server** (leaf) certificate and the second is
|
||||
the intermediate certificate. When an intermediate CA is used to sign
|
||||
**leaf** certificates it is not enough for the server to only show it's
|
||||
**leaf** certificate because the client (which only has access to the root
|
||||
certificate) will not be able to validate the full chain.
|
||||
#### 5. Run the simple server.
|
||||
|
||||
4. Run the simple server.
|
||||
<pre><code><b>$ go run srv.go &</b></code></pre>
|
||||
|
||||
<pre><code>
|
||||
<b>$ go run srv.go &</b>
|
||||
</code></pre>
|
||||
#### 6. Get the root certificate from the Step CA.
|
||||
|
||||
5. Get the root certificate from the Step CA.
|
||||
In a new Terminal window:
|
||||
|
||||
In a new Terminal window:
|
||||
<pre><code><b>$ step ca root root.crt</b>
|
||||
The root certificate has been saved in root.crt.</code></pre>
|
||||
|
||||
<pre><code>
|
||||
<b>$ step ca root root.crt</b>
|
||||
The root certificate has been saved in root.crt.
|
||||
</code></pre>
|
||||
#### 7. Make an authenticated, encrypted curl request to your server using HTTP over TLS.
|
||||
|
||||
6. Make an authenticated, encrypted curl request to your server using HTTP over TLS.
|
||||
|
||||
<pre><code>
|
||||
<b>$ curl --cacert root.crt https://localhost:8443/hi</b>
|
||||
Hello, world!
|
||||
</code></pre>
|
||||
<pre><code><b>$ curl --cacert root.crt https://localhost:8443/hi</b>
|
||||
Hello, world!</code></pre>
|
||||
|
||||
*All Done!*
|
||||
|
||||
|
@ -346,5 +351,5 @@ help solve problems in this space.
|
|||
|
||||
## Further Reading
|
||||
|
||||
Check out the [Getting Started](./docs/GETTING_STARTED.md) guide for more examples
|
||||
Check out the [Getting Started](https://smallstep.com/docs/getting-started/) guide for more examples
|
||||
and best practices on running Step CA in production.
|
||||
|
|
|
@ -24,6 +24,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/smallstep/assert"
|
||||
"github.com/smallstep/certificates/authority"
|
||||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
"github.com/smallstep/certificates/logging"
|
||||
|
@ -151,7 +153,7 @@ func parseCertificate(data string) *x509.Certificate {
|
|||
}
|
||||
|
||||
func parseCertificateRequest(data string) *x509.CertificateRequest {
|
||||
block, _ := pem.Decode([]byte(csrPEM))
|
||||
block, _ := pem.Decode([]byte(data))
|
||||
if block == nil {
|
||||
panic("failed to parse certificate request PEM")
|
||||
}
|
||||
|
@ -386,13 +388,13 @@ func TestSignRequest_Validate(t *testing.T) {
|
|||
NotAfter time.Time
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
wantErr bool
|
||||
name string
|
||||
fields fields
|
||||
err error
|
||||
}{
|
||||
{"missing csr", fields{CertificateRequest{}, "foobarzar", time.Time{}, time.Time{}}, true},
|
||||
{"invalid csr", fields{CertificateRequest{bad}, "foobarzar", time.Time{}, time.Time{}}, true},
|
||||
{"missing ott", fields{CertificateRequest{csr}, "", time.Time{}, time.Time{}}, true},
|
||||
{"missing csr", fields{CertificateRequest{}, "foobarzar", time.Time{}, time.Time{}}, errors.New("missing csr")},
|
||||
{"invalid csr", fields{CertificateRequest{bad}, "foobarzar", time.Time{}, time.Time{}}, errors.New("invalid csr")},
|
||||
{"missing ott", fields{CertificateRequest{csr}, "", time.Time{}, time.Time{}}, errors.New("missing ott")},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -402,8 +404,12 @@ func TestSignRequest_Validate(t *testing.T) {
|
|||
NotAfter: NewTimeDuration(tt.fields.NotAfter),
|
||||
NotBefore: NewTimeDuration(tt.fields.NotBefore),
|
||||
}
|
||||
if err := s.Validate(); (err != nil) != tt.wantErr {
|
||||
t.Errorf("SignRequest.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
if err := s.Validate(); err != nil {
|
||||
if assert.NotNil(t, tt.err) {
|
||||
assert.HasPrefix(t, err.Error(), tt.err.Error())
|
||||
}
|
||||
} else {
|
||||
assert.Nil(t, tt.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -124,11 +124,14 @@ func TestAuthorityNew(t *testing.T) {
|
|||
assert.True(t, auth.initOnce)
|
||||
assert.NotNil(t, auth.intermediateIdentity)
|
||||
for _, p := range tc.config.AuthorityConfig.Provisioners {
|
||||
_p, ok := auth.provisioners.Load(p.GetID())
|
||||
var _p provisioner.Interface
|
||||
_p, ok = auth.provisioners.Load(p.GetID())
|
||||
assert.True(t, ok)
|
||||
assert.Equals(t, p, _p)
|
||||
if kid, encryptedKey, ok := p.GetEncryptedKey(); ok {
|
||||
key, ok := auth.provisioners.LoadEncryptedKey(kid)
|
||||
var kid, encryptedKey string
|
||||
if kid, encryptedKey, ok = p.GetEncryptedKey(); ok {
|
||||
var key string
|
||||
key, ok = auth.provisioners.LoadEncryptedKey(kid)
|
||||
assert.True(t, ok)
|
||||
assert.Equals(t, encryptedKey, key)
|
||||
}
|
||||
|
|
|
@ -68,7 +68,6 @@ func TestAuthority_authorizeToken(t *testing.T) {
|
|||
auth *Authority
|
||||
ott string
|
||||
err *apiError
|
||||
res []interface{}
|
||||
}
|
||||
tests := map[string]func(t *testing.T) *authorizeTest{
|
||||
"fail/invalid-ott": func(t *testing.T) *authorizeTest {
|
||||
|
@ -276,7 +275,6 @@ func TestAuthority_authorizeRevoke(t *testing.T) {
|
|||
auth *Authority
|
||||
opts *RevokeOptions
|
||||
err error
|
||||
res []interface{}
|
||||
}
|
||||
tests := map[string]func(t *testing.T) *authorizeTest{
|
||||
"fail/token/invalid-ott": func(t *testing.T) *authorizeTest {
|
||||
|
@ -386,7 +384,6 @@ func TestAuthority_AuthorizeSign(t *testing.T) {
|
|||
auth *Authority
|
||||
ott string
|
||||
err *apiError
|
||||
res []interface{}
|
||||
}
|
||||
tests := map[string]func(t *testing.T) *authorizeTest{
|
||||
"fail/invalid-ott": func(t *testing.T) *authorizeTest {
|
||||
|
@ -452,7 +449,7 @@ func TestAuthority_AuthorizeSign(t *testing.T) {
|
|||
}
|
||||
} else {
|
||||
if assert.Nil(t, tc.err) {
|
||||
assert.Len(t, 6, got)
|
||||
assert.Len(t, 8, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -479,7 +476,6 @@ func TestAuthority_Authorize(t *testing.T) {
|
|||
auth *Authority
|
||||
ott string
|
||||
err *apiError
|
||||
res []interface{}
|
||||
}
|
||||
tests := map[string]func(t *testing.T) *authorizeTest{
|
||||
"fail/invalid-ott": func(t *testing.T) *authorizeTest {
|
||||
|
@ -545,7 +541,7 @@ func TestAuthority_Authorize(t *testing.T) {
|
|||
}
|
||||
} else {
|
||||
if assert.Nil(t, tc.err) {
|
||||
assert.Len(t, 6, got)
|
||||
assert.Len(t, 8, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -296,6 +296,7 @@ func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
|
|||
}
|
||||
|
||||
return append(so,
|
||||
defaultPublicKeyValidator{},
|
||||
commonNameValidator(payload.Claims.Subject),
|
||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||
newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID),
|
||||
|
|
|
@ -328,11 +328,11 @@ func TestAWS_AuthorizeSign(t *testing.T) {
|
|||
wantLen int
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok", p1, args{t1}, 4, false},
|
||||
{"ok", p2, args{t2}, 6, false},
|
||||
{"ok", p2, args{t2Hostname}, 6, false},
|
||||
{"ok", p2, args{t2PrivateIP}, 6, false},
|
||||
{"ok", p1, args{t4}, 4, false},
|
||||
{"ok", p1, args{t1}, 5, false},
|
||||
{"ok", p2, args{t2}, 7, false},
|
||||
{"ok", p2, args{t2Hostname}, 7, false},
|
||||
{"ok", p2, args{t2PrivateIP}, 7, false},
|
||||
{"ok", p1, args{t4}, 5, false},
|
||||
{"fail account", p3, args{t3}, 0, true},
|
||||
{"fail token", p1, args{"token"}, 0, true},
|
||||
{"fail subject", p1, args{failSubject}, 0, true},
|
||||
|
|
|
@ -284,6 +284,7 @@ func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption,
|
|||
}
|
||||
|
||||
return append(so,
|
||||
defaultPublicKeyValidator{},
|
||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||
newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID),
|
||||
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
||||
|
|
|
@ -283,9 +283,9 @@ func TestAzure_AuthorizeSign(t *testing.T) {
|
|||
wantLen int
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok", p1, args{t1}, 3, false},
|
||||
{"ok", p2, args{t2}, 5, false},
|
||||
{"ok", p1, args{t11}, 3, false},
|
||||
{"ok", p1, args{t1}, 4, false},
|
||||
{"ok", p2, args{t2}, 6, false},
|
||||
{"ok", p1, args{t11}, 4, false},
|
||||
{"fail tenant", p3, args{t3}, 0, true},
|
||||
{"fail resource group", p4, args{t4}, 0, true},
|
||||
{"fail token", p1, args{"token"}, 0, true},
|
||||
|
|
|
@ -237,6 +237,7 @@ func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
|
|||
}
|
||||
|
||||
return append(so,
|
||||
defaultPublicKeyValidator{},
|
||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||
newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName),
|
||||
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
||||
|
|
|
@ -313,9 +313,9 @@ func TestGCP_AuthorizeSign(t *testing.T) {
|
|||
wantLen int
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok", p1, args{t1}, 3, false},
|
||||
{"ok", p2, args{t2}, 5, false},
|
||||
{"ok", p3, args{t3}, 3, false},
|
||||
{"ok", p1, args{t1}, 4, false},
|
||||
{"ok", p2, args{t2}, 6, false},
|
||||
{"ok", p3, args{t3}, 4, false},
|
||||
{"fail token", p1, args{"token"}, 0, true},
|
||||
{"fail key", p1, args{failKey}, 0, true},
|
||||
{"fail iss", p1, args{failIss}, 0, true},
|
||||
|
|
|
@ -156,11 +156,13 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
|
|||
claims.SANs = []string{claims.Subject}
|
||||
}
|
||||
|
||||
dnsNames, ips := x509util.SplitSANs(claims.SANs)
|
||||
dnsNames, ips, emails := x509util.SplitSANs(claims.SANs)
|
||||
return []SignOption{
|
||||
defaultPublicKeyValidator{},
|
||||
commonNameValidator(claims.Subject),
|
||||
dnsNamesValidator(dnsNames),
|
||||
ipAddressesValidator(ips),
|
||||
emailAddressesValidator(emails),
|
||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||
newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID),
|
||||
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
||||
|
|
|
@ -276,14 +276,14 @@ func TestJWK_AuthorizeSign(t *testing.T) {
|
|||
}
|
||||
} else {
|
||||
if assert.NotNil(t, got) {
|
||||
assert.Len(t, 6, got)
|
||||
assert.Len(t, 8, got)
|
||||
|
||||
_cnv := got[0]
|
||||
_cnv := got[1]
|
||||
cnv, ok := _cnv.(commonNameValidator)
|
||||
assert.True(t, ok)
|
||||
assert.Equals(t, string(cnv), "subject")
|
||||
|
||||
_dnv := got[1]
|
||||
_dnv := got[2]
|
||||
dnv, ok := _dnv.(dnsNamesValidator)
|
||||
assert.True(t, ok)
|
||||
if tt.name == "ok-sans" {
|
||||
|
|
|
@ -283,12 +283,18 @@ func (o *OIDC) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e
|
|||
}, nil
|
||||
}
|
||||
|
||||
return []SignOption{
|
||||
emailOnlyIdentity(claims.Email),
|
||||
so := []SignOption{
|
||||
defaultPublicKeyValidator{},
|
||||
profileDefaultDuration(o.claimer.DefaultTLSCertDuration()),
|
||||
newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID),
|
||||
newValidityValidator(o.claimer.MinTLSCertDuration(), o.claimer.MaxTLSCertDuration()),
|
||||
}, nil
|
||||
}
|
||||
// Admins should be able to authorize any SAN
|
||||
if o.IsAdmin(claims.Email) {
|
||||
return so, nil
|
||||
}
|
||||
|
||||
return append(so, emailOnlyIdentity(claims.Email)), nil
|
||||
}
|
||||
|
||||
// AuthorizeRenewal returns an error if the renewal is disabled.
|
||||
|
|
|
@ -291,7 +291,7 @@ func TestOIDC_AuthorizeSign(t *testing.T) {
|
|||
if tt.name == "admin" {
|
||||
assert.Len(t, 3, got)
|
||||
} else {
|
||||
assert.Len(t, 4, got)
|
||||
assert.Len(t, 5, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -152,7 +152,16 @@ func (l *List) UnmarshalJSON(data []byte) error {
|
|||
case "azure":
|
||||
p = &Azure{}
|
||||
default:
|
||||
return errors.Errorf("provisioner type %s not supported", typ.Type)
|
||||
// Skip unsupported provisioners. A client using this method may be
|
||||
// compiled with a version of smallstep/certificates that does not
|
||||
// support a specific provisioner type. If we don't skip unknown
|
||||
// provisioners, a client encountering an unknown provisioner will
|
||||
// break. Rather than break the client, we skip the provisioner.
|
||||
// TODO: accept a pluggable logger (depending on client) that can
|
||||
// warn the user that an unknown provisioner was found and suggest
|
||||
// that the user update their client's dependency on
|
||||
// step/certificates and recompile.
|
||||
continue
|
||||
}
|
||||
if err := json.Unmarshal(data, p); err != nil {
|
||||
return errors.Errorf("error unmarshaling provisioner")
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package provisioner
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
|
@ -10,6 +12,7 @@ import (
|
|||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/smallstep/cli/crypto/x509util"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
// Options contains the options that can be passed to the Sign method.
|
||||
|
@ -78,7 +81,7 @@ func (e emailOnlyIdentity) Valid(req *x509.CertificateRequest) error {
|
|||
case len(req.EmailAddresses) == 0:
|
||||
return errors.New("certificate request does not contain any email address")
|
||||
case len(req.EmailAddresses) > 1:
|
||||
return errors.New("certificate request does not contain too many email addresses")
|
||||
return errors.New("certificate request contains too many email addresses")
|
||||
case req.EmailAddresses[0] == "":
|
||||
return errors.New("certificate request cannot contain an empty email address")
|
||||
case req.EmailAddresses[0] != string(e):
|
||||
|
@ -88,6 +91,23 @@ func (e emailOnlyIdentity) Valid(req *x509.CertificateRequest) error {
|
|||
}
|
||||
}
|
||||
|
||||
// defaultPublicKeyValidator validates the public key of a certificate request.
|
||||
type defaultPublicKeyValidator struct{}
|
||||
|
||||
// Valid checks that certificate request common name matches the one configured.
|
||||
func (v defaultPublicKeyValidator) Valid(req *x509.CertificateRequest) error {
|
||||
switch k := req.PublicKey.(type) {
|
||||
case *rsa.PublicKey:
|
||||
if k.Size() < 256 {
|
||||
return errors.New("rsa key in CSR must be at least 2048 bits (256 bytes)")
|
||||
}
|
||||
case *ecdsa.PublicKey, ed25519.PublicKey:
|
||||
default:
|
||||
return errors.Errorf("unrecognized public key of type '%T' in CSR", k)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// commonNameValidator validates the common name of a certificate request.
|
||||
type commonNameValidator string
|
||||
|
||||
|
@ -157,6 +177,26 @@ func (v ipAddressesValidator) Valid(req *x509.CertificateRequest) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// emailAddressesValidator validates the email address SANs of a certificate request.
|
||||
type emailAddressesValidator []string
|
||||
|
||||
// Valid checks that certificate request IP Addresses match those configured in
|
||||
// the bootstrap (token) flow.
|
||||
func (v emailAddressesValidator) Valid(req *x509.CertificateRequest) error {
|
||||
want := make(map[string]bool)
|
||||
for _, s := range v {
|
||||
want[s] = true
|
||||
}
|
||||
got := make(map[string]bool)
|
||||
for _, s := range req.EmailAddresses {
|
||||
got[s] = true
|
||||
}
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
return errors.Errorf("certificate request does not contain the valid Email Addresses - got %v, want %v", req.EmailAddresses, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validityValidator validates the certificate temporal validity settings.
|
||||
type validityValidator struct {
|
||||
min time.Duration
|
||||
|
|
|
@ -7,6 +7,12 @@ import (
|
|||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/smallstep/assert"
|
||||
"github.com/smallstep/cli/crypto/pemutil"
|
||||
"github.com/smallstep/cli/crypto/x509util"
|
||||
stepx509 "github.com/smallstep/cli/pkg/x509"
|
||||
)
|
||||
|
||||
func Test_emailOnlyIdentity_Valid(t *testing.T) {
|
||||
|
@ -41,6 +47,72 @@ func Test_emailOnlyIdentity_Valid(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_defaultPublicKeyValidator_Valid(t *testing.T) {
|
||||
_shortRSA, err := pemutil.Read("./testdata/short-rsa.csr")
|
||||
assert.FatalError(t, err)
|
||||
shortRSA, ok := _shortRSA.(*x509.CertificateRequest)
|
||||
assert.Fatal(t, ok)
|
||||
|
||||
_rsa, err := pemutil.Read("./testdata/rsa.csr")
|
||||
assert.FatalError(t, err)
|
||||
rsaCSR, ok := _rsa.(*x509.CertificateRequest)
|
||||
assert.Fatal(t, ok)
|
||||
|
||||
_ecdsa, err := pemutil.Read("./testdata/ecdsa.csr")
|
||||
assert.FatalError(t, err)
|
||||
ecdsaCSR, ok := _ecdsa.(*x509.CertificateRequest)
|
||||
assert.Fatal(t, ok)
|
||||
|
||||
_ed25519, err := pemutil.Read("./testdata/ed25519.csr", pemutil.WithStepCrypto())
|
||||
assert.FatalError(t, err)
|
||||
ed25519CSR, ok := _ed25519.(*stepx509.CertificateRequest)
|
||||
assert.Fatal(t, ok)
|
||||
|
||||
v := defaultPublicKeyValidator{}
|
||||
tests := []struct {
|
||||
name string
|
||||
csr *x509.CertificateRequest
|
||||
err error
|
||||
}{
|
||||
{
|
||||
"fail/unrecognized-key-type",
|
||||
&x509.CertificateRequest{PublicKey: "foo"},
|
||||
errors.New("unrecognized public key of type 'string' in CSR"),
|
||||
},
|
||||
{
|
||||
"fail/rsa/too-short",
|
||||
shortRSA,
|
||||
errors.New("rsa key in CSR must be at least 2048 bits (256 bytes)"),
|
||||
},
|
||||
{
|
||||
"ok/rsa",
|
||||
rsaCSR,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"ok/ecdsa",
|
||||
ecdsaCSR,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"ok/ed25519",
|
||||
x509util.ToX509CertificateRequest(ed25519CSR),
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := v.Valid(tt.csr); err != nil {
|
||||
if assert.NotNil(t, tt.err) {
|
||||
assert.HasPrefix(t, err.Error(), tt.err.Error())
|
||||
}
|
||||
} else {
|
||||
assert.Nil(t, tt.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_commonNameValidator_Valid(t *testing.T) {
|
||||
type args struct {
|
||||
req *x509.CertificateRequest
|
||||
|
@ -88,6 +160,33 @@ func Test_commonNameSliceValidator_Valid(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_emailAddressesValidator_Valid(t *testing.T) {
|
||||
type args struct {
|
||||
req *x509.CertificateRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
v emailAddressesValidator
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok0", []string{}, args{&x509.CertificateRequest{EmailAddresses: []string{}}}, false},
|
||||
{"ok1", []string{"max@smallstep.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"max@smallstep.com"}}}, false},
|
||||
{"ok2", []string{"max@step.com", "mike@step.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"max@step.com", "mike@step.com"}}}, false},
|
||||
{"ok3", []string{"max@step.com", "mike@step.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"mike@step.com", "max@step.com"}}}, false},
|
||||
{"fail1", []string{"max@step.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"mike@step.com"}}}, true},
|
||||
{"fail2", []string{"mike@step.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"max@step.com", "mike@step.com"}}}, true},
|
||||
{"fail3", []string{"mike@step.com", "max@step.com"}, args{&x509.CertificateRequest{DNSNames: []string{"mike@step.com", "mex@step.com"}}}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := tt.v.Valid(tt.args.req); (err != nil) != tt.wantErr {
|
||||
t.Errorf("dnsNamesValidator.Valid() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_dnsNamesValidator_Valid(t *testing.T) {
|
||||
type args struct {
|
||||
req *x509.CertificateRequest
|
||||
|
|
7
authority/provisioner/testdata/ecdsa.csr
vendored
Normal file
7
authority/provisioner/testdata/ecdsa.csr
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIHqMIGRAgEAMA4xDDAKBgNVBAMTA2ZvbzBZMBMGByqGSM49AgEGCCqGSM49AwEH
|
||||
A0IABKdDjTb7XIYCWC4QUq1xn5hgf3J4WpfWbd3C5frKrA4/VdQ+XfpHQIxDoHqh
|
||||
jcWke0SEETc9i6HDDtWv8bXSETegITAfBgkqhkiG9w0BCQ4xEjAQMA4GA1UdEQQH
|
||||
MAWCA2ZvbzAKBggqhkjOPQQDAgNIADBFAiEA1pFLT8p/YogG0o6NEEmdxzwbOzJA
|
||||
A+C+DvoT91c1OcQCIGUjP3s+k6Xwdf/VukUZXTfG1lobmkZhO3vYxAjPkwA7
|
||||
-----END CERTIFICATE REQUEST-----
|
8
authority/provisioner/testdata/ecdsa.key
vendored
Normal file
8
authority/provisioner/testdata/ecdsa.key
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
-----BEGIN EC PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-256-CBC,54abd40e525b255542ee6161ec438721
|
||||
|
||||
fJvmEc5n0IG4t4FKF+ekKhpog4ods2nZjBR5KLkGH5oSGAOEADSXIRBK76Jnm/nz
|
||||
Kv8ZwGqxNnoJUQyeTMlyg5OnOUAQPyNBPvoItOlD2DP32WJXgQ+NSHB2h9pcBGYG
|
||||
yLWrCtzl9/P9REWskanPO4RujP27Ht62omcMO7SxxNI=
|
||||
-----END EC PRIVATE KEY-----
|
6
authority/provisioner/testdata/ed25519.csr
vendored
Normal file
6
authority/provisioner/testdata/ed25519.csr
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIGuMGICAQAwDjEMMAoGA1UEAxMDZm9vMCowBQYDK2VwAyEA3yF/Igqb5UTp6XOq
|
||||
yj+cZL9nIfjDKrUT0fMzDAHtIqqgITAfBgkqhkiG9w0BCQ4xEjAQMA4GA1UdEQQH
|
||||
MAWCA2ZvbzAFBgMrZXADQQAIAx7N6ezi4NL8n0oJU8v3AmVSi0XvTuIHXUtcLGoU
|
||||
OZtlO3zjWI+DgcT/ADeEKn+T8OazDxcCbTBbHiM2hIsA
|
||||
-----END CERTIFICATE REQUEST-----
|
6
authority/provisioner/testdata/ed25519.key
vendored
Normal file
6
authority/provisioner/testdata/ed25519.key
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGkMGAGCSqGSIb3DQEFDTBTMDIGCSqGSIb3DQEFDDAlBBDJ0vCXdpPyUiLlbge5
|
||||
1g0jAgMBhqAwDAYIKoZIhvcNAgkAADAdBglghkgBZQMEASoEENtOknzU2eS2mlxl
|
||||
73Yo/IoEQEyJS2EEx3+oYaKlFIB90e1Zkmi8da7d3r2iUlfc7faRAiKChcEvtEas
|
||||
vYF2l9LEZ9DXv1Rm1uyNuSpXuddHScE=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
16
authority/provisioner/testdata/rsa.csr
vendored
Normal file
16
authority/provisioner/testdata/rsa.csr
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICdDCCAVwCAQAwDjEMMAoGA1UEAxMDZm9vMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEA86h3t/KJylE0/aPxvF9JqPaOwSsGexuDWqDVJSOWBJi/ZqUA
|
||||
Ea2Gy05ZIJkQ5GOy0bUs2JCNCVXVkfPrUkX6IvIlXpTjutjMDYyYGdgQjzpKPnOA
|
||||
v3mO2a7mLMzJunws7pvrUPP7z5KDCKSAPf6VAcu/na8rGDWn1TUYR8hINK1rLQQf
|
||||
OcyNWrr7yLkR84jSsrw/Qgc8NS//F4ccca1NfZecPEtxgcHjKdDQZ3SYRAfb6Dc0
|
||||
jRuvoByAd3q9okOOr70gpMXgpoFVArDynaHMPK9xJ1w2p3s2/NhOYgY9f9rtcWTo
|
||||
afoAcHK1jy5iQCogFUKt1bUCz5IsaYkRt+D+HQIDAQABoCEwHwYJKoZIhvcNAQkO
|
||||
MRIwEDAOBgNVHREEBzAFggNmb28wDQYJKoZIhvcNAQELBQADggEBAOsv1UKwEbcY
|
||||
8Fj2Pl55BjkqQG4PqSQdWJZfK0ol/GRty5XFaTgOUZyTeXOag84OGw0qM0E7kkUa
|
||||
O5QwDOpnmIgg01Ywr4QM166l1iED+eOUscXJMonBAsS3JNYF1JxcDyKzIl/dt9+w
|
||||
JXQ64uquuD57amOs8++ROfKW988HzXm0OnoHj8LZ1Mq2yUmxvnnfVnmMpZWo43sA
|
||||
8NQs4v9dT5wLByFvBjcaWiGVZwZiwT4Q/Msskv9L0o1On0fgCJ6PjLYdblTwMHDZ
|
||||
syH+X8SsUqeEmyvtiRc1XUeFbxS2hnPXJCXeyfljqwsBNGaVhBXcsV2Lg7IaloBF
|
||||
/RyWqQZ44eE=
|
||||
-----END CERTIFICATE REQUEST-----
|
30
authority/provisioner/testdata/rsa.key
vendored
Normal file
30
authority/provisioner/testdata/rsa.key
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-256-CBC,e77ed7e2d2572b5a246a1c4b994190bb
|
||||
|
||||
29o7UA/L7OF7inTPKkwBrtd8CJdXVQs9R3oJPitmFk8SZbrLHEiEhF1C0uB3xK3s
|
||||
GWQ9O7bjERM3uAvQkd7MSkUUBpyPXS9GFacd85e85d1Ubl6miTAwkFrQnT9yn6n/
|
||||
Fak5JtkmdB6ObfVTioOwT1jdtGTifKg1bIhYISgwqCWhgV2fUFk6HQAAIMXTTRc+
|
||||
ZK1WbunT7LimYrnN3gQ4ylm/4C8nQl3JCGpvWZaRoH91q1LLD6IwWmX0D09F37dU
|
||||
X3KoKv/GvuDlV3H1dUBwxhU+GI5/lItPp9OcdLZnnr67Gs+X+do3MFT1h675TM4N
|
||||
c9QEIJB6RYatLBKHCS7j8W7EbuJAFZ+MCCapP92ERmVVVsWPY+V7CDVQxM2v4X/w
|
||||
7C7JYx8b4xuQbdvu9KVU5irsXg8hBx7kDb/mtWjT4+8+sseLKA4oOmI6XwVMdbow
|
||||
MciGilAIaNtWwQHe0EK9E9tiQfc9OyzxdrfplRckAAehHuPGU7+iMCsigCLT3aiV
|
||||
CDHmnLdTXKIvGe8faTQoJphrb9F8bobGo5D4ZqX5f6gKuPIJsfd/r0GD8VNSF/Q7
|
||||
SJQMhkVyaixFB0gQbmea7sTyScdW+Qne7nLpam3ISgo+G4CAH8W88wLnuHMLmvoC
|
||||
ZE3HvArSeQZ0WPHgB86AfoNRIxd6Emgb+dFyA6wPJC29nZkB8PFSrAHp0zp7KilF
|
||||
fe9K2dVAUBZFhQthQIYAjJmYLCukLhxUALiqdSmQZrt6DSE33K8s5ed2KJu/60G6
|
||||
lZwIzQHPXesRhwmwbkfPB8CyWM+L6osdWv8QyMdM8Wb+66zkhKWBNbm+ccMfP6Zf
|
||||
1ynF/a/DRX8bf81w+nvLsCGTdxVuEVEpuzS1NclKTmYQu58Ol0RgQe2JSxL89n+A
|
||||
JAHUu9g9LcTg2jNPjxeA/vusSXMZRrPqrUCYhHhcgR4mE13uyyFI/9frk0gPpKXp
|
||||
/FislMydWov2JRp1ixzypMBqlFR/zF6j6m3P1g7gchwScWzrZQHD58xdRin4Udiv
|
||||
OR4huswh5v2i/0KozBoUAwbvPGERnMlTaGoBMPJ5Xe/jkBJw3uC3Dhi74uyUCjqU
|
||||
hMQW4RJKmuiZVfAIX0RdgeUWXPs+8pf2pXrpIiVHCAHDrxXNMC7X6/9EcBN15B88
|
||||
W5/KIRngDeB2oVYrn1GfO7iLu1Rd8VFXyaVItOXq7WrL2pwm8ANhWcFDdnXf6jHW
|
||||
BcKss1j8rZxOchksf+ZPXhn3QkdooD9iVONky1zLIsV5GPwMe8+yXwXznzJSbHH7
|
||||
dOfhK93fZqUwx4gFULwCuWIwLTfNmQ3VzdKioGt39RFDVQb+pbR7p9jv899VjsVO
|
||||
TBBpRa00fvbK1H2CMVHnwwIf82M4XypSNGR/tSD3AImZPb5RfZnznoXXCMEfYVsd
|
||||
8/Ry4GHusA+zxCjCxHFtXVkb9sklewJtnUmN5mUzo/81szuigLB5IADR21IOyVBq
|
||||
A4kz96Ta885Z5owhonfZp1HD53pDEbxCuuIy+fgYfjfDSAj3L/QT3ZKrdcIdYQap
|
||||
PhrNRW3j38koAatTLd3+E9KqBO5BiY+T5h+Q3XesWnaXInfu5WKiiEm5hHiejA0C
|
||||
-----END RSA PRIVATE KEY-----
|
10
authority/provisioner/testdata/short-rsa.csr
vendored
Normal file
10
authority/provisioner/testdata/short-rsa.csr
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBdDCB2wIBADAOMQwwCgYDVQQDEwNmb28wgaIwDQYJKoZIhvcNAQEBBQADgZAA
|
||||
MIGMAoGEAK8dks7oV6kcIFEaWna7CDGYPAE8IL7rNi+ruQ1dIYz+JtxT7OPjbCn/
|
||||
t5iqni96+35iS/8CvMtEuquOMTMSWOWwlurrbTbLqCazuz/g233o8udxSxhny3cY
|
||||
wHogp4cXCX6cFll6DeUnoCEuTTSIu8IBHbK48VfNw4V4gGz6cp/H93HrAgMBAAGg
|
||||
ITAfBgkqhkiG9w0BCQ4xEjAQMA4GA1UdEQQHMAWCA2ZvbzANBgkqhkiG9w0BAQsF
|
||||
AAOBhABCZsYM+Kgje68Z9Fjl2+cBwtQHvZDarh+cz6W1SchinZ1T0aNQvSj/otOe
|
||||
ttnEF4Rq8zqzr4fbv+AF451Mx36AkfgZr9XWGzxidrH+fBCNWXWNR+ymhrL6UFTG
|
||||
2FbarLt9jN2aJLAYQPwtSeGTAZ74tLOPRPnTP6aMfFNg4XCR0uveHA==
|
||||
-----END CERTIFICATE REQUEST-----
|
|
@ -8,6 +8,7 @@ import (
|
|||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
@ -205,6 +206,33 @@ func TestSign(t *testing.T) {
|
|||
},
|
||||
}
|
||||
},
|
||||
"fail rsa key too short": func(t *testing.T) *signTest {
|
||||
shortRSAKeyPEM := `-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBdDCB2wIBADAOMQwwCgYDVQQDEwNmb28wgaIwDQYJKoZIhvcNAQEBBQADgZAA
|
||||
MIGMAoGEAK8dks7oV6kcIFEaWna7CDGYPAE8IL7rNi+ruQ1dIYz+JtxT7OPjbCn/
|
||||
t5iqni96+35iS/8CvMtEuquOMTMSWOWwlurrbTbLqCazuz/g233o8udxSxhny3cY
|
||||
wHogp4cXCX6cFll6DeUnoCEuTTSIu8IBHbK48VfNw4V4gGz6cp/H93HrAgMBAAGg
|
||||
ITAfBgkqhkiG9w0BCQ4xEjAQMA4GA1UdEQQHMAWCA2ZvbzANBgkqhkiG9w0BAQsF
|
||||
AAOBhABCZsYM+Kgje68Z9Fjl2+cBwtQHvZDarh+cz6W1SchinZ1T0aNQvSj/otOe
|
||||
ttnEF4Rq8zqzr4fbv+AF451Mx36AkfgZr9XWGzxidrH+fBCNWXWNR+ymhrL6UFTG
|
||||
2FbarLt9jN2aJLAYQPwtSeGTAZ74tLOPRPnTP6aMfFNg4XCR0uveHA==
|
||||
-----END CERTIFICATE REQUEST-----`
|
||||
block, _ := pem.Decode([]byte(shortRSAKeyPEM))
|
||||
assert.FatalError(t, err)
|
||||
csr, err := x509.ParseCertificateRequest(block.Bytes)
|
||||
assert.FatalError(t, err)
|
||||
|
||||
return &signTest{
|
||||
auth: a,
|
||||
csr: csr,
|
||||
extraOpts: extraOpts,
|
||||
signOpts: signOpts,
|
||||
err: &apiError{errors.New("sign: rsa key in CSR must be at least 2048 bits (256 bytes)"),
|
||||
http.StatusUnauthorized,
|
||||
apiCtx{"csr": csr, "signOptions": signOpts},
|
||||
},
|
||||
}
|
||||
},
|
||||
"fail store cert in db": func(t *testing.T) *signTest {
|
||||
csr := getCSR(t, priv)
|
||||
_a := testAuthority(t)
|
||||
|
|
|
@ -563,8 +563,7 @@ func CreateSignRequest(ott string) (*api.SignRequest, crypto.PrivateKey, error)
|
|||
return nil, nil, errors.Wrap(err, "error generating key")
|
||||
}
|
||||
|
||||
var emails []string
|
||||
dnsNames, ips := x509util.SplitSANs(claims.SANs)
|
||||
dnsNames, ips, emails := x509util.SplitSANs(claims.SANs)
|
||||
if claims.Email != "" {
|
||||
emails = append(emails, claims.Email)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"html"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
|
@ -54,12 +56,64 @@ func printFullVersion() {
|
|||
fmt.Printf("Release Date: %s\n", releaseDate())
|
||||
}
|
||||
|
||||
// appHelpTemplate contains the modified template for the main app
|
||||
var appHelpTemplate = `## NAME
|
||||
**{{.HelpName}}** -- {{.Usage}}
|
||||
|
||||
## USAGE
|
||||
{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}**{{if .Commands}} <command>{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}_[arguments]_{{end}}{{end}}{{if .Description}}
|
||||
|
||||
## DESCRIPTION
|
||||
{{.Description}}{{end}}{{if .VisibleCommands}}
|
||||
|
||||
## COMMANDS
|
||||
|
||||
{{range .VisibleCategories}}{{if .Name}}{{.Name}}:{{end}}
|
||||
|||
|
||||
|---|---|{{range .VisibleCommands}}
|
||||
| **{{join .Names ", "}}** | {{.Usage}} |{{end}}
|
||||
{{end}}{{if .VisibleFlags}}{{end}}
|
||||
|
||||
## OPTIONS
|
||||
|
||||
{{range $index, $option := .VisibleFlags}}{{if $index}}
|
||||
{{end}}{{$option}}
|
||||
{{end}}{{end}}{{if .Copyright}}{{if len .Authors}}
|
||||
|
||||
## AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
|
||||
|
||||
{{range $index, $author := .Authors}}{{if $index}}
|
||||
{{end}}{{$author}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
|
||||
|
||||
## ONLINE
|
||||
|
||||
This documentation is available online at https://smallstep.com/docs/certificates
|
||||
|
||||
## VERSION
|
||||
|
||||
{{.Version}}{{end}}{{end}}
|
||||
|
||||
## COPYRIGHT
|
||||
|
||||
{{.Copyright}}
|
||||
|
||||
## FEEDBACK ` +
|
||||
html.UnescapeString("&#"+strconv.Itoa(128525)+";") + " " +
|
||||
html.UnescapeString("&#"+strconv.Itoa(127867)+";") +
|
||||
`
|
||||
|
||||
The **step-ca** utility is not instrumented for usage statistics. It does not phone home.
|
||||
But your feedback is extremely valuable. Any information you can provide regarding how you’re using **step-ca** helps.
|
||||
Please send us a sentence or two, good or bad: **feedback@smallstep.com** or join https://gitter.im/smallstep/community.
|
||||
{{end}}
|
||||
`
|
||||
|
||||
func main() {
|
||||
// Override global framework components
|
||||
cli.VersionPrinter = func(c *cli.Context) {
|
||||
printFullVersion()
|
||||
}
|
||||
cli.AppHelpTemplate = usage.AppHelpTemplate
|
||||
cli.AppHelpTemplate = appHelpTemplate
|
||||
cli.SubcommandHelpTemplate = usage.SubcommandHelpTemplate
|
||||
cli.CommandHelpTemplate = usage.CommandHelpTemplate
|
||||
cli.HelpPrinter = usage.HelpPrinter
|
||||
|
@ -118,7 +172,7 @@ intermediate private key.`,
|
|||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "version",
|
||||
Usage: "Displays the current version of the cli",
|
||||
Usage: "Displays the current version of step-ca",
|
||||
// Command prints out the current version of the tool
|
||||
Action: func(c *cli.Context) error {
|
||||
printFullVersion()
|
||||
|
@ -143,12 +197,12 @@ intermediate private key.`,
|
|||
}()
|
||||
}
|
||||
|
||||
app.Action = func(ctx *cli.Context) error {
|
||||
app.Action = func(_ *cli.Context) error {
|
||||
// Hack to be able to run a the top action as a subcommand
|
||||
cmd := cli.Command{Name: "start", Action: startAction, Flags: app.Flags}
|
||||
set := flag.NewFlagSet(app.Name, flag.ContinueOnError)
|
||||
set.Parse(os.Args)
|
||||
ctx = cli.NewContext(app, set, nil)
|
||||
ctx := cli.NewContext(app, set, nil)
|
||||
return cmd.Run(ctx)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue