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
|
coverage.txt
|
||||||
vendor
|
vendor
|
||||||
output
|
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"
|
pruneopts = "UT"
|
||||||
revision = "e2d15f34fcf99d5dbb871c820ec73f710fca9815"
|
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]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:454adc7f974228ff789428b6dc098638c57a64aa0718f0bd61e53d3cd39d7a75"
|
digest = "1:454adc7f974228ff789428b6dc098638c57a64aa0718f0bd61e53d3cd39d7a75"
|
||||||
|
@ -32,17 +17,6 @@
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "2972be24d48e78746da79ba8e24e8b488c9880de"
|
revision = "2972be24d48e78746da79ba8e24e8b488c9880de"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:848ef40f818e59905140552cc49ff3dc1a15f955e4b56d1c5c2cc4b54dbadf0c"
|
|
||||||
name = "github.com/client9/misspell"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"cmd/misspell",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "b90dc15cfd220ecf8bbc9043ecb928cef381f011"
|
|
||||||
version = "v0.3.4"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:21ac9938fb1098b3a7b0dd909fb30878d33231177fac11a2821114eb9c1088ff"
|
digest = "1:21ac9938fb1098b3a7b0dd909fb30878d33231177fac11a2821114eb9c1088ff"
|
||||||
name = "github.com/dgraph-io/badger"
|
name = "github.com/dgraph-io/badger"
|
||||||
|
@ -82,17 +56,6 @@
|
||||||
revision = "72cd26f257d44c1114970e19afddcd812016007e"
|
revision = "72cd26f257d44c1114970e19afddcd812016007e"
|
||||||
version = "v1.4.1"
|
version = "v1.4.1"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "travis-1.9"
|
|
||||||
digest = "1:e8f5d9c09a7209c740e769713376abda388c41b777ba8e9ed52767e21acf379f"
|
|
||||||
name = "github.com/golang/lint"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"golint",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "883fe33ffc4344bad1ecd881f61afd5ec5d80e0a"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d"
|
digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d"
|
||||||
name = "github.com/golang/protobuf"
|
name = "github.com/golang/protobuf"
|
||||||
|
@ -101,22 +64,6 @@
|
||||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||||
version = "v1.2.0"
|
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]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:e51f40f0c19b39c1825eadd07d5c0a98a2ad5942b166d9fc4f54750ce9a04810"
|
digest = "1:e51f40f0c19b39c1825eadd07d5c0a98a2ad5942b166d9fc4f54750ce9a04810"
|
||||||
|
@ -145,7 +92,7 @@
|
||||||
revision = "2d01aacdc34a083dca635ba869909f5fc0cd4f41"
|
revision = "2d01aacdc34a083dca635ba869909f5fc0cd4f41"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:2a2a76072bd413b3484a0b5bb2fbb078b0b7dd8950e9276c900e14dce2354679"
|
digest = "1:2d2bc0f23cca6b59cec3fbece9abc102bdb19f548dd58d7667e57699074a2c76"
|
||||||
name = "github.com/manifoldco/promptui"
|
name = "github.com/manifoldco/promptui"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
|
@ -153,8 +100,8 @@
|
||||||
"screenbuf",
|
"screenbuf",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "20f2a94120aa14a334121a6de66616a7fa89a5cd"
|
revision = "157c96fb638a14d268b305cf2012582431fcc410"
|
||||||
version = "v0.3.2"
|
version = "v0.3.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
|
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
|
||||||
|
@ -210,27 +157,6 @@
|
||||||
revision = "f5bce3387232559bcbe6a5f8227c4bf508dac1ba"
|
revision = "f5bce3387232559bcbe6a5f8227c4bf508dac1ba"
|
||||||
version = "v1.11.0"
|
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]]
|
[[projects]]
|
||||||
digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
|
digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
|
||||||
name = "github.com/pkg/errors"
|
name = "github.com/pkg/errors"
|
||||||
|
@ -281,7 +207,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:8eb842c27bca9dae16d77baeba7cf612135033da381faf833bb8c11c29a751c7"
|
digest = "1:4998154cc4ffb0ab954b7ecaad6899dcdea8f8ec79c94a071994d1a3b332d493"
|
||||||
name = "github.com/smallstep/cli"
|
name = "github.com/smallstep/cli"
|
||||||
packages = [
|
packages = [
|
||||||
"command",
|
"command",
|
||||||
|
@ -302,7 +228,7 @@
|
||||||
"utils",
|
"utils",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "98635d188cade54451e3997b530716297ce7fc00"
|
revision = "3254c70079f798ee5f269c98fe27abd9a11c4aad"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -318,14 +244,6 @@
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "a0934e12468769d8cbede3ed316c47a4b88de4ca"
|
revision = "a0934e12468769d8cbede3ed316c47a4b88de4ca"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:ba52e5a5fb800ce55108b7a5f181bb809aab71c16736051312b0aa969f82ad39"
|
|
||||||
name = "github.com/tsenart/deadcode"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "210d2dc333e90c7e3eedf4f2242507a8e83ed4ab"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:6743b69de0d73e91004e4e201cf4965b59a0fa5caf6f0ffbe0cb9ee8807738a7"
|
digest = "1:6743b69de0d73e91004e4e201cf4965b59a0fa5caf6f0ffbe0cb9ee8807738a7"
|
||||||
|
@ -441,13 +359,6 @@
|
||||||
revision = "54a98f90d1c46b7731eb8fb305d2a321c30ef610"
|
revision = "54a98f90d1c46b7731eb8fb305d2a321c30ef610"
|
||||||
version = "v1.5.0"
|
version = "v1.5.0"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:39efb07a0d773dc09785b237ada4e10b5f28646eb6505d97bc18f8d2ff439362"
|
|
||||||
name = "gopkg.in/alecthomas/kingpin.v3-unstable"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:9593bab40e981b1f90b7e07faeab0d09b75fe338880d08880f986a9d3283c53f"
|
digest = "1:9593bab40e981b1f90b7e07faeab0d09b75fe338880d08880f986a9d3283c53f"
|
||||||
name = "gopkg.in/square/go-jose.v2"
|
name = "gopkg.in/square/go-jose.v2"
|
||||||
|
@ -461,23 +372,11 @@
|
||||||
revision = "730df5f748271903322feb182be83b43ebbbe27d"
|
revision = "730df5f748271903322feb182be83b43ebbbe27d"
|
||||||
version = "v2.3.1"
|
version = "v2.3.1"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
|
|
||||||
name = "gopkg.in/yaml.v2"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
|
||||||
version = "v2.2.1"
|
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
input-imports = [
|
input-imports = [
|
||||||
"github.com/alecthomas/gometalinter",
|
|
||||||
"github.com/client9/misspell/cmd/misspell",
|
|
||||||
"github.com/go-chi/chi",
|
"github.com/go-chi/chi",
|
||||||
"github.com/golang/lint/golint",
|
|
||||||
"github.com/gordonklaus/ineffassign",
|
|
||||||
"github.com/newrelic/go-agent",
|
"github.com/newrelic/go-agent",
|
||||||
"github.com/pkg/errors",
|
"github.com/pkg/errors",
|
||||||
"github.com/rs/xid",
|
"github.com/rs/xid",
|
||||||
|
@ -491,13 +390,14 @@
|
||||||
"github.com/smallstep/cli/crypto/x509util",
|
"github.com/smallstep/cli/crypto/x509util",
|
||||||
"github.com/smallstep/cli/errs",
|
"github.com/smallstep/cli/errs",
|
||||||
"github.com/smallstep/cli/jose",
|
"github.com/smallstep/cli/jose",
|
||||||
|
"github.com/smallstep/cli/pkg/x509",
|
||||||
"github.com/smallstep/cli/token",
|
"github.com/smallstep/cli/token",
|
||||||
"github.com/smallstep/cli/token/provision",
|
"github.com/smallstep/cli/token/provision",
|
||||||
"github.com/smallstep/cli/usage",
|
"github.com/smallstep/cli/usage",
|
||||||
"github.com/smallstep/nosql",
|
"github.com/smallstep/nosql",
|
||||||
"github.com/smallstep/nosql/database",
|
"github.com/smallstep/nosql/database",
|
||||||
"github.com/tsenart/deadcode",
|
|
||||||
"github.com/urfave/cli",
|
"github.com/urfave/cli",
|
||||||
|
"golang.org/x/crypto/ed25519",
|
||||||
"golang.org/x/crypto/ocsp",
|
"golang.org/x/crypto/ocsp",
|
||||||
"golang.org/x/crypto/ssh",
|
"golang.org/x/crypto/ssh",
|
||||||
"golang.org/x/net/http2",
|
"golang.org/x/net/http2",
|
||||||
|
|
13
Gopkg.toml
13
Gopkg.toml
|
@ -23,19 +23,6 @@
|
||||||
# non-go = false
|
# non-go = false
|
||||||
# go-tests = true
|
# go-tests = true
|
||||||
# unused-packages = 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]]
|
[[override]]
|
||||||
name = "gopkg.in/alecthomas/kingpin.v3-unstable"
|
name = "gopkg.in/alecthomas/kingpin.v3-unstable"
|
||||||
revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306"
|
revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306"
|
||||||
|
|
28
Makefile
28
Makefile
|
@ -22,25 +22,18 @@ all: build test lint
|
||||||
bootstra%:
|
bootstra%:
|
||||||
$Q which dep || go get github.com/golang/dep/cmd/dep
|
$Q which dep || go get github.com/golang/dep/cmd/dep
|
||||||
$Q dep ensure
|
$Q dep ensure
|
||||||
|
$Q GO111MODULE=on go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.17.1
|
||||||
|
|
||||||
|
|
||||||
vendor: Gopkg.lock
|
vendor: Gopkg.lock
|
||||||
$Q dep ensure
|
$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
|
define VENDOR_BIN_TMPL
|
||||||
vendor/bin/$(notdir $(1)): vendor
|
vendor/bin/$(notdir $(1)): vendor
|
||||||
$Q go build -o $$@ ./vendor/$(1)
|
$Q go build -o $$@ ./vendor/$(1)
|
||||||
VENDOR_BINS += vendor/bin/$(notdir $(1))
|
VENDOR_BINS += vendor/bin/$(notdir $(1))
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(foreach pkg,$(BOOTSTRAP),$(eval $(call VENDOR_BIN_TMPL,$(pkg))))
|
|
||||||
|
|
||||||
.PHONY: bootstra% vendor
|
.PHONY: bootstra% vendor
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
|
@ -126,24 +119,11 @@ integration: bin/$(BINNAME)
|
||||||
# Linting
|
# 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:
|
fmt:
|
||||||
$Q gofmt -l -w $(SRC)
|
$Q gofmt -l -w $(SRC)
|
||||||
|
|
||||||
lint: $(LINTERS)
|
lint:
|
||||||
|
$Q LOG_LEVEL=error golangci-lint run
|
||||||
|
|
||||||
.PHONY: $(LINTERS) lint fmt
|
.PHONY: $(LINTERS) lint fmt
|
||||||
|
|
||||||
|
|
271
README.md
271
README.md
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
An online certificate authority and related tools for secure automated certificate management, so you can use TLS everywhere.
|
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) |
|
[Website](https://smallstep.com) |
|
||||||
[Documentation](#documentation) |
|
[Documentation](#documentation) |
|
||||||
[Installation Guide](#installation-guide) |
|
[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
|
## Motivation
|
||||||
|
|
||||||
Managing your own *public key infrastructure* (PKI) can be tedious and error
|
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
|
makes it much easier to implement good security practices early, and
|
||||||
incrementally improve them as your system matures.
|
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
|
website](https://smallstep.com/certificates) and the [blog
|
||||||
post](https://smallstep.com/blog/step-certificates.html) announcing Step
|
post](https://smallstep.com/blog/step-certificates.html) announcing this project.
|
||||||
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.
|
|
||||||
|
|
||||||
## Installation Guide
|
## Installation Guide
|
||||||
|
|
||||||
These instructions will install an OS specific version of the `step-ca` binary on
|
These instructions will install an OS specific version of the `step-ca` binary on
|
||||||
your local machine.
|
your local machine.
|
||||||
|
|
||||||
> NOTE: While `step` is not required to run the Step Certificate Authority (CA)
|
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.
|
||||||
> 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.
|
|
||||||
|
|
||||||
### Mac OS
|
### Mac OS
|
||||||
|
|
||||||
Install `step` via [Homebrew](https://brew.sh/). The
|
Install `step` and `step-ca` together via [Homebrew](https://brew.sh/):
|
||||||
[Homebrew Formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/step.rb)
|
|
||||||
installs both `step cli` and `step certificates`.
|
|
||||||
|
|
||||||
<pre><code>
|
<pre><code><b>$ brew install step</b>
|
||||||
<b>$ brew install step</b>
|
|
||||||
|
|
||||||
# Test installation ...
|
# Test installation ...
|
||||||
<b>$ step certificate inspect https://smallstep.com</b>
|
<b>$ step certificate inspect https://smallstep.com</b>
|
||||||
|
@ -87,24 +110,24 @@ Certificate:
|
||||||
Serial Number: 326381749415081530968054238478851085504954 (0x3bf265673332db2d0c70e48a163fb7d11ba)
|
Serial Number: 326381749415081530968054238478851085504954 (0x3bf265673332db2d0c70e48a163fb7d11ba)
|
||||||
Signature Algorithm: SHA256-RSA
|
Signature Algorithm: SHA256-RSA
|
||||||
Issuer: C=US,O=Let's Encrypt,CN=Let's Encrypt Authority X3
|
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`
|
> Note: If you have installed `step` previously through the `smallstep/smallstep`
|
||||||
> tap you will need to run the following commands before installing:
|
> 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
|
### Linux
|
||||||
|
|
||||||
#### Debian
|
#### Debian
|
||||||
|
|
||||||
1. [Optional] Install `step cli`.
|
1. [Optional] Install `step`.
|
||||||
|
|
||||||
Download the latest Debian package from
|
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
|
$ 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
|
$ sudo dpkg -i step_X.Y.Z_amd64.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Install `step certificates`.
|
2. Install `step-ca`.
|
||||||
|
|
||||||
Download the latest Debian package from
|
Download the latest Debian package from [releases](https://github.com/smallstep/certificates/releases):
|
||||||
[`step certificates` 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
|
$ 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
|
We are using the [Arch User Repository](https://aur.archlinux.org) to distribute
|
||||||
`step` binaries for Arch Linux.
|
`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/).
|
* 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.
|
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
|
### Test
|
||||||
|
|
||||||
<pre><code>
|
<pre><code><b>$ step version</b>
|
||||||
<b>$ step version</b>
|
Smallstep CLI/0.10.0 (darwin/amd64)
|
||||||
Smallstep CLI/0.8.5 (darwin/amd64)
|
Release Date: 2019-04-30 19:01 UTC
|
||||||
Release Date: 2019-02-13 22:17 UTC
|
|
||||||
|
|
||||||
<b>$ step-ca version</b>
|
<b>$ step-ca version</b>
|
||||||
Smallstep CA/0.8.4 (darwin/amd64)
|
Smallstep CA/0.10.0 (darwin/amd64)
|
||||||
Release Date: 2019-02-18 18:56 UTC
|
Release Date: 2019-04-30 19:02 UTC</code></pre>
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
In the following guide we'll run a simple `hello` server that requires clients
|
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
|
to connect over an authorized and encrypted channel using HTTPS. `step-ca`
|
||||||
Certificate Authority (CA) will issue an identity dial tone to our server
|
will issue certificates to our server, allowing it to authenticate and encrypt
|
||||||
enabling it to authenticate and encrypt communication. Let's get started!
|
communication. Let's get started!
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
|
@ -167,101 +201,84 @@ enabling it to authenticate and encrypt communication. Let's get started!
|
||||||
|
|
||||||
### 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
|
Generating root certificate...
|
||||||
X.509 Certificates and private keys.
|
all done!
|
||||||
|
|
||||||
The root X.509 Certificate is a fancy public key that will be
|
Generating intermediate certificate...
|
||||||
distributed to clients enabling them to authenticate all certificates
|
all done!
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.</code></pre>
|
||||||
explanation of the Step CA configuration file.
|
|
||||||
|
|
||||||
<pre><code>
|
This command will:
|
||||||
<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>
|
|
||||||
|
|
||||||
Generating root certificate...
|
- Generate [password protected](https://github.com/smallstep/certificates/blob/master/docs/GETTING_STARTED.md#passwords) private keys for your CA to sign certificates
|
||||||
all done!
|
- 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...
|
You can find these artifacts in `$STEPPATH` (or `~/.step` by default).
|
||||||
all done!
|
|
||||||
|
|
||||||
✔ Root certificate: /Users/bob/src/github.com/smallstep/step/.step/certs/root_ca.crt
|
#### 2. Start `step-ca`:
|
||||||
✔ 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
|
|
||||||
|
|
||||||
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>
|
<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>
|
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 ...
|
2019/02/18 13:28:58 Serving HTTPS on 127.0.0.1:8080 ...</code></pre>
|
||||||
</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
|
||||||
|
|
||||||
```
|
import (
|
||||||
$ cat > srv.go <<EOF
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HiHandler(w http.ResponseWriter, req *http.Request) {
|
func HiHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
w.Write([]byte("Hello, world!\n"))
|
w.Write([]byte("Hello, world!\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
http.HandleFunc("/hi", HiHandler)
|
http.HandleFunc("/hi", HiHandler)
|
||||||
err := http.ListenAndServeTLS(":8443", "srv.crt", "srv.key", nil)
|
err := http.ListenAndServeTLS(":8443", "srv.crt", "srv.key", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Get an identity for your server from the Step CA.
|
#### 4. Get an identity for your server from the Step CA.
|
||||||
|
|
||||||
<pre><code>
|
<pre><code><b>$ step ca certificate localhost srv.crt srv.key</b>
|
||||||
<b>$ step ca certificate localhost srv.crt srv.key</b>
|
✔ Key ID: rQxROEr7Kx9TNjSQBTETtsu3GKmuW9zm02dMXZ8GUEk (bob@example.com)
|
||||||
✔ Key ID: rQxROEr7Kx9TNjSQBTETtsu3GKmuW9zm02dMXZ8GUEk (bob@example.com)
|
✔ Please enter the password to decrypt the provisioner key: abc123
|
||||||
✔ Please enter the password to decrypt the provisioner key: abc123
|
✔ CA: https://localhost:8080/1.0/sign
|
||||||
✔ CA: https://localhost:8080/1.0/sign
|
✔ Certificate: srv.crt
|
||||||
✔ Certificate: srv.crt
|
✔ Private Key: srv.key
|
||||||
✔ Private Key: srv.key
|
|
||||||
|
|
||||||
<b>$ step certificate inspect --bundle srv.crt</b>
|
<b>$ step certificate inspect --bundle srv.crt</b>
|
||||||
Certificate:
|
Certificate:
|
||||||
Data:
|
Data:
|
||||||
Version: 3 (0x2)
|
Version: 3 (0x2)
|
||||||
Serial Number: 140439335711218707689123407681832384336 (0x69a7a1d7f6f22f68059d2d9088307750)
|
Serial Number: 140439335711218707689123407681832384336 (0x69a7a1d7f6f22f68059d2d9088307750)
|
||||||
|
@ -271,8 +288,8 @@ X.509 Certificates and private keys.
|
||||||
Not Before: Feb 18 21:32:35 2019 UTC
|
Not Before: Feb 18 21:32:35 2019 UTC
|
||||||
Not After : Feb 19 21:32:35 2019 UTC
|
Not After : Feb 19 21:32:35 2019 UTC
|
||||||
Subject: CN=localhost
|
Subject: CN=localhost
|
||||||
...
|
...
|
||||||
Certificate:
|
Certificate:
|
||||||
Data:
|
Data:
|
||||||
Version: 3 (0x2)
|
Version: 3 (0x2)
|
||||||
Serial Number: 207035091234452090159026162349261226844 (0x9bc18217bd560cf07db23178ed90835c)
|
Serial Number: 207035091234452090159026162349261226844 (0x9bc18217bd560cf07db23178ed90835c)
|
||||||
|
@ -282,37 +299,25 @@ X.509 Certificates and private keys.
|
||||||
Not Before: Feb 18 21:27:21 2019 UTC
|
Not Before: Feb 18 21:27:21 2019 UTC
|
||||||
Not After : Feb 15 21:27:21 2029 UTC
|
Not After : Feb 15 21:27:21 2029 UTC
|
||||||
Subject: CN=Example Inc. Intermediate CA
|
Subject: CN=Example Inc. Intermediate CA
|
||||||
...
|
...</code></pre>
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
Notice that when you inspect `srv.crt` there are actually two certificates
|
Note that `step` and `step-ca` handle details like [certificate bundling](https://smallstep.com/blog/everything-pki.html#intermediates-chains-and-bundling) for you.
|
||||||
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.
|
|
||||||
|
|
||||||
4. Run the simple server.
|
#### 5. Run the simple server.
|
||||||
|
|
||||||
<pre><code>
|
<pre><code><b>$ go run srv.go &</b></code></pre>
|
||||||
<b>$ go run srv.go &</b>
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
5. Get the root certificate from the Step CA.
|
#### 6. Get the root certificate from the Step CA.
|
||||||
|
|
||||||
In a new Terminal window:
|
In a new Terminal window:
|
||||||
|
|
||||||
<pre><code>
|
<pre><code><b>$ step ca root root.crt</b>
|
||||||
<b>$ step ca root root.crt</b>
|
The root certificate has been saved in root.crt.</code></pre>
|
||||||
The root certificate has been saved in root.crt.
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
6. Make an authenticated, encrypted curl request to your server using HTTP over TLS.
|
#### 7. Make an authenticated, encrypted curl request to your server using HTTP over TLS.
|
||||||
|
|
||||||
<pre><code>
|
<pre><code><b>$ curl --cacert root.crt https://localhost:8443/hi</b>
|
||||||
<b>$ curl --cacert root.crt https://localhost:8443/hi</b>
|
Hello, world!</code></pre>
|
||||||
Hello, world!
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
*All Done!*
|
*All Done!*
|
||||||
|
|
||||||
|
@ -346,5 +351,5 @@ help solve problems in this space.
|
||||||
|
|
||||||
## Further Reading
|
## 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.
|
and best practices on running Step CA in production.
|
||||||
|
|
|
@ -24,6 +24,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/smallstep/assert"
|
||||||
"github.com/smallstep/certificates/authority"
|
"github.com/smallstep/certificates/authority"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
"github.com/smallstep/certificates/logging"
|
"github.com/smallstep/certificates/logging"
|
||||||
|
@ -151,7 +153,7 @@ func parseCertificate(data string) *x509.Certificate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCertificateRequest(data string) *x509.CertificateRequest {
|
func parseCertificateRequest(data string) *x509.CertificateRequest {
|
||||||
block, _ := pem.Decode([]byte(csrPEM))
|
block, _ := pem.Decode([]byte(data))
|
||||||
if block == nil {
|
if block == nil {
|
||||||
panic("failed to parse certificate request PEM")
|
panic("failed to parse certificate request PEM")
|
||||||
}
|
}
|
||||||
|
@ -388,11 +390,11 @@ func TestSignRequest_Validate(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fields fields
|
fields fields
|
||||||
wantErr bool
|
err error
|
||||||
}{
|
}{
|
||||||
{"missing csr", fields{CertificateRequest{}, "foobarzar", 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{}}, true},
|
{"invalid csr", fields{CertificateRequest{bad}, "foobarzar", time.Time{}, time.Time{}}, errors.New("invalid csr")},
|
||||||
{"missing ott", fields{CertificateRequest{csr}, "", time.Time{}, time.Time{}}, true},
|
{"missing ott", fields{CertificateRequest{csr}, "", time.Time{}, time.Time{}}, errors.New("missing ott")},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -402,8 +404,12 @@ func TestSignRequest_Validate(t *testing.T) {
|
||||||
NotAfter: NewTimeDuration(tt.fields.NotAfter),
|
NotAfter: NewTimeDuration(tt.fields.NotAfter),
|
||||||
NotBefore: NewTimeDuration(tt.fields.NotBefore),
|
NotBefore: NewTimeDuration(tt.fields.NotBefore),
|
||||||
}
|
}
|
||||||
if err := s.Validate(); (err != nil) != tt.wantErr {
|
if err := s.Validate(); err != nil {
|
||||||
t.Errorf("SignRequest.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
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.True(t, auth.initOnce)
|
||||||
assert.NotNil(t, auth.intermediateIdentity)
|
assert.NotNil(t, auth.intermediateIdentity)
|
||||||
for _, p := range tc.config.AuthorityConfig.Provisioners {
|
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.True(t, ok)
|
||||||
assert.Equals(t, p, _p)
|
assert.Equals(t, p, _p)
|
||||||
if kid, encryptedKey, ok := p.GetEncryptedKey(); ok {
|
var kid, encryptedKey string
|
||||||
key, ok := auth.provisioners.LoadEncryptedKey(kid)
|
if kid, encryptedKey, ok = p.GetEncryptedKey(); ok {
|
||||||
|
var key string
|
||||||
|
key, ok = auth.provisioners.LoadEncryptedKey(kid)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equals(t, encryptedKey, key)
|
assert.Equals(t, encryptedKey, key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,6 @@ func TestAuthority_authorizeToken(t *testing.T) {
|
||||||
auth *Authority
|
auth *Authority
|
||||||
ott string
|
ott string
|
||||||
err *apiError
|
err *apiError
|
||||||
res []interface{}
|
|
||||||
}
|
}
|
||||||
tests := map[string]func(t *testing.T) *authorizeTest{
|
tests := map[string]func(t *testing.T) *authorizeTest{
|
||||||
"fail/invalid-ott": 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
|
auth *Authority
|
||||||
opts *RevokeOptions
|
opts *RevokeOptions
|
||||||
err error
|
err error
|
||||||
res []interface{}
|
|
||||||
}
|
}
|
||||||
tests := map[string]func(t *testing.T) *authorizeTest{
|
tests := map[string]func(t *testing.T) *authorizeTest{
|
||||||
"fail/token/invalid-ott": 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
|
auth *Authority
|
||||||
ott string
|
ott string
|
||||||
err *apiError
|
err *apiError
|
||||||
res []interface{}
|
|
||||||
}
|
}
|
||||||
tests := map[string]func(t *testing.T) *authorizeTest{
|
tests := map[string]func(t *testing.T) *authorizeTest{
|
||||||
"fail/invalid-ott": func(t *testing.T) *authorizeTest {
|
"fail/invalid-ott": func(t *testing.T) *authorizeTest {
|
||||||
|
@ -452,7 +449,7 @@ func TestAuthority_AuthorizeSign(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assert.Nil(t, tc.err) {
|
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
|
auth *Authority
|
||||||
ott string
|
ott string
|
||||||
err *apiError
|
err *apiError
|
||||||
res []interface{}
|
|
||||||
}
|
}
|
||||||
tests := map[string]func(t *testing.T) *authorizeTest{
|
tests := map[string]func(t *testing.T) *authorizeTest{
|
||||||
"fail/invalid-ott": func(t *testing.T) *authorizeTest {
|
"fail/invalid-ott": func(t *testing.T) *authorizeTest {
|
||||||
|
@ -545,7 +541,7 @@ func TestAuthority_Authorize(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assert.Nil(t, tc.err) {
|
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,
|
return append(so,
|
||||||
|
defaultPublicKeyValidator{},
|
||||||
commonNameValidator(payload.Claims.Subject),
|
commonNameValidator(payload.Claims.Subject),
|
||||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||||
newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID),
|
newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID),
|
||||||
|
|
|
@ -328,11 +328,11 @@ func TestAWS_AuthorizeSign(t *testing.T) {
|
||||||
wantLen int
|
wantLen int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1}, 4, false},
|
{"ok", p1, args{t1}, 5, false},
|
||||||
{"ok", p2, args{t2}, 6, false},
|
{"ok", p2, args{t2}, 7, false},
|
||||||
{"ok", p2, args{t2Hostname}, 6, false},
|
{"ok", p2, args{t2Hostname}, 7, false},
|
||||||
{"ok", p2, args{t2PrivateIP}, 6, false},
|
{"ok", p2, args{t2PrivateIP}, 7, false},
|
||||||
{"ok", p1, args{t4}, 4, false},
|
{"ok", p1, args{t4}, 5, false},
|
||||||
{"fail account", p3, args{t3}, 0, true},
|
{"fail account", p3, args{t3}, 0, true},
|
||||||
{"fail token", p1, args{"token"}, 0, true},
|
{"fail token", p1, args{"token"}, 0, true},
|
||||||
{"fail subject", p1, args{failSubject}, 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,
|
return append(so,
|
||||||
|
defaultPublicKeyValidator{},
|
||||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||||
newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID),
|
newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID),
|
||||||
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
||||||
|
|
|
@ -283,9 +283,9 @@ func TestAzure_AuthorizeSign(t *testing.T) {
|
||||||
wantLen int
|
wantLen int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1}, 3, false},
|
{"ok", p1, args{t1}, 4, false},
|
||||||
{"ok", p2, args{t2}, 5, false},
|
{"ok", p2, args{t2}, 6, false},
|
||||||
{"ok", p1, args{t11}, 3, false},
|
{"ok", p1, args{t11}, 4, false},
|
||||||
{"fail tenant", p3, args{t3}, 0, true},
|
{"fail tenant", p3, args{t3}, 0, true},
|
||||||
{"fail resource group", p4, args{t4}, 0, true},
|
{"fail resource group", p4, args{t4}, 0, true},
|
||||||
{"fail token", p1, args{"token"}, 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,
|
return append(so,
|
||||||
|
defaultPublicKeyValidator{},
|
||||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||||
newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName),
|
newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName),
|
||||||
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
||||||
|
|
|
@ -313,9 +313,9 @@ func TestGCP_AuthorizeSign(t *testing.T) {
|
||||||
wantLen int
|
wantLen int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1}, 3, false},
|
{"ok", p1, args{t1}, 4, false},
|
||||||
{"ok", p2, args{t2}, 5, false},
|
{"ok", p2, args{t2}, 6, false},
|
||||||
{"ok", p3, args{t3}, 3, false},
|
{"ok", p3, args{t3}, 4, false},
|
||||||
{"fail token", p1, args{"token"}, 0, true},
|
{"fail token", p1, args{"token"}, 0, true},
|
||||||
{"fail key", p1, args{failKey}, 0, true},
|
{"fail key", p1, args{failKey}, 0, true},
|
||||||
{"fail iss", p1, args{failIss}, 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}
|
claims.SANs = []string{claims.Subject}
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsNames, ips := x509util.SplitSANs(claims.SANs)
|
dnsNames, ips, emails := x509util.SplitSANs(claims.SANs)
|
||||||
return []SignOption{
|
return []SignOption{
|
||||||
|
defaultPublicKeyValidator{},
|
||||||
commonNameValidator(claims.Subject),
|
commonNameValidator(claims.Subject),
|
||||||
dnsNamesValidator(dnsNames),
|
dnsNamesValidator(dnsNames),
|
||||||
ipAddressesValidator(ips),
|
ipAddressesValidator(ips),
|
||||||
|
emailAddressesValidator(emails),
|
||||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||||
newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID),
|
newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID),
|
||||||
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
||||||
|
|
|
@ -276,14 +276,14 @@ func TestJWK_AuthorizeSign(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assert.NotNil(t, got) {
|
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)
|
cnv, ok := _cnv.(commonNameValidator)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equals(t, string(cnv), "subject")
|
assert.Equals(t, string(cnv), "subject")
|
||||||
|
|
||||||
_dnv := got[1]
|
_dnv := got[2]
|
||||||
dnv, ok := _dnv.(dnsNamesValidator)
|
dnv, ok := _dnv.(dnsNamesValidator)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
if tt.name == "ok-sans" {
|
if tt.name == "ok-sans" {
|
||||||
|
|
|
@ -283,12 +283,18 @@ func (o *OIDC) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return []SignOption{
|
so := []SignOption{
|
||||||
emailOnlyIdentity(claims.Email),
|
defaultPublicKeyValidator{},
|
||||||
profileDefaultDuration(o.claimer.DefaultTLSCertDuration()),
|
profileDefaultDuration(o.claimer.DefaultTLSCertDuration()),
|
||||||
newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID),
|
newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID),
|
||||||
newValidityValidator(o.claimer.MinTLSCertDuration(), o.claimer.MaxTLSCertDuration()),
|
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.
|
// AuthorizeRenewal returns an error if the renewal is disabled.
|
||||||
|
|
|
@ -291,7 +291,7 @@ func TestOIDC_AuthorizeSign(t *testing.T) {
|
||||||
if tt.name == "admin" {
|
if tt.name == "admin" {
|
||||||
assert.Len(t, 3, got)
|
assert.Len(t, 3, got)
|
||||||
} else {
|
} else {
|
||||||
assert.Len(t, 4, got)
|
assert.Len(t, 5, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -152,7 +152,16 @@ func (l *List) UnmarshalJSON(data []byte) error {
|
||||||
case "azure":
|
case "azure":
|
||||||
p = &Azure{}
|
p = &Azure{}
|
||||||
default:
|
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 {
|
if err := json.Unmarshal(data, p); err != nil {
|
||||||
return errors.Errorf("error unmarshaling provisioner")
|
return errors.Errorf("error unmarshaling provisioner")
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package provisioner
|
package provisioner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
|
@ -10,6 +12,7 @@ import (
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/smallstep/cli/crypto/x509util"
|
"github.com/smallstep/cli/crypto/x509util"
|
||||||
|
"golang.org/x/crypto/ed25519"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options contains the options that can be passed to the Sign method.
|
// 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:
|
case len(req.EmailAddresses) == 0:
|
||||||
return errors.New("certificate request does not contain any email address")
|
return errors.New("certificate request does not contain any email address")
|
||||||
case len(req.EmailAddresses) > 1:
|
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] == "":
|
case req.EmailAddresses[0] == "":
|
||||||
return errors.New("certificate request cannot contain an empty email address")
|
return errors.New("certificate request cannot contain an empty email address")
|
||||||
case req.EmailAddresses[0] != string(e):
|
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.
|
// commonNameValidator validates the common name of a certificate request.
|
||||||
type commonNameValidator string
|
type commonNameValidator string
|
||||||
|
|
||||||
|
@ -157,6 +177,26 @@ func (v ipAddressesValidator) Valid(req *x509.CertificateRequest) error {
|
||||||
return nil
|
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.
|
// validityValidator validates the certificate temporal validity settings.
|
||||||
type validityValidator struct {
|
type validityValidator struct {
|
||||||
min time.Duration
|
min time.Duration
|
||||||
|
|
|
@ -7,6 +7,12 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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) {
|
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) {
|
func Test_commonNameValidator_Valid(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
req *x509.CertificateRequest
|
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) {
|
func Test_dnsNamesValidator_Valid(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
req *x509.CertificateRequest
|
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"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"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 {
|
"fail store cert in db": func(t *testing.T) *signTest {
|
||||||
csr := getCSR(t, priv)
|
csr := getCSR(t, priv)
|
||||||
_a := testAuthority(t)
|
_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")
|
return nil, nil, errors.Wrap(err, "error generating key")
|
||||||
}
|
}
|
||||||
|
|
||||||
var emails []string
|
dnsNames, ips, emails := x509util.SplitSANs(claims.SANs)
|
||||||
dnsNames, ips := x509util.SplitSANs(claims.SANs)
|
|
||||||
if claims.Email != "" {
|
if claims.Email != "" {
|
||||||
emails = append(emails, claims.Email)
|
emails = append(emails, claims.Email)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -11,6 +12,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
@ -54,12 +56,64 @@ func printFullVersion() {
|
||||||
fmt.Printf("Release Date: %s\n", releaseDate())
|
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() {
|
func main() {
|
||||||
// Override global framework components
|
// Override global framework components
|
||||||
cli.VersionPrinter = func(c *cli.Context) {
|
cli.VersionPrinter = func(c *cli.Context) {
|
||||||
printFullVersion()
|
printFullVersion()
|
||||||
}
|
}
|
||||||
cli.AppHelpTemplate = usage.AppHelpTemplate
|
cli.AppHelpTemplate = appHelpTemplate
|
||||||
cli.SubcommandHelpTemplate = usage.SubcommandHelpTemplate
|
cli.SubcommandHelpTemplate = usage.SubcommandHelpTemplate
|
||||||
cli.CommandHelpTemplate = usage.CommandHelpTemplate
|
cli.CommandHelpTemplate = usage.CommandHelpTemplate
|
||||||
cli.HelpPrinter = usage.HelpPrinter
|
cli.HelpPrinter = usage.HelpPrinter
|
||||||
|
@ -118,7 +172,7 @@ intermediate private key.`,
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []cli.Command{
|
||||||
{
|
{
|
||||||
Name: "version",
|
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
|
// Command prints out the current version of the tool
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
printFullVersion()
|
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
|
// Hack to be able to run a the top action as a subcommand
|
||||||
cmd := cli.Command{Name: "start", Action: startAction, Flags: app.Flags}
|
cmd := cli.Command{Name: "start", Action: startAction, Flags: app.Flags}
|
||||||
set := flag.NewFlagSet(app.Name, flag.ContinueOnError)
|
set := flag.NewFlagSet(app.Name, flag.ContinueOnError)
|
||||||
set.Parse(os.Args)
|
set.Parse(os.Args)
|
||||||
ctx = cli.NewContext(app, set, nil)
|
ctx := cli.NewContext(app, set, nil)
|
||||||
return cmd.Run(ctx)
|
return cmd.Run(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue