From 29f5a35965c6b838a7c4eeb416507166e8f499e0 Mon Sep 17 00:00:00 2001 From: Gary Belvin Date: Fri, 12 Nov 2021 13:00:32 -0500 Subject: [PATCH 01/34] simplify flags --- cmd/step-pkcs11-init/main.go | 65 +++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/cmd/step-pkcs11-init/main.go b/cmd/step-pkcs11-init/main.go index 0db1e4d9..53d27208 100644 --- a/cmd/step-pkcs11-init/main.go +++ b/cmd/step-pkcs11-init/main.go @@ -32,7 +32,7 @@ import ( // Config is a mapping of the cli flags. type Config struct { KMS string - RootOnly bool + GenerateRoot bool RootObject string RootKeyObject string RootSubject string @@ -59,11 +59,9 @@ func (c *Config) Validate() error { case c.KMS == "": return errors.New("flag `--kms` is required") case c.RootFile != "" && c.KeyFile == "": - return errors.New("flag `--root` requires flag `--key`") + return errors.New("flag `--root-cert-file` requires flag `--key`") case c.KeyFile != "" && c.RootFile == "": - return errors.New("flag `--key` requires flag `--root`") - case c.RootOnly && c.RootFile != "": - return errors.New("flag `--root-only` is incompatible with flag `--root`") + return errors.New("flag `--key` requires flag `--root-cert-file`") case c.RootFile == "" && c.RootObject == "": return errors.New("one of flag `--root` or `--root-cert` is required") case c.RootFile == "" && c.RootKeyObject == "": @@ -73,7 +71,7 @@ func (c *Config) Validate() error { c.RootObject = "" c.RootKeyObject = "" } - if c.RootOnly { + if c.CrtKeyPath != "" { c.CrtObject = "" c.CrtKeyObject = "" } @@ -101,20 +99,24 @@ func main() { var c Config flag.StringVar(&c.KMS, "kms", kmsuri, "PKCS #11 URI with the module-path and token to connect to the module.") flag.StringVar(&c.Pin, "pin", "", "PKCS #11 PIN") - flag.StringVar(&c.RootObject, "root-cert", "pkcs11:id=7330;object=root-cert", "PKCS #11 URI with object id and label to store the root certificate.") - flag.StringVar(&c.RootPath, "root-cert-path", "root_ca.crt", "Location to write the root certificate.") - flag.StringVar(&c.RootKeyObject, "root-key", "pkcs11:id=7330;object=root-key", "PKCS #11 URI with object id and label to store the root key.") + // Option 1: Generate new root + flag.BoolVar(&c.GenerateRoot, "root-gen", true, "Enable the generation of a root key.") + flag.StringVar(&c.RootFile, "root-cert-file", "", "Path to the root certificate to use.") + flag.StringVar(&c.RootObject, "root-cert-obj", "pkcs11:id=7330;object=root-cert", "PKCS #11 URI with object id and label to store the root certificate.") + flag.StringVar(&c.RootKeyObject, "root-key-obj", "pkcs11:id=7330;object=root-key", "PKCS #11 URI with object id and label to store the root key.") flag.StringVar(&c.RootSubject, "root-name", "PKCS #11 Smallstep Root", "Subject and Issuer of the root certificate.") + // Option 2: Read root from disk and sign intermediate + flag.StringVar(&c.RootPath, "root-cert-path", "root_ca.crt", "Location to write the root certificate.") + flag.StringVar(&c.KeyFile, "root-key-file", "", "Path to the root key to use.") + // Option 3: Generate certificate signing request flag.StringVar(&c.CrtObject, "crt-cert", "pkcs11:id=7331;object=intermediate-cert", "PKCS #11 URI with object id and label to store the intermediate certificate.") flag.StringVar(&c.CrtPath, "crt-cert-path", "intermediate_ca.crt", "Location to write the intermediate certificate.") flag.StringVar(&c.CrtKeyObject, "crt-key", "pkcs11:id=7331;object=intermediate-key", "PKCS #11 URI with object id and label to store the intermediate certificate.") flag.StringVar(&c.CrtSubject, "crt-name", "PKCS #11 Smallstep Intermediate", "Subject of the intermediate certificate.") - flag.StringVar(&c.CrtKeyPath, "crt-key-path", "intermediate_ca_key", "Location to write the intermediate private key.") + flag.StringVar(&c.CrtKeyPath, "crt-key-path", "", "Location to write the intermediate private key.") flag.StringVar(&c.SSHHostKeyObject, "ssh-host-key", "pkcs11:id=7332;object=ssh-host-key", "PKCS #11 URI with object id and label to store the key used to sign SSH host certificates.") flag.StringVar(&c.SSHUserKeyObject, "ssh-user-key", "pkcs11:id=7333;object=ssh-user-key", "PKCS #11 URI with object id and label to store the key used to sign SSH user certificates.") - flag.BoolVar(&c.RootOnly, "root-only", false, "Store only only the root certificate and sign and intermediate.") - flag.StringVar(&c.RootFile, "root", "", "Path to the root certificate to use.") - flag.StringVar(&c.KeyFile, "key", "", "Path to the root key to use.") + flag.BoolVar(&c.EnableSSH, "ssh", false, "Enable the creation of ssh keys.") flag.BoolVar(&c.NoCerts, "no-certs", false, "Do not store certificates in the module.") flag.BoolVar(&c.Force, "force", false, "Force the delete of previous keys.") @@ -276,22 +278,8 @@ func createPKI(k kms.KeyManager, c Config) error { // Root Certificate var signer crypto.Signer var root *x509.Certificate - if c.RootFile != "" && c.KeyFile != "" { - root, err = pemutil.ReadCertificate(c.RootFile) - if err != nil { - return err - } - - key, err := pemutil.Read(c.KeyFile) - if err != nil { - return err - } - - var ok bool - if signer, ok = key.(crypto.Signer); !ok { - return errors.Errorf("key type '%T' does not implement a signer", key) - } - } else { + switch { + case c.GenerateRoot: resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ Name: c.RootKeyObject, SignatureAlgorithm: apiv1.ECDSAWithSHA256, @@ -350,12 +338,27 @@ func createPKI(k kms.KeyManager, c Config) error { ui.PrintSelected("Root Key", resp.Name) ui.PrintSelected("Root Certificate", c.RootPath) + case c.RootFile != "" && c.KeyFile != "": // Read Root From File + root, err = pemutil.ReadCertificate(c.RootFile) + if err != nil { + return err + } + + key, err := pemutil.Read(c.KeyFile) + if err != nil { + return err + } + + var ok bool + if signer, ok = key.(crypto.Signer); !ok { + return errors.Errorf("key type '%T' does not implement a signer", key) + } } // Intermediate Certificate var keyName string var publicKey crypto.PublicKey - if c.RootOnly { + if c.CrtKeyPath != "" { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return errors.Wrap(err, "error creating intermediate key") @@ -427,7 +430,7 @@ func createPKI(k kms.KeyManager, c Config) error { return err } - if c.RootOnly { + if c.CrtKeyPath != "" { ui.PrintSelected("Intermediate Key", c.CrtKeyPath) } else { ui.PrintSelected("Intermediate Key", keyName) From bbb327c8c526aaf3b16fb595975c53774c1c5d84 Mon Sep 17 00:00:00 2001 From: Gary Belvin Date: Fri, 12 Nov 2021 14:09:17 -0500 Subject: [PATCH 02/34] Make a csr if there's not a root --- cmd/step-pkcs11-init/main.go | 97 +++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 36 deletions(-) diff --git a/cmd/step-pkcs11-init/main.go b/cmd/step-pkcs11-init/main.go index 53d27208..613b8208 100644 --- a/cmd/step-pkcs11-init/main.go +++ b/cmd/step-pkcs11-init/main.go @@ -358,6 +358,7 @@ func createPKI(k kms.KeyManager, c Config) error { // Intermediate Certificate var keyName string var publicKey crypto.PublicKey + var intSigner crypto.Signer if c.CrtKeyPath != "" { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { @@ -376,6 +377,7 @@ func createPKI(k kms.KeyManager, c Config) error { } publicKey = priv.Public() + intSigner = priv } else { resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ Name: c.CrtKeyObject, @@ -387,47 +389,70 @@ func createPKI(k kms.KeyManager, c Config) error { } publicKey = resp.PublicKey keyName = resp.Name - } - template := &x509.Certificate{ - IsCA: true, - NotBefore: now, - NotAfter: now.Add(time.Hour * 24 * 365 * 10), - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, - BasicConstraintsValid: true, - MaxPathLen: 0, - MaxPathLenZero: true, - Issuer: root.Subject, - Subject: pkix.Name{CommonName: c.CrtSubject}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(publicKey), - } - - b, err := x509.CreateCertificate(rand.Reader, template, root, publicKey, signer) - if err != nil { - return err - } - - intermediate, err := x509.ParseCertificate(b) - if err != nil { - return errors.Wrap(err, "error parsing intermediate certificate") - } - - if cm, ok := k.(kms.CertificateManager); ok && !c.NoCerts { - if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ - Name: c.CrtObject, - Certificate: intermediate, - Extractable: c.Extractable, - }); err != nil { + intSigner, err = k.CreateSigner(&resp.CreateSignerRequest) + if err != nil { return err } } - if err := fileutil.WriteFile(c.CrtPath, pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); err != nil { - return err + if root != nil { + template := &x509.Certificate{ + IsCA: true, + NotBefore: now, + NotAfter: now.Add(time.Hour * 24 * 365 * 10), + KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, + BasicConstraintsValid: true, + MaxPathLen: 0, + MaxPathLenZero: true, + Issuer: root.Subject, + Subject: pkix.Name{CommonName: c.CrtSubject}, + SerialNumber: mustSerialNumber(), + SubjectKeyId: mustSubjectKeyID(publicKey), + } + + b, err := x509.CreateCertificate(rand.Reader, template, root, publicKey, signer) + if err != nil { + return err + } + + intermediate, err := x509.ParseCertificate(b) + if err != nil { + return errors.Wrap(err, "error parsing intermediate certificate") + } + + if cm, ok := k.(kms.CertificateManager); ok && !c.NoCerts { + if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ + Name: c.CrtObject, + Certificate: intermediate, + Extractable: c.Extractable, + }); err != nil { + return err + } + } + + if err := fileutil.WriteFile(c.CrtPath, pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: b, + }), 0600); err != nil { + return err + } + } else { // No root available, generate CSR for external root. + csrTemplate := x509.CertificateRequest{ + Subject: pkix.Name{CommonName: c.CrtSubject}, + SignatureAlgorithm: x509.ECDSAWithSHA256, + } + // step: generate the csr request + csrCertificate, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, intSigner) + if err != nil { + return err + } + if err := fileutil.WriteFile(c.CrtPath, pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE REQUEST", + Bytes: csrCertificate, + }), 0600); err != nil { + return err + } } if c.CrtKeyPath != "" { From e7a988b2cd3e135d3482cc20146f1de8cac38026 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Sat, 13 Nov 2021 00:46:34 +0100 Subject: [PATCH 03/34] Pin golangci-lint to v1.43.0 and fix issues --- .github/workflows/test.yml | 2 +- .golangci.yml | 6 ---- acme/api/account_test.go | 8 ++--- acme/api/handler.go | 2 +- acme/api/handler_test.go | 10 +++--- acme/api/middleware.go | 6 ++-- acme/api/middleware_test.go | 19 +++++------ acme/api/order_test.go | 8 ++--- acme/challenge.go | 4 +-- acme/challenge_test.go | 11 +++---- api/api_test.go | 24 +++++++------- api/revoke_test.go | 4 +-- api/ssh_test.go | 42 ++++++++++++------------ api/utils.go | 3 +- authority/authority_test.go | 8 ++--- authority/export.go | 4 +-- authority/provisioner/aws.go | 11 ++++--- authority/provisioner/azure.go | 4 +-- authority/provisioner/azure_test.go | 2 +- authority/provisioner/gcp.go | 4 +-- authority/provisioner/utils_test.go | 10 +++--- authority/provisioners.go | 6 ++-- authority/tls_test.go | 18 +++++----- ca/acmeClient.go | 5 ++- ca/acmeClient_test.go | 20 +++++------ ca/adminClient.go | 10 +++--- ca/bootstrap_test.go | 10 +++--- ca/ca_test.go | 12 +++---- ca/client.go | 7 ++-- ca/identity/client.go | 6 ++-- ca/identity/client_test.go | 6 ++-- ca/identity/identity.go | 13 ++++---- ca/provisioner_test.go | 4 +-- ca/renew.go | 26 +++++++-------- ca/tls_options_test.go | 20 +++++------ ca/tls_test.go | 10 +++--- cas/stepcas/stepcas_test.go | 4 +-- commands/app.go | 9 +++-- commands/export.go | 6 ++-- examples/basic-federation/client/main.go | 4 +-- examples/bootstrap-client/client.go | 4 +-- kms/cloudkms/cloudkms_test.go | 8 ++--- kms/cloudkms/signer_test.go | 8 ++--- kms/softkms/softkms_test.go | 8 ++--- kms/sshagentkms/sshagentkms_test.go | 15 ++++----- kms/uri/uri.go | 4 +-- scep/api/api.go | 3 +- templates/templates.go | 3 +- 48 files changed, 213 insertions(+), 228 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 96655664..bfc861c7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,7 +33,7 @@ jobs: uses: golangci/golangci-lint-action@v2 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: 'latest' + version: 'v1.43.0' # Optional: working directory, useful for monorepos # working-directory: somedir diff --git a/.golangci.yml b/.golangci.yml index cf389517..67aac2df 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -73,9 +73,3 @@ issues: - error strings should not be capitalized or end with punctuation or a newline - Wrapf call needs 1 arg but has 2 args - cs.NegotiatedProtocolIsMutual is deprecated -# golangci.com configuration -# https://github.com/golangci/golangci/wiki/Configuration -service: - golangci-lint-version: 1.19.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" diff --git a/acme/api/account_test.go b/acme/api/account_test.go index a45751a0..abee97a2 100644 --- a/acme/api/account_test.go +++ b/acme/api/account_test.go @@ -5,7 +5,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http/httptest" "net/url" "testing" @@ -263,7 +263,7 @@ func TestHandler_GetOrdersByAccountID(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -468,7 +468,7 @@ func TestHandler_NewAccount(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -668,7 +668,7 @@ func TestHandler_GetOrUpdateAccount(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) diff --git a/acme/api/handler.go b/acme/api/handler.go index b05bd0c4..394986e1 100644 --- a/acme/api/handler.go +++ b/acme/api/handler.go @@ -17,7 +17,7 @@ import ( ) func link(url, typ string) string { - return fmt.Sprintf("<%s>;rel=\"%s\"", url, typ) + return fmt.Sprintf("<%s>;rel=%q", url, typ) } // Clock that returns time in UTC rounded to seconds. diff --git a/acme/api/handler_test.go b/acme/api/handler_test.go index 8112ad4c..14e00f12 100644 --- a/acme/api/handler_test.go +++ b/acme/api/handler_test.go @@ -7,7 +7,7 @@ import ( "encoding/json" "encoding/pem" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "net/url" @@ -89,7 +89,7 @@ func TestHandler_GetDirectory(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -261,7 +261,7 @@ func TestHandler_GetAuthorization(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -404,7 +404,7 @@ func TestHandler_GetCertificate(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -660,7 +660,7 @@ func TestHandler_GetChallenge(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) diff --git a/acme/api/middleware.go b/acme/api/middleware.go index bc67dbc6..be531ca8 100644 --- a/acme/api/middleware.go +++ b/acme/api/middleware.go @@ -4,7 +4,7 @@ import ( "context" "crypto/rsa" "errors" - "io/ioutil" + "io" "net/http" "net/url" "strings" @@ -118,7 +118,7 @@ func (h *Handler) verifyContentType(next nextHTTP) nextHTTP { // parseJWS is a middleware that parses a request body into a JSONWebSignature struct. func (h *Handler) parseJWS(next nextHTTP) nextHTTP { return func(w http.ResponseWriter, r *http.Request) { - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) if err != nil { api.WriteError(w, acme.WrapErrorISE(err, "failed to read request body")) return @@ -378,7 +378,7 @@ func (h *Handler) verifyAndExtractJWSPayload(next nextHTTP) nextHTTP { } ctx = context.WithValue(ctx, payloadContextKey, &payloadInfo{ value: payload, - isPostAsGet: string(payload) == "", + isPostAsGet: len(payload) == 0, isEmptyJSON: string(payload) == "{}", }) next(w, r.WithContext(ctx)) diff --git a/acme/api/middleware_test.go b/acme/api/middleware_test.go index e8d22d53..9b36d316 100644 --- a/acme/api/middleware_test.go +++ b/acme/api/middleware_test.go @@ -8,7 +8,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/http/httptest" "net/url" @@ -148,7 +147,7 @@ func TestHandler_addNonce(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -205,7 +204,7 @@ func TestHandler_addDirLink(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -332,7 +331,7 @@ func TestHandler_verifyContentType(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -400,7 +399,7 @@ func TestHandler_isPostAsGet(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -490,7 +489,7 @@ func TestHandler_parseJWS(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -689,7 +688,7 @@ func TestHandler_verifyAndExtractJWSPayload(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -891,7 +890,7 @@ func TestHandler_lookupJWK(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -1087,7 +1086,7 @@ func TestHandler_extractJWK(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -1454,7 +1453,7 @@ func TestHandler_validateJWS(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) diff --git a/acme/api/order_test.go b/acme/api/order_test.go index 3c6d768f..1ce034e7 100644 --- a/acme/api/order_test.go +++ b/acme/api/order_test.go @@ -7,7 +7,7 @@ import ( "encoding/base64" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http/httptest" "net/url" "reflect" @@ -430,7 +430,7 @@ func TestHandler_GetOrder(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -1343,7 +1343,7 @@ func TestHandler_NewOrder(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) @@ -1633,7 +1633,7 @@ func TestHandler_FinalizeOrder(t *testing.T) { assert.Equals(t, res.StatusCode, tc.statusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) diff --git a/acme/challenge.go b/acme/challenge.go index b880708c..bfe1937d 100644 --- a/acme/challenge.go +++ b/acme/challenge.go @@ -12,7 +12,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net" "net/http" "net/url" @@ -89,7 +89,7 @@ func http01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWeb "error doing http GET for url %s with status code %d", u, resp.StatusCode)) } - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return WrapErrorISE(err, "error reading "+ "response body for url %s", u) diff --git a/acme/challenge_test.go b/acme/challenge_test.go index a522790f..d8ce4d76 100644 --- a/acme/challenge_test.go +++ b/acme/challenge_test.go @@ -15,7 +15,6 @@ import ( "encoding/hex" "fmt" "io" - "io/ioutil" "math/big" "net" "net/http" @@ -707,7 +706,7 @@ func TestHTTP01Validate(t *testing.T) { vo: &ValidateChallengeOptions{ HTTPGet: func(url string) (*http.Response, error) { return &http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString("foo")), + Body: io.NopCloser(bytes.NewBufferString("foo")), }, nil }, }, @@ -733,7 +732,7 @@ func TestHTTP01Validate(t *testing.T) { vo: &ValidateChallengeOptions{ HTTPGet: func(url string) (*http.Response, error) { return &http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString("foo")), + Body: io.NopCloser(bytes.NewBufferString("foo")), }, nil }, }, @@ -775,7 +774,7 @@ func TestHTTP01Validate(t *testing.T) { vo: &ValidateChallengeOptions{ HTTPGet: func(url string) (*http.Response, error) { return &http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString("foo")), + Body: io.NopCloser(bytes.NewBufferString("foo")), }, nil }, }, @@ -818,7 +817,7 @@ func TestHTTP01Validate(t *testing.T) { vo: &ValidateChallengeOptions{ HTTPGet: func(url string) (*http.Response, error) { return &http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString(expKeyAuth)), + Body: io.NopCloser(bytes.NewBufferString(expKeyAuth)), }, nil }, }, @@ -860,7 +859,7 @@ func TestHTTP01Validate(t *testing.T) { vo: &ValidateChallengeOptions{ HTTPGet: func(url string) (*http.Response, error) { return &http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString(expKeyAuth)), + Body: io.NopCloser(bytes.NewBufferString(expKeyAuth)), }, nil }, }, diff --git a/api/api_test.go b/api/api_test.go index 89596165..05d592f0 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -16,7 +16,7 @@ import ( "encoding/json" "encoding/pem" "fmt" - "io/ioutil" + "io" "math/big" "net/http" "net/http/httptest" @@ -788,7 +788,7 @@ func Test_caHandler_Health(t *testing.T) { t.Errorf("caHandler.Health StatusCode = %d, wants 200", res.StatusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.Health unexpected error = %v", err) @@ -829,7 +829,7 @@ func Test_caHandler_Root(t *testing.T) { t.Errorf("caHandler.Root StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.Root unexpected error = %v", err) @@ -902,7 +902,7 @@ func Test_caHandler_Sign(t *testing.T) { t.Errorf("caHandler.Root StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.Root unexpected error = %v", err) @@ -954,7 +954,7 @@ func Test_caHandler_Renew(t *testing.T) { t.Errorf("caHandler.Renew StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.Renew unexpected error = %v", err) @@ -1015,7 +1015,7 @@ func Test_caHandler_Rekey(t *testing.T) { t.Errorf("caHandler.Rekey StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.Rekey unexpected error = %v", err) @@ -1038,12 +1038,12 @@ func Test_caHandler_Provisioners(t *testing.T) { r *http.Request } - req, err := http.NewRequest("GET", "http://example.com/provisioners?cursor=foo&limit=20", nil) + req, err := http.NewRequest("GET", "http://example.com/provisioners?cursor=foo&limit=20", http.NoBody) if err != nil { t.Fatal(err) } - reqLimitFail, err := http.NewRequest("GET", "http://example.com/provisioners?limit=abc", nil) + reqLimitFail, err := http.NewRequest("GET", "http://example.com/provisioners?limit=abc", http.NoBody) if err != nil { t.Fatal(err) } @@ -1105,7 +1105,7 @@ func Test_caHandler_Provisioners(t *testing.T) { if res.StatusCode != tt.statusCode { t.Errorf("caHandler.Provisioners StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.Provisioners unexpected error = %v", err) @@ -1175,7 +1175,7 @@ func Test_caHandler_ProvisionerKey(t *testing.T) { if res.StatusCode != tt.statusCode { t.Errorf("caHandler.Provisioners StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.Provisioners unexpected error = %v", err) @@ -1225,7 +1225,7 @@ func Test_caHandler_Roots(t *testing.T) { t.Errorf("caHandler.Roots StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.Roots unexpected error = %v", err) @@ -1271,7 +1271,7 @@ func Test_caHandler_Federation(t *testing.T) { t.Errorf("caHandler.Federation StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.Federation unexpected error = %v", err) diff --git a/api/revoke_test.go b/api/revoke_test.go index f44acebf..4ed4e3fe 100644 --- a/api/revoke_test.go +++ b/api/revoke_test.go @@ -6,7 +6,7 @@ import ( "crypto/tls" "crypto/x509" "encoding/json" - "io/ioutil" + "io" "net/http" "net/http/httptest" "strings" @@ -233,7 +233,7 @@ func Test_caHandler_Revoke(t *testing.T) { assert.Equals(t, tc.statusCode, res.StatusCode) - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() assert.FatalError(t, err) diff --git a/api/ssh_test.go b/api/ssh_test.go index a2e8748f..a3d7da0d 100644 --- a/api/ssh_test.go +++ b/api/ssh_test.go @@ -10,7 +10,7 @@ import ( "encoding/base64" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "reflect" @@ -299,14 +299,14 @@ func Test_caHandler_SSHSign(t *testing.T) { body []byte statusCode int }{ - {"ok-user", userReq, nil, user, nil, nil, nil, nil, nil, []byte(fmt.Sprintf(`{"crt":"%s"}`, userB64)), http.StatusCreated}, - {"ok-host", hostReq, nil, host, nil, nil, nil, nil, nil, []byte(fmt.Sprintf(`{"crt":"%s"}`, hostB64)), http.StatusCreated}, - {"ok-user-add", userAddReq, nil, user, nil, user, nil, nil, nil, []byte(fmt.Sprintf(`{"crt":"%s","addUserCrt":"%s"}`, userB64, userB64)), http.StatusCreated}, - {"ok-user-identity", userIdentityReq, nil, user, nil, user, nil, identityCerts, nil, []byte(fmt.Sprintf(`{"crt":"%s","identityCrt":[%s]}`, userB64, identityCertsPEM)), http.StatusCreated}, + {"ok-user", userReq, nil, user, nil, nil, nil, nil, nil, []byte(fmt.Sprintf(`{"crt":%q}`, userB64)), http.StatusCreated}, + {"ok-host", hostReq, nil, host, nil, nil, nil, nil, nil, []byte(fmt.Sprintf(`{"crt":%q}`, hostB64)), http.StatusCreated}, + {"ok-user-add", userAddReq, nil, user, nil, user, nil, nil, nil, []byte(fmt.Sprintf(`{"crt":%q,"addUserCrt":%q}`, userB64, userB64)), http.StatusCreated}, + {"ok-user-identity", userIdentityReq, nil, user, nil, user, nil, identityCerts, nil, []byte(fmt.Sprintf(`{"crt":%q,"identityCrt":[%s]}`, userB64, identityCertsPEM)), http.StatusCreated}, {"fail-body", []byte("bad-json"), nil, nil, nil, nil, nil, nil, nil, nil, http.StatusBadRequest}, {"fail-validate", []byte("{}"), nil, nil, nil, nil, nil, nil, nil, nil, http.StatusBadRequest}, {"fail-publicKey", []byte(`{"publicKey":"Zm9v","ott":"ott"}`), nil, nil, nil, nil, nil, nil, nil, nil, http.StatusBadRequest}, - {"fail-publicKey", []byte(fmt.Sprintf(`{"publicKey":"%s","ott":"ott","addUserPublicKey":"Zm9v"}`, base64.StdEncoding.EncodeToString(user.Key.Marshal()))), nil, nil, nil, nil, nil, nil, nil, nil, http.StatusBadRequest}, + {"fail-publicKey", []byte(fmt.Sprintf(`{"publicKey":%q,"ott":"ott","addUserPublicKey":"Zm9v"}`, base64.StdEncoding.EncodeToString(user.Key.Marshal()))), nil, nil, nil, nil, nil, nil, nil, nil, http.StatusBadRequest}, {"fail-authorize", userReq, fmt.Errorf("an-error"), nil, nil, nil, nil, nil, nil, nil, http.StatusUnauthorized}, {"fail-signSSH", userReq, nil, nil, fmt.Errorf("an-error"), nil, nil, nil, nil, nil, http.StatusForbidden}, {"fail-SignSSHAddUser", userAddReq, nil, user, nil, nil, fmt.Errorf("an-error"), nil, nil, nil, http.StatusForbidden}, @@ -338,7 +338,7 @@ func Test_caHandler_SSHSign(t *testing.T) { t.Errorf("caHandler.SignSSH StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.SignSSH unexpected error = %v", err) @@ -368,10 +368,10 @@ func Test_caHandler_SSHRoots(t *testing.T) { body []byte statusCode int }{ - {"ok", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}, UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":["%s"],"hostKey":["%s"]}`, userB64, hostB64)), http.StatusOK}, - {"many", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host, host}, UserKeys: []ssh.PublicKey{user, user}}, nil, []byte(fmt.Sprintf(`{"userKey":["%s","%s"],"hostKey":["%s","%s"]}`, userB64, userB64, hostB64, hostB64)), http.StatusOK}, - {"user", &authority.SSHKeys{UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":["%s"]}`, userB64)), http.StatusOK}, - {"host", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}}, nil, []byte(fmt.Sprintf(`{"hostKey":["%s"]}`, hostB64)), http.StatusOK}, + {"ok", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}, UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":[%q],"hostKey":[%q]}`, userB64, hostB64)), http.StatusOK}, + {"many", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host, host}, UserKeys: []ssh.PublicKey{user, user}}, nil, []byte(fmt.Sprintf(`{"userKey":[%q,%q],"hostKey":[%q,%q]}`, userB64, userB64, hostB64, hostB64)), http.StatusOK}, + {"user", &authority.SSHKeys{UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":[%q]}`, userB64)), http.StatusOK}, + {"host", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}}, nil, []byte(fmt.Sprintf(`{"hostKey":[%q]}`, hostB64)), http.StatusOK}, {"empty", &authority.SSHKeys{}, nil, nil, http.StatusNotFound}, {"error", nil, fmt.Errorf("an error"), nil, http.StatusInternalServerError}, } @@ -392,7 +392,7 @@ func Test_caHandler_SSHRoots(t *testing.T) { t.Errorf("caHandler.SSHRoots StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.SSHRoots unexpected error = %v", err) @@ -422,10 +422,10 @@ func Test_caHandler_SSHFederation(t *testing.T) { body []byte statusCode int }{ - {"ok", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}, UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":["%s"],"hostKey":["%s"]}`, userB64, hostB64)), http.StatusOK}, - {"many", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host, host}, UserKeys: []ssh.PublicKey{user, user}}, nil, []byte(fmt.Sprintf(`{"userKey":["%s","%s"],"hostKey":["%s","%s"]}`, userB64, userB64, hostB64, hostB64)), http.StatusOK}, - {"user", &authority.SSHKeys{UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":["%s"]}`, userB64)), http.StatusOK}, - {"host", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}}, nil, []byte(fmt.Sprintf(`{"hostKey":["%s"]}`, hostB64)), http.StatusOK}, + {"ok", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}, UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":[%q],"hostKey":[%q]}`, userB64, hostB64)), http.StatusOK}, + {"many", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host, host}, UserKeys: []ssh.PublicKey{user, user}}, nil, []byte(fmt.Sprintf(`{"userKey":[%q,%q],"hostKey":[%q,%q]}`, userB64, userB64, hostB64, hostB64)), http.StatusOK}, + {"user", &authority.SSHKeys{UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":[%q]}`, userB64)), http.StatusOK}, + {"host", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}}, nil, []byte(fmt.Sprintf(`{"hostKey":[%q]}`, hostB64)), http.StatusOK}, {"empty", &authority.SSHKeys{}, nil, nil, http.StatusNotFound}, {"error", nil, fmt.Errorf("an error"), nil, http.StatusInternalServerError}, } @@ -446,7 +446,7 @@ func Test_caHandler_SSHFederation(t *testing.T) { t.Errorf("caHandler.SSHFederation StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.SSHFederation unexpected error = %v", err) @@ -506,7 +506,7 @@ func Test_caHandler_SSHConfig(t *testing.T) { t.Errorf("caHandler.SSHConfig StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.SSHConfig unexpected error = %v", err) @@ -553,7 +553,7 @@ func Test_caHandler_SSHCheckHost(t *testing.T) { t.Errorf("caHandler.SSHCheckHost StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.SSHCheckHost unexpected error = %v", err) @@ -604,7 +604,7 @@ func Test_caHandler_SSHGetHosts(t *testing.T) { t.Errorf("caHandler.SSHGetHosts StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.SSHGetHosts unexpected error = %v", err) @@ -659,7 +659,7 @@ func Test_caHandler_SSHBastion(t *testing.T) { t.Errorf("caHandler.SSHBastion StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("caHandler.SSHBastion unexpected error = %v", err) diff --git a/api/utils.go b/api/utils.go index bf45db53..fa56ed6b 100644 --- a/api/utils.go +++ b/api/utils.go @@ -3,7 +3,6 @@ package api import ( "encoding/json" "io" - "io/ioutil" "log" "net/http" @@ -102,7 +101,7 @@ func ReadJSON(r io.Reader, v interface{}) error { // ReadProtoJSON reads JSON from the request body and stores it in the value // pointed by v. func ReadProtoJSON(r io.Reader, m proto.Message) error { - data, err := ioutil.ReadAll(r) + data, err := io.ReadAll(r) if err != nil { return errs.Wrap(http.StatusBadRequest, err, "error reading request body") } diff --git a/authority/authority_test.go b/authority/authority_test.go index 1e18a24f..abb06cf4 100644 --- a/authority/authority_test.go +++ b/authority/authority_test.go @@ -7,8 +7,8 @@ import ( "crypto/x509" "encoding/hex" "fmt" - "io/ioutil" "net" + "os" "reflect" "testing" "time" @@ -195,7 +195,7 @@ func TestAuthority_GetDatabase(t *testing.T) { } func TestNewEmbedded(t *testing.T) { - caPEM, err := ioutil.ReadFile("testdata/certs/root_ca.crt") + caPEM, err := os.ReadFile("testdata/certs/root_ca.crt") assert.FatalError(t, err) crt, err := pemutil.ReadCertificate("testdata/certs/intermediate_ca.crt") @@ -268,7 +268,7 @@ func TestNewEmbedded(t *testing.T) { } func TestNewEmbedded_Sign(t *testing.T) { - caPEM, err := ioutil.ReadFile("testdata/certs/root_ca.crt") + caPEM, err := os.ReadFile("testdata/certs/root_ca.crt") assert.FatalError(t, err) crt, err := pemutil.ReadCertificate("testdata/certs/intermediate_ca.crt") @@ -294,7 +294,7 @@ func TestNewEmbedded_Sign(t *testing.T) { } func TestNewEmbedded_GetTLSCertificate(t *testing.T) { - caPEM, err := ioutil.ReadFile("testdata/certs/root_ca.crt") + caPEM, err := os.ReadFile("testdata/certs/root_ca.crt") assert.FatalError(t, err) crt, err := pemutil.ReadCertificate("testdata/certs/intermediate_ca.crt") diff --git a/authority/export.go b/authority/export.go index 8a5a257f..d1096fa5 100644 --- a/authority/export.go +++ b/authority/export.go @@ -2,8 +2,8 @@ package authority import ( "encoding/json" - "io/ioutil" "net/url" + "os" "path/filepath" "strings" @@ -257,7 +257,7 @@ func mustReadFileOrURI(fn string, m map[string][]byte) string { panic(err) } if ok { - b, err := ioutil.ReadFile(config.StepAbs(fn)) + b, err := os.ReadFile(config.StepAbs(fn)) if err != nil { panic(errors.Wrapf(err, "error reading %s", fn)) } diff --git a/authority/provisioner/aws.go b/authority/provisioner/aws.go index cd129b7b..fdad7b4a 100644 --- a/authority/provisioner/aws.go +++ b/authority/provisioner/aws.go @@ -9,9 +9,10 @@ import ( "encoding/json" "encoding/pem" "fmt" - "io/ioutil" + "io" "net" "net/http" + "os" "strings" "time" @@ -165,7 +166,7 @@ func newAWSConfig(certPath string) (*awsConfig, error) { if certPath == "" { certBytes = []byte(awsCertificate) } else { - if b, err := ioutil.ReadFile(certPath); err == nil { + if b, err := os.ReadFile(certPath); err == nil { certBytes = b } else { return nil, errors.Wrapf(err, "error reading %s", certPath) @@ -569,7 +570,7 @@ func (p *AWS) readURLv2(url string) (*http.Response, error) { client := http.Client{} // first get the token - req, err := http.NewRequest(http.MethodPut, p.config.tokenURL, nil) + req, err := http.NewRequest(http.MethodPut, p.config.tokenURL, http.NoBody) if err != nil { return nil, err } @@ -582,7 +583,7 @@ func (p *AWS) readURLv2(url string) (*http.Response, error) { if resp.StatusCode >= 400 { return nil, fmt.Errorf("Request for API token returned non-successful status code %d", resp.StatusCode) } - token, err := ioutil.ReadAll(resp.Body) + token, err := io.ReadAll(resp.Body) if err != nil { return nil, err } @@ -602,7 +603,7 @@ func (p *AWS) readURLv2(url string) (*http.Response, error) { func (p *AWS) readResponseBody(resp *http.Response) ([]byte, error) { defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return nil, err } diff --git a/authority/provisioner/azure.go b/authority/provisioner/azure.go index a90d1728..55d77f49 100644 --- a/authority/provisioner/azure.go +++ b/authority/provisioner/azure.go @@ -6,7 +6,7 @@ import ( "crypto/x509" "encoding/hex" "encoding/json" - "io/ioutil" + "io" "net/http" "regexp" "strings" @@ -173,7 +173,7 @@ func (p *Azure) GetIdentityToken(subject, caURL string) (string, error) { } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return "", errors.Wrap(err, "error reading identity token response") } diff --git a/authority/provisioner/azure_test.go b/authority/provisioner/azure_test.go index b7c321a6..7f8d6017 100644 --- a/authority/provisioner/azure_test.go +++ b/authority/provisioner/azure_test.go @@ -107,7 +107,7 @@ func TestAzure_GetIdentityToken(t *testing.T) { w.Write([]byte(t1)) default: w.Header().Add("Content-Type", "application/json") - w.Write([]byte(fmt.Sprintf(`{"access_token":"%s"}`, t1))) + fmt.Fprintf(w, `{"access_token":"%s"}`, t1) } })) defer srv.Close() diff --git a/authority/provisioner/gcp.go b/authority/provisioner/gcp.go index 98d776d1..e46f4ce4 100644 --- a/authority/provisioner/gcp.go +++ b/authority/provisioner/gcp.go @@ -7,7 +7,7 @@ import ( "crypto/x509" "encoding/hex" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "strings" @@ -183,7 +183,7 @@ func (p *GCP) GetIdentityToken(subject, caURL string) (string, error) { return "", errors.Wrap(err, "error doing identity request, are you in a GCP VM?") } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return "", errors.Wrap(err, "error on identity request") } diff --git a/authority/provisioner/utils_test.go b/authority/provisioner/utils_test.go index e39efbcf..fe2678fc 100644 --- a/authority/provisioner/utils_test.go +++ b/authority/provisioner/utils_test.go @@ -10,9 +10,9 @@ import ( "encoding/json" "encoding/pem" "fmt" - "io/ioutil" "net/http" "net/http/httptest" + "os" "strings" "time" @@ -188,7 +188,7 @@ func generateJWK() (*JWK, error) { } func generateK8sSA(inputPubKey interface{}) (*K8sSA, error) { - fooPubB, err := ioutil.ReadFile("./testdata/certs/foo.pub") + fooPubB, err := os.ReadFile("./testdata/certs/foo.pub") if err != nil { return nil, err } @@ -196,7 +196,7 @@ func generateK8sSA(inputPubKey interface{}) (*K8sSA, error) { if err != nil { return nil, err } - barPubB, err := ioutil.ReadFile("./testdata/certs/bar.pub") + barPubB, err := os.ReadFile("./testdata/certs/bar.pub") if err != nil { return nil, err } @@ -234,7 +234,7 @@ func generateSSHPOP() (*SSHPOP, error) { return nil, err } - userB, err := ioutil.ReadFile("./testdata/certs/ssh_user_ca_key.pub") + userB, err := os.ReadFile("./testdata/certs/ssh_user_ca_key.pub") if err != nil { return nil, err } @@ -242,7 +242,7 @@ func generateSSHPOP() (*SSHPOP, error) { if err != nil { return nil, err } - hostB, err := ioutil.ReadFile("./testdata/certs/ssh_host_ca_key.pub") + hostB, err := os.ReadFile("./testdata/certs/ssh_host_ca_key.pub") if err != nil { return nil, err } diff --git a/authority/provisioners.go b/authority/provisioners.go index 7e02126f..e394e7e9 100644 --- a/authority/provisioners.go +++ b/authority/provisioners.go @@ -6,7 +6,7 @@ import ( "encoding/json" "encoding/pem" "fmt" - "io/ioutil" + "os" "github.com/pkg/errors" "github.com/smallstep/certificates/authority/admin" @@ -524,7 +524,7 @@ func provisionerOptionsToLinkedca(p *provisioner.Options) (*linkedca.Template, * x509Template.Template = []byte(p.SSH.Template) } else if p.X509.TemplateFile != "" { filename := step.StepAbs(p.X509.TemplateFile) - if x509Template.Template, err = ioutil.ReadFile(filename); err != nil { + if x509Template.Template, err = os.ReadFile(filename); err != nil { return nil, nil, errors.Wrap(err, "error reading x509 template") } } @@ -540,7 +540,7 @@ func provisionerOptionsToLinkedca(p *provisioner.Options) (*linkedca.Template, * sshTemplate.Template = []byte(p.SSH.Template) } else if p.SSH.TemplateFile != "" { filename := step.StepAbs(p.SSH.TemplateFile) - if sshTemplate.Template, err = ioutil.ReadFile(filename); err != nil { + if sshTemplate.Template, err = os.ReadFile(filename); err != nil { return nil, nil, errors.Wrap(err, "error reading ssh template") } } diff --git a/authority/tls_test.go b/authority/tls_test.go index f1d1748d..158e6f4f 100644 --- a/authority/tls_test.go +++ b/authority/tls_test.go @@ -538,15 +538,15 @@ ZYtQ9Ot36qc= if tc.csr.Subject.CommonName == "" { assert.Equals(t, leaf.Subject, pkix.Name{}) } else { - assert.Equals(t, fmt.Sprintf("%v", leaf.Subject), - fmt.Sprintf("%v", &pkix.Name{ + assert.Equals(t, leaf.Subject.String(), + pkix.Name{ Country: []string{tmplt.Country}, Organization: []string{tmplt.Organization}, Locality: []string{tmplt.Locality}, StreetAddress: []string{tmplt.StreetAddress}, Province: []string{tmplt.Province}, CommonName: "smallstep test", - })) + }.String()) assert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com"}) } assert.Equals(t, leaf.Issuer, intermediate.Subject) @@ -718,15 +718,15 @@ func TestAuthority_Renew(t *testing.T) { assert.True(t, leaf.NotAfter.Before(expiry.Add(time.Minute))) tmplt := a.config.AuthorityConfig.Template - assert.Equals(t, fmt.Sprintf("%v", leaf.Subject), - fmt.Sprintf("%v", &pkix.Name{ + assert.Equals(t, leaf.Subject.String(), + pkix.Name{ Country: []string{tmplt.Country}, Organization: []string{tmplt.Organization}, Locality: []string{tmplt.Locality}, StreetAddress: []string{tmplt.StreetAddress}, Province: []string{tmplt.Province}, CommonName: tmplt.CommonName, - })) + }.String()) assert.Equals(t, leaf.Issuer, intermediate.Subject) assert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) @@ -925,15 +925,15 @@ func TestAuthority_Rekey(t *testing.T) { assert.True(t, leaf.NotAfter.Before(expiry.Add(time.Minute))) tmplt := a.config.AuthorityConfig.Template - assert.Equals(t, fmt.Sprintf("%v", leaf.Subject), - fmt.Sprintf("%v", &pkix.Name{ + assert.Equals(t, leaf.Subject.String(), + pkix.Name{ Country: []string{tmplt.Country}, Organization: []string{tmplt.Organization}, Locality: []string{tmplt.Locality}, StreetAddress: []string{tmplt.StreetAddress}, Province: []string{tmplt.Province}, CommonName: tmplt.CommonName, - })) + }.String()) assert.Equals(t, leaf.Issuer, intermediate.Subject) assert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) diff --git a/ca/acmeClient.go b/ca/acmeClient.go index d1f40f32..28451a45 100644 --- a/ca/acmeClient.go +++ b/ca/acmeClient.go @@ -7,7 +7,6 @@ import ( "encoding/pem" "fmt" "io" - "io/ioutil" "net/http" "strings" @@ -292,7 +291,7 @@ func (c *ACMEClient) GetCertificate(url string) (*x509.Certificate, []*x509.Cert return nil, nil, readACMEError(resp.Body) } defer resp.Body.Close() - bodyBytes, err := ioutil.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return nil, nil, errors.Wrap(err, "error reading GET certificate response") } @@ -338,7 +337,7 @@ func (c *ACMEClient) GetAccountOrders() ([]string, error) { func readACMEError(r io.ReadCloser) error { defer r.Close() - b, err := ioutil.ReadAll(r) + b, err := io.ReadAll(r) if err != nil { return errors.Wrap(err, "error reading from body") } diff --git a/ca/acmeClient_test.go b/ca/acmeClient_test.go index 656a82cf..d22c4972 100644 --- a/ca/acmeClient_test.go +++ b/ca/acmeClient_test.go @@ -5,7 +5,7 @@ import ( "encoding/base64" "encoding/json" "encoding/pem" - "io/ioutil" + "io" "net/http" "net/http/httptest" "testing" @@ -317,7 +317,7 @@ func TestACMEClient_post(t *testing.T) { } // validate jws request protected headers and body - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) assert.FatalError(t, err) jws, err := jose.ParseJWS(string(body)) assert.FatalError(t, err) @@ -455,7 +455,7 @@ func TestACMEClient_NewOrder(t *testing.T) { } // validate jws request protected headers and body - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) assert.FatalError(t, err) jws, err := jose.ParseJWS(string(body)) assert.FatalError(t, err) @@ -575,7 +575,7 @@ func TestACMEClient_GetOrder(t *testing.T) { } // validate jws request protected headers and body - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) assert.FatalError(t, err) jws, err := jose.ParseJWS(string(body)) assert.FatalError(t, err) @@ -695,7 +695,7 @@ func TestACMEClient_GetAuthz(t *testing.T) { } // validate jws request protected headers and body - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) assert.FatalError(t, err) jws, err := jose.ParseJWS(string(body)) assert.FatalError(t, err) @@ -815,7 +815,7 @@ func TestACMEClient_GetChallenge(t *testing.T) { } // validate jws request protected headers and body - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) assert.FatalError(t, err) jws, err := jose.ParseJWS(string(body)) assert.FatalError(t, err) @@ -936,7 +936,7 @@ func TestACMEClient_ValidateChallenge(t *testing.T) { } // validate jws request protected headers and body - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) assert.FatalError(t, err) jws, err := jose.ParseJWS(string(body)) assert.FatalError(t, err) @@ -1061,7 +1061,7 @@ func TestACMEClient_FinalizeOrder(t *testing.T) { } // validate jws request protected headers and body - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) assert.FatalError(t, err) jws, err := jose.ParseJWS(string(body)) assert.FatalError(t, err) @@ -1188,7 +1188,7 @@ func TestACMEClient_GetAccountOrders(t *testing.T) { } // validate jws request protected headers and body - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) assert.FatalError(t, err) jws, err := jose.ParseJWS(string(body)) assert.FatalError(t, err) @@ -1317,7 +1317,7 @@ func TestACMEClient_GetCertificate(t *testing.T) { } // validate jws request protected headers and body - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) assert.FatalError(t, err) jws, err := jose.ParseJWS(string(body)) assert.FatalError(t, err) diff --git a/ca/adminClient.go b/ca/adminClient.go index 6022f677..2e447f55 100644 --- a/ca/adminClient.go +++ b/ca/adminClient.go @@ -197,7 +197,7 @@ func (c *AdminClient) GetAdminsPaginate(opts ...AdminOption) (*adminAPI.GetAdmin if err != nil { return nil, errors.Wrapf(err, "error generating admin token") } - req, err := http.NewRequest("GET", u.String(), nil) + req, err := http.NewRequest("GET", u.String(), http.NoBody) if err != nil { return nil, errors.Wrapf(err, "create GET %s request failed", u) } @@ -284,7 +284,7 @@ func (c *AdminClient) RemoveAdmin(id string) error { if err != nil { return errors.Wrapf(err, "error generating admin token") } - req, err := http.NewRequest("DELETE", u.String(), nil) + req, err := http.NewRequest("DELETE", u.String(), http.NoBody) if err != nil { return errors.Wrapf(err, "create DELETE %s request failed", u) } @@ -363,7 +363,7 @@ func (c *AdminClient) GetProvisioner(opts ...ProvisionerOption) (*linkedca.Provi if err != nil { return nil, errors.Wrapf(err, "error generating admin token") } - req, err := http.NewRequest("GET", u.String(), nil) + req, err := http.NewRequest("GET", u.String(), http.NoBody) if err != nil { return nil, errors.Wrapf(err, "create PUT %s request failed", u) } @@ -402,7 +402,7 @@ func (c *AdminClient) GetProvisionersPaginate(opts ...ProvisionerOption) (*admin if err != nil { return nil, errors.Wrapf(err, "error generating admin token") } - req, err := http.NewRequest("GET", u.String(), nil) + req, err := http.NewRequest("GET", u.String(), http.NoBody) if err != nil { return nil, errors.Wrapf(err, "create PUT %s request failed", u) } @@ -472,7 +472,7 @@ func (c *AdminClient) RemoveProvisioner(opts ...ProvisionerOption) error { if err != nil { return errors.Wrapf(err, "error generating admin token") } - req, err := http.NewRequest("DELETE", u.String(), nil) + req, err := http.NewRequest("DELETE", u.String(), http.NoBody) if err != nil { return errors.Wrapf(err, "create DELETE %s request failed", u) } diff --git a/ca/bootstrap_test.go b/ca/bootstrap_test.go index e7d0e401..7c1bc908 100644 --- a/ca/bootstrap_test.go +++ b/ca/bootstrap_test.go @@ -3,7 +3,7 @@ package ca import ( "context" "crypto/tls" - "io/ioutil" + "io" "net" "net/http" "net/http/httptest" @@ -382,7 +382,7 @@ func TestBootstrapClientServerRotation(t *testing.T) { return errors.Wrapf(err, "client.Get(%s) failed", srvURL) } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return errors.Wrap(err, "client.Get() error reading response") } @@ -499,7 +499,7 @@ func TestBootstrapClientServerFederation(t *testing.T) { return errors.Wrapf(err, "client.Get(%s) failed", srvURL) } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return errors.Wrap(err, "client.Get() error reading response") } @@ -589,9 +589,9 @@ func TestBootstrapListener(t *testing.T) { return } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { - t.Errorf("ioutil.ReadAll() error = %v", err) + t.Errorf("io.ReadAll() error = %v", err) return } if string(b) != "ok" { diff --git a/ca/ca_test.go b/ca/ca_test.go index ff264db7..0f7cb02e 100644 --- a/ca/ca_test.go +++ b/ca/ca_test.go @@ -294,15 +294,15 @@ ZEp7knvU2psWRw== assert.Equals(t, leaf.NotBefore, now.Truncate(time.Second)) assert.Equals(t, leaf.NotAfter, leafExpiry.Truncate(time.Second)) - assert.Equals(t, fmt.Sprintf("%v", leaf.Subject), - fmt.Sprintf("%v", &pkix.Name{ + assert.Equals(t, leaf.Subject.String(), + pkix.Name{ Country: []string{asn1dn.Country}, Organization: []string{asn1dn.Organization}, Locality: []string{asn1dn.Locality}, StreetAddress: []string{asn1dn.StreetAddress}, Province: []string{asn1dn.Province}, CommonName: asn1dn.CommonName, - })) + }.String()) assert.Equals(t, leaf.Issuer, intermediate.Subject) assert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) @@ -641,10 +641,10 @@ func TestCARenew(t *testing.T) { assert.Equals(t, leaf.NotBefore, now.Truncate(time.Second)) assert.Equals(t, leaf.NotAfter, leafExpiry.Truncate(time.Second)) - assert.Equals(t, fmt.Sprintf("%v", leaf.Subject), - fmt.Sprintf("%v", &pkix.Name{ + assert.Equals(t, leaf.Subject.String(), + pkix.Name{ CommonName: asn1dn.CommonName, - })) + }.String()) assert.Equals(t, leaf.Issuer, intermediate.Subject) assert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256) diff --git a/ca/client.go b/ca/client.go index cfeddba0..df4561d8 100644 --- a/ca/client.go +++ b/ca/client.go @@ -15,7 +15,6 @@ import ( "encoding/json" "encoding/pem" "io" - "io/ioutil" "net/http" "net/url" "os" @@ -75,7 +74,7 @@ func (c *uaClient) SetTransport(tr http.RoundTripper) { } func (c *uaClient) Get(u string) (*http.Response, error) { - req, err := http.NewRequest("GET", u, nil) + req, err := http.NewRequest("GET", u, http.NoBody) if err != nil { return nil, errors.Wrapf(err, "new request GET %s failed", u) } @@ -350,7 +349,7 @@ func WithRetryFunc(fn RetryFunc) ClientOption { } func getTransportFromFile(filename string) (http.RoundTripper, error) { - data, err := ioutil.ReadFile(filename) + data, err := os.ReadFile(filename) if err != nil { return nil, errors.Wrapf(err, "error reading %s", filename) } @@ -1305,7 +1304,7 @@ func readJSON(r io.ReadCloser, v interface{}) error { func readProtoJSON(r io.ReadCloser, m proto.Message) error { defer r.Close() - data, err := ioutil.ReadAll(r) + data, err := io.ReadAll(r) if err != nil { return err } diff --git a/ca/identity/client.go b/ca/identity/client.go index 4377638f..7d5dcfcb 100644 --- a/ca/identity/client.go +++ b/ca/identity/client.go @@ -5,9 +5,9 @@ import ( "crypto/x509" "encoding/json" "fmt" - "io/ioutil" "net/http" "net/url" + "os" "github.com/pkg/errors" ) @@ -27,7 +27,7 @@ func (c *Client) ResolveReference(ref *url.URL) *url.URL { // $STEPPATH/config/defaults.json and the identity defined in // $STEPPATH/config/identity.json func LoadClient() (*Client, error) { - b, err := ioutil.ReadFile(DefaultsFile) + b, err := os.ReadFile(DefaultsFile) if err != nil { return nil, errors.Wrapf(err, "error reading %s", DefaultsFile) } @@ -65,7 +65,7 @@ func LoadClient() (*Client, error) { } // RootCAs - b, err = ioutil.ReadFile(defaults.Root) + b, err = os.ReadFile(defaults.Root) if err != nil { return nil, errors.Wrapf(err, "error loading %s", defaults.Root) } diff --git a/ca/identity/client_test.go b/ca/identity/client_test.go index 402ec7b8..0ed9b33b 100644 --- a/ca/identity/client_test.go +++ b/ca/identity/client_test.go @@ -3,10 +3,10 @@ package identity import ( "crypto/tls" "crypto/x509" - "io/ioutil" "net/http" "net/http/httptest" "net/url" + "os" "reflect" "testing" ) @@ -40,7 +40,7 @@ func TestClient(t *testing.T) { if err != nil { t.Fatal(err) } - b, err := ioutil.ReadFile("testdata/certs/root_ca.crt") + b, err := os.ReadFile("testdata/certs/root_ca.crt") if err != nil { t.Fatal(err) } @@ -114,7 +114,7 @@ func TestLoadClient(t *testing.T) { if err != nil { t.Fatal(err) } - b, err := ioutil.ReadFile("testdata/certs/root_ca.crt") + b, err := os.ReadFile("testdata/certs/root_ca.crt") if err != nil { t.Fatal(err) } diff --git a/ca/identity/identity.go b/ca/identity/identity.go index 0f022dd7..4c665850 100644 --- a/ca/identity/identity.go +++ b/ca/identity/identity.go @@ -7,7 +7,6 @@ import ( "crypto/x509" "encoding/json" "encoding/pem" - "io/ioutil" "net/http" "os" "path/filepath" @@ -61,7 +60,7 @@ type Identity struct { // LoadIdentity loads an identity present in the given filename. func LoadIdentity(filename string) (*Identity, error) { - b, err := ioutil.ReadFile(filename) + b, err := os.ReadFile(filename) if err != nil { return nil, errors.Wrapf(err, "error reading %s", filename) } @@ -112,7 +111,7 @@ func WriteDefaultIdentity(certChain []api.Certificate, key crypto.PrivateKey) er if err := pem.Encode(buf, block); err != nil { return errors.Wrap(err, "error encoding identity key") } - if err := ioutil.WriteFile(keyFilename, buf.Bytes(), 0600); err != nil { + if err := os.WriteFile(keyFilename, buf.Bytes(), 0600); err != nil { return errors.Wrap(err, "error writing identity certificate") } @@ -127,7 +126,7 @@ func WriteDefaultIdentity(certChain []api.Certificate, key crypto.PrivateKey) er }); err != nil { return errors.Wrap(err, "error writing identity json") } - if err := ioutil.WriteFile(IdentityFile, buf.Bytes(), 0600); err != nil { + if err := os.WriteFile(IdentityFile, buf.Bytes(), 0600); err != nil { return errors.Wrap(err, "error writing identity certificate") } @@ -153,7 +152,7 @@ func writeCertificate(filename string, certChain []api.Certificate) error { } } - if err := ioutil.WriteFile(filename, buf.Bytes(), 0600); err != nil { + if err := os.WriteFile(filename, buf.Bytes(), 0600); err != nil { return errors.Wrap(err, "error writing certificate") } @@ -263,7 +262,7 @@ func (i *Identity) GetCertPool() (*x509.CertPool, error) { if i.Root == "" { return nil, nil } - b, err := ioutil.ReadFile(i.Root) + b, err := os.ReadFile(i.Root) if err != nil { return nil, errors.Wrap(err, "error reading identity root") } @@ -320,7 +319,7 @@ func (i *Identity) Renew(client Renewer) error { } } certFilename := filepath.Join(identityDir, "identity.crt") - if err := ioutil.WriteFile(certFilename, buf.Bytes(), 0600); err != nil { + if err := os.WriteFile(certFilename, buf.Bytes(), 0600); err != nil { return errors.Wrap(err, "error writing identity certificate") } diff --git a/ca/provisioner_test.go b/ca/provisioner_test.go index ea0ca51e..01b54d17 100644 --- a/ca/provisioner_test.go +++ b/ca/provisioner_test.go @@ -1,8 +1,8 @@ package ca import ( - "io/ioutil" "net/url" + "os" "reflect" "testing" "time" @@ -45,7 +45,7 @@ func TestNewProvisioner(t *testing.T) { defer ca.Close() want := getTestProvisioner(t, ca.URL) - caBundle, err := ioutil.ReadFile("testdata/secrets/root_ca.crt") + caBundle, err := os.ReadFile("testdata/secrets/root_ca.crt") if err != nil { t.Fatal(err) } diff --git a/ca/renew.go b/ca/renew.go index 7d574748..915be787 100644 --- a/ca/renew.go +++ b/ca/renew.go @@ -18,7 +18,7 @@ var minCertDuration = time.Minute // TLSRenewer automatically renews a tls certificate using a RenewFunc. type TLSRenewer struct { - sync.RWMutex + renewMutex sync.RWMutex RenewCertificate RenewFunc cert *tls.Certificate timer *time.Timer @@ -81,9 +81,9 @@ func NewTLSRenewer(cert *tls.Certificate, fn RenewFunc, opts ...tlsRenewerOption func (r *TLSRenewer) Run() { cert := r.getCertificate() next := r.nextRenewDuration(cert.Leaf.NotAfter) - r.Lock() + r.renewMutex.Lock() r.timer = time.AfterFunc(next, r.renewCertificate) - r.Unlock() + r.renewMutex.Unlock() } // RunContext starts the certificate renewer for the given certificate. @@ -133,25 +133,25 @@ func (r *TLSRenewer) GetClientCertificate(*tls.CertificateRequestInfo) (*tls.Cer // if the timer does not fire e.g. when the CA is run from a laptop that // enters sleep mode. func (r *TLSRenewer) getCertificate() *tls.Certificate { - r.RLock() + r.renewMutex.RLock() cert := r.cert - r.RUnlock() + r.renewMutex.RUnlock() return cert } // getCertificateForCA returns the certificate using a read-only lock. It will // automatically renew the certificate if it has expired. func (r *TLSRenewer) getCertificateForCA() *tls.Certificate { - r.RLock() + r.renewMutex.RLock() // Force certificate renewal if the timer didn't run. // This is an special case that can happen after a computer sleep. if time.Now().After(r.certNotAfter) { - r.RUnlock() + r.renewMutex.RUnlock() r.renewCertificate() - r.RLock() + r.renewMutex.RLock() } cert := r.cert - r.RUnlock() + r.renewMutex.RUnlock() return cert } @@ -159,10 +159,10 @@ func (r *TLSRenewer) getCertificateForCA() *tls.Certificate { // updates certNotAfter with 1m of delta; this will force the renewal of the // certificate if it is about to expire. func (r *TLSRenewer) setCertificate(cert *tls.Certificate) { - r.Lock() + r.renewMutex.Lock() r.cert = cert r.certNotAfter = cert.Leaf.NotAfter.Add(-1 * time.Minute) - r.Unlock() + r.renewMutex.Unlock() } func (r *TLSRenewer) renewCertificate() { @@ -175,9 +175,9 @@ func (r *TLSRenewer) renewCertificate() { r.setCertificate(cert) next = r.nextRenewDuration(cert.Leaf.NotAfter) } - r.Lock() + r.renewMutex.Lock() r.timer.Reset(next) - r.Unlock() + r.renewMutex.Unlock() } func (r *TLSRenewer) nextRenewDuration(notAfter time.Time) time.Duration { diff --git a/ca/tls_options_test.go b/ca/tls_options_test.go index 8744bb2b..7d94926b 100644 --- a/ca/tls_options_test.go +++ b/ca/tls_options_test.go @@ -4,8 +4,8 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "io/ioutil" "net/http" + "os" "reflect" "sort" "testing" @@ -202,7 +202,7 @@ func TestAddRootsToRootCAs(t *testing.T) { t.Fatal(err) } - root, err := ioutil.ReadFile("testdata/secrets/root_ca.crt") + root, err := os.ReadFile("testdata/secrets/root_ca.crt") if err != nil { t.Fatal(err) } @@ -256,7 +256,7 @@ func TestAddRootsToClientCAs(t *testing.T) { t.Fatal(err) } - root, err := ioutil.ReadFile("testdata/secrets/root_ca.crt") + root, err := os.ReadFile("testdata/secrets/root_ca.crt") if err != nil { t.Fatal(err) } @@ -310,12 +310,12 @@ func TestAddFederationToRootCAs(t *testing.T) { t.Fatal(err) } - root, err := ioutil.ReadFile("testdata/secrets/root_ca.crt") + root, err := os.ReadFile("testdata/secrets/root_ca.crt") if err != nil { t.Fatal(err) } - federated, err := ioutil.ReadFile("testdata/secrets/federated_ca.crt") + federated, err := os.ReadFile("testdata/secrets/federated_ca.crt") if err != nil { t.Fatal(err) } @@ -374,12 +374,12 @@ func TestAddFederationToClientCAs(t *testing.T) { t.Fatal(err) } - root, err := ioutil.ReadFile("testdata/secrets/root_ca.crt") + root, err := os.ReadFile("testdata/secrets/root_ca.crt") if err != nil { t.Fatal(err) } - federated, err := ioutil.ReadFile("testdata/secrets/federated_ca.crt") + federated, err := os.ReadFile("testdata/secrets/federated_ca.crt") if err != nil { t.Fatal(err) } @@ -438,7 +438,7 @@ func TestAddRootsToCAs(t *testing.T) { t.Fatal(err) } - root, err := ioutil.ReadFile("testdata/secrets/root_ca.crt") + root, err := os.ReadFile("testdata/secrets/root_ca.crt") if err != nil { t.Fatal(err) } @@ -492,12 +492,12 @@ func TestAddFederationToCAs(t *testing.T) { t.Fatal(err) } - root, err := ioutil.ReadFile("testdata/secrets/root_ca.crt") + root, err := os.ReadFile("testdata/secrets/root_ca.crt") if err != nil { t.Fatal(err) } - federated, err := ioutil.ReadFile("testdata/secrets/federated_ca.crt") + federated, err := os.ReadFile("testdata/secrets/federated_ca.crt") if err != nil { t.Fatal(err) } diff --git a/ca/tls_test.go b/ca/tls_test.go index ac1d84b6..93dbe9b3 100644 --- a/ca/tls_test.go +++ b/ca/tls_test.go @@ -8,7 +8,7 @@ import ( "crypto/tls" "crypto/x509" "encoding/hex" - "io/ioutil" + "io" "log" "net/http" "net/http/httptest" @@ -221,7 +221,7 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) { return } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { t.Fatalf("ioutil.RealAdd() error = %v", err) } @@ -335,7 +335,7 @@ func TestClient_GetServerTLSConfig_renew(t *testing.T) { } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { t.Errorf("ioutil.RealAdd() error = %v", err) return @@ -374,9 +374,9 @@ func TestClient_GetServerTLSConfig_renew(t *testing.T) { } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { - t.Errorf("ioutil.RealAdd() error = %v", err) + t.Errorf("io.ReadAll() error = %v", err) return } if !bytes.Equal(b, []byte("ok")) { diff --git a/cas/stepcas/stepcas_test.go b/cas/stepcas/stepcas_test.go index f430a1dd..ad7851bf 100644 --- a/cas/stepcas/stepcas_test.go +++ b/cas/stepcas/stepcas_test.go @@ -91,7 +91,7 @@ func mustSerializeCrt(filename string, certs ...*x509.Certificate) { panic(err) } } - if err := ioutil.WriteFile(filename, buf.Bytes(), 0600); err != nil { + if err := os.WriteFile(filename, buf.Bytes(), 0600); err != nil { panic(err) } } @@ -105,7 +105,7 @@ func mustSerializeKey(filename string, key crypto.Signer) { Type: "PRIVATE KEY", Bytes: b, }) - if err := ioutil.WriteFile(filename, b, 0600); err != nil { + if err := os.WriteFile(filename, b, 0600); err != nil { panic(err) } } diff --git a/commands/app.go b/commands/app.go index 84232a6c..8c40de0e 100644 --- a/commands/app.go +++ b/commands/app.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "fmt" - "io/ioutil" "net" "net/http" "os" @@ -98,7 +97,7 @@ To get a linked authority token: var password []byte if passFile != "" { - if password, err = ioutil.ReadFile(passFile); err != nil { + if password, err = os.ReadFile(passFile); err != nil { fatal(errors.Wrapf(err, "error reading %s", passFile)) } password = bytes.TrimRightFunc(password, unicode.IsSpace) @@ -106,7 +105,7 @@ To get a linked authority token: var sshHostPassword []byte if sshHostPassFile != "" { - if sshHostPassword, err = ioutil.ReadFile(sshHostPassFile); err != nil { + if sshHostPassword, err = os.ReadFile(sshHostPassFile); err != nil { fatal(errors.Wrapf(err, "error reading %s", sshHostPassFile)) } sshHostPassword = bytes.TrimRightFunc(sshHostPassword, unicode.IsSpace) @@ -114,7 +113,7 @@ To get a linked authority token: var sshUserPassword []byte if sshUserPassFile != "" { - if sshUserPassword, err = ioutil.ReadFile(sshUserPassFile); err != nil { + if sshUserPassword, err = os.ReadFile(sshUserPassFile); err != nil { fatal(errors.Wrapf(err, "error reading %s", sshUserPassFile)) } sshUserPassword = bytes.TrimRightFunc(sshUserPassword, unicode.IsSpace) @@ -122,7 +121,7 @@ To get a linked authority token: var issuerPassword []byte if issuerPassFile != "" { - if issuerPassword, err = ioutil.ReadFile(issuerPassFile); err != nil { + if issuerPassword, err = os.ReadFile(issuerPassFile); err != nil { fatal(errors.Wrapf(err, "error reading %s", issuerPassFile)) } issuerPassword = bytes.TrimRightFunc(issuerPassword, unicode.IsSpace) diff --git a/commands/export.go b/commands/export.go index 5586f576..19bfb1fa 100644 --- a/commands/export.go +++ b/commands/export.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "os" "unicode" "github.com/pkg/errors" @@ -72,14 +72,14 @@ func exportAction(ctx *cli.Context) error { } if passwordFile != "" { - b, err := ioutil.ReadFile(passwordFile) + b, err := os.ReadFile(passwordFile) if err != nil { return errors.Wrapf(err, "error reading %s", passwordFile) } cfg.Password = string(bytes.TrimRightFunc(b, unicode.IsSpace)) } if issuerPasswordFile != "" { - b, err := ioutil.ReadFile(issuerPasswordFile) + b, err := os.ReadFile(issuerPasswordFile) if err != nil { return errors.Wrapf(err, "error reading %s", issuerPasswordFile) } diff --git a/examples/basic-federation/client/main.go b/examples/basic-federation/client/main.go index e8c5140e..93e94f56 100644 --- a/examples/basic-federation/client/main.go +++ b/examples/basic-federation/client/main.go @@ -3,7 +3,7 @@ package main import ( "context" "fmt" - "io/ioutil" + "io" "os" "time" @@ -32,7 +32,7 @@ func main() { if err != nil { panic(err) } - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) resp.Body.Close() if err != nil { panic(err) diff --git a/examples/bootstrap-client/client.go b/examples/bootstrap-client/client.go index 109336be..4936eb6c 100644 --- a/examples/bootstrap-client/client.go +++ b/examples/bootstrap-client/client.go @@ -3,7 +3,7 @@ package main import ( "context" "fmt" - "io/ioutil" + "io" "os" "time" @@ -32,7 +32,7 @@ func main() { if err != nil { panic(err) } - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) resp.Body.Close() if err != nil { panic(err) diff --git a/kms/cloudkms/cloudkms_test.go b/kms/cloudkms/cloudkms_test.go index fefa6e2a..814e3638 100644 --- a/kms/cloudkms/cloudkms_test.go +++ b/kms/cloudkms/cloudkms_test.go @@ -4,7 +4,7 @@ import ( "context" "crypto" "fmt" - "io/ioutil" + "os" "reflect" "testing" @@ -165,7 +165,7 @@ func TestCloudKMS_Close(t *testing.T) { func TestCloudKMS_CreateSigner(t *testing.T) { keyName := "projects/p/locations/l/keyRings/k/cryptoKeys/c/cryptoKeyVersions/1" - pemBytes, err := ioutil.ReadFile("testdata/pub.pem") + pemBytes, err := os.ReadFile("testdata/pub.pem") if err != nil { t.Fatal(err) } @@ -223,7 +223,7 @@ func TestCloudKMS_CreateKey(t *testing.T) { testError := fmt.Errorf("an error") alreadyExists := status.Error(codes.AlreadyExists, "already exists") - pemBytes, err := ioutil.ReadFile("testdata/pub.pem") + pemBytes, err := os.ReadFile("testdata/pub.pem") if err != nil { t.Fatal(err) } @@ -389,7 +389,7 @@ func TestCloudKMS_GetPublicKey(t *testing.T) { keyName := "projects/p/locations/l/keyRings/k/cryptoKeys/c/cryptoKeyVersions/1" testError := fmt.Errorf("an error") - pemBytes, err := ioutil.ReadFile("testdata/pub.pem") + pemBytes, err := os.ReadFile("testdata/pub.pem") if err != nil { t.Fatal(err) } diff --git a/kms/cloudkms/signer_test.go b/kms/cloudkms/signer_test.go index a8f964f1..22d1fe19 100644 --- a/kms/cloudkms/signer_test.go +++ b/kms/cloudkms/signer_test.go @@ -7,7 +7,7 @@ import ( "crypto/x509" "fmt" "io" - "io/ioutil" + "os" "reflect" "testing" @@ -17,7 +17,7 @@ import ( ) func Test_newSigner(t *testing.T) { - pemBytes, err := ioutil.ReadFile("testdata/pub.pem") + pemBytes, err := os.ReadFile("testdata/pub.pem") if err != nil { t.Fatal(err) } @@ -70,7 +70,7 @@ func Test_newSigner(t *testing.T) { } func Test_signer_Public(t *testing.T) { - pemBytes, err := ioutil.ReadFile("testdata/pub.pem") + pemBytes, err := os.ReadFile("testdata/pub.pem") if err != nil { t.Fatal(err) } @@ -159,7 +159,7 @@ func Test_signer_Sign(t *testing.T) { } func TestSigner_SignatureAlgorithm(t *testing.T) { - pemBytes, err := ioutil.ReadFile("testdata/pub.pem") + pemBytes, err := os.ReadFile("testdata/pub.pem") if err != nil { t.Fatal(err) } diff --git a/kms/softkms/softkms_test.go b/kms/softkms/softkms_test.go index 9e293b07..907a7efe 100644 --- a/kms/softkms/softkms_test.go +++ b/kms/softkms/softkms_test.go @@ -11,7 +11,7 @@ import ( "crypto/x509" "encoding/pem" "fmt" - "io/ioutil" + "os" "reflect" "testing" @@ -78,7 +78,7 @@ func TestSoftKMS_CreateSigner(t *testing.T) { } // Read and decode file using standard packages - b, err := ioutil.ReadFile("testdata/priv.pem") + b, err := os.ReadFile("testdata/priv.pem") if err != nil { t.Fatal(err) } @@ -234,7 +234,7 @@ func TestSoftKMS_CreateKey(t *testing.T) { } func TestSoftKMS_GetPublicKey(t *testing.T) { - b, err := ioutil.ReadFile("testdata/pub.pem") + b, err := os.ReadFile("testdata/pub.pem") if err != nil { t.Fatal(err) } @@ -332,7 +332,7 @@ func TestSoftKMS_CreateDecrypter(t *testing.T) { if err != nil { t.Fatal(err) } - b, err := ioutil.ReadFile("testdata/rsa.priv.pem") + b, err := os.ReadFile("testdata/rsa.priv.pem") if err != nil { t.Fatal(err) } diff --git a/kms/sshagentkms/sshagentkms_test.go b/kms/sshagentkms/sshagentkms_test.go index d3a9e9f5..2c0a8aba 100644 --- a/kms/sshagentkms/sshagentkms_test.go +++ b/kms/sshagentkms/sshagentkms_test.go @@ -9,7 +9,6 @@ import ( "crypto/rand" "crypto/x509" "encoding/pem" - "io/ioutil" "net" "os" "os/exec" @@ -202,7 +201,7 @@ func TestNew(t *testing.T) { }) // Load ssh test fixtures - b, err := ioutil.ReadFile("testdata/ssh") + b, err := os.ReadFile("testdata/ssh") if err != nil { t.Fatal(err) } @@ -290,7 +289,7 @@ func TestSSHAgentKMS_CreateSigner(t *testing.T) { } // Read and decode file using standard packages - b, err := ioutil.ReadFile("testdata/priv.pem") + b, err := os.ReadFile("testdata/priv.pem") if err != nil { t.Fatal(err) } @@ -315,7 +314,7 @@ func TestSSHAgentKMS_CreateSigner(t *testing.T) { }) // Load ssh test fixtures - sshPubKeyStr, err := ioutil.ReadFile("testdata/ssh.pub") + sshPubKeyStr, err := os.ReadFile("testdata/ssh.pub") if err != nil { t.Fatal(err) } @@ -323,7 +322,7 @@ func TestSSHAgentKMS_CreateSigner(t *testing.T) { if err != nil { t.Fatal(err) } - b, err = ioutil.ReadFile("testdata/ssh") + b, err = os.ReadFile("testdata/ssh") if err != nil { t.Fatal(err) } @@ -499,7 +498,7 @@ func TestSSHAgentKMS_CreateKey(t *testing.T) { */ func TestSSHAgentKMS_GetPublicKey(t *testing.T) { - b, err := ioutil.ReadFile("testdata/pub.pem") + b, err := os.ReadFile("testdata/pub.pem") if err != nil { t.Fatal(err) } @@ -510,7 +509,7 @@ func TestSSHAgentKMS_GetPublicKey(t *testing.T) { } // Load ssh test fixtures - b, err = ioutil.ReadFile("testdata/ssh.pub") + b, err = os.ReadFile("testdata/ssh.pub") if err != nil { t.Fatal(err) } @@ -518,7 +517,7 @@ func TestSSHAgentKMS_GetPublicKey(t *testing.T) { if err != nil { t.Fatal(err) } - b, err = ioutil.ReadFile("testdata/ssh") + b, err = os.ReadFile("testdata/ssh") if err != nil { t.Fatal(err) } diff --git a/kms/uri/uri.go b/kms/uri/uri.go index 36e15e7d..a812f80b 100644 --- a/kms/uri/uri.go +++ b/kms/uri/uri.go @@ -3,8 +3,8 @@ package uri import ( "bytes" "encoding/hex" - "io/ioutil" "net/url" + "os" "strings" "unicode" @@ -140,7 +140,7 @@ func readFile(path string) ([]byte, error) { if err == nil && (u.Scheme == "" || u.Scheme == "file") && u.Path != "" { path = u.Path } - b, err := ioutil.ReadFile(path) + b, err := os.ReadFile(path) if err != nil { return nil, errors.Wrapf(err, "error reading %s", path) } diff --git a/scep/api/api.go b/scep/api/api.go index 4e02d4a1..0c8c469b 100644 --- a/scep/api/api.go +++ b/scep/api/api.go @@ -5,7 +5,6 @@ import ( "crypto/x509" "encoding/base64" "io" - "io/ioutil" "net/http" "net/url" "strings" @@ -167,7 +166,7 @@ func decodeSCEPRequest(r *http.Request) (SCEPRequest, error) { return SCEPRequest{}, errors.Errorf("unsupported operation: %s", operation) } case http.MethodPost: - body, err := ioutil.ReadAll(io.LimitReader(r.Body, maxPayloadSize)) + body, err := io.ReadAll(io.LimitReader(r.Body, maxPayloadSize)) if err != nil { return SCEPRequest{}, err } diff --git a/templates/templates.go b/templates/templates.go index 09416b68..4fd68ce9 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -2,7 +2,6 @@ package templates import ( "bytes" - "io/ioutil" "os" "path/filepath" "strings" @@ -167,7 +166,7 @@ func (t *Template) Load() error { switch { case t.TemplatePath != "": filename := config.StepAbs(t.TemplatePath) - b, err := ioutil.ReadFile(filename) + b, err := os.ReadFile(filename) if err != nil { return errors.Wrapf(err, "error reading %s", filename) } From 2c05f488f6f0e00aa6a1e3e19a0cf6534032b5c6 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Sat, 13 Nov 2021 01:43:03 +0100 Subject: [PATCH 04/34] Remove support for Go 1.15 --- .github/workflows/test.yml | 2 +- go.mod | 2 +- go.sum | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bfc861c7..78b59f4b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - go: [ '1.15', '1.16', '1.17' ] + go: [ '1.16', '1.17' ] steps: - name: Checkout diff --git a/go.mod b/go.mod index 5f234b7a..c31dca60 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/smallstep/certificates -go 1.15 +go 1.16 require ( cloud.google.com/go v0.83.0 diff --git a/go.sum b/go.sum index 0f12f0a6..1ee17532 100644 --- a/go.sum +++ b/go.sum @@ -367,10 +367,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= @@ -956,7 +954,6 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= From 741ac64c6128e5b6941b91e22f9ad9f8203467f2 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 5 Aug 2021 14:00:58 -0700 Subject: [PATCH 05/34] change name of package cli-utils/config to cli-utils/step --- ca/identity/identity.go | 10 +++++----- go.mod | 11 +++++++---- templates/templates.go | 8 ++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/ca/identity/identity.go b/ca/identity/identity.go index 0f022dd7..14a22eb9 100644 --- a/ca/identity/identity.go +++ b/ca/identity/identity.go @@ -16,7 +16,7 @@ import ( "github.com/pkg/errors" "github.com/smallstep/certificates/api" - "go.step.sm/cli-utils/config" + "go.step.sm/cli-utils/step" "go.step.sm/crypto/pemutil" ) @@ -40,10 +40,10 @@ const TunnelTLS Type = "tTLS" const DefaultLeeway = 1 * time.Minute // IdentityFile contains the location of the identity file. -var IdentityFile = filepath.Join(config.StepPath(), "config", "identity.json") +var IdentityFile = filepath.Join(step.Path(), "config", "identity.json") // DefaultsFile contains the location of the defaults file. -var DefaultsFile = filepath.Join(config.StepPath(), "config", "defaults.json") +var DefaultsFile = filepath.Join(step.Path(), "config", "defaults.json") // Identity represents the identity file that can be used to authenticate with // the CA. @@ -80,8 +80,8 @@ func LoadDefaultIdentity() (*Identity, error) { // configDir and identityDir are used in WriteDefaultIdentity for testing // purposes. var ( - configDir = filepath.Join(config.StepPath(), "config") - identityDir = filepath.Join(config.StepPath(), "identity") + configDir = filepath.Join(step.Path(), "config") + identityDir = filepath.Join(step.Path(), "identity") ) // WriteDefaultIdentity writes the given certificates and key and the diff --git a/go.mod b/go.mod index 5f234b7a..3b7c0f3a 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,10 @@ require ( gopkg.in/square/go-jose.v2 v2.6.0 ) -// replace github.com/smallstep/nosql => ../nosql -// replace go.step.sm/crypto => ../crypto -// replace go.step.sm/cli-utils => ../cli-utils -// replace go.step.sm/linkedca => ../linkedca +//replace github.com/smallstep/nosql => ../nosql + +//replace go.step.sm/crypto => ../crypto + +replace go.step.sm/cli-utils => ../cli-utils + +replace go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 => github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568 diff --git a/templates/templates.go b/templates/templates.go index 09416b68..4fb831d4 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -10,8 +10,8 @@ import ( "github.com/Masterminds/sprig/v3" "github.com/pkg/errors" - "go.step.sm/cli-utils/config" "go.step.sm/cli-utils/fileutil" + "go.step.sm/cli-utils/step" ) // TemplateType defines how a template will be written in disk. @@ -132,7 +132,7 @@ func (t *Template) Validate() error { if t.TemplatePath != "" { // Check for file - st, err := os.Stat(config.StepAbs(t.TemplatePath)) + st, err := os.Stat(step.Abs(t.TemplatePath)) if err != nil { return errors.Wrapf(err, "error reading %s", t.TemplatePath) } @@ -166,7 +166,7 @@ func (t *Template) Load() error { if t.Template == nil && t.Type != Directory { switch { case t.TemplatePath != "": - filename := config.StepAbs(t.TemplatePath) + filename := step.Abs(t.TemplatePath) b, err := ioutil.ReadFile(filename) if err != nil { return errors.Wrapf(err, "error reading %s", filename) @@ -247,7 +247,7 @@ type Output struct { // Write writes the Output to the filesystem as a directory, file or snippet. func (o *Output) Write() error { - path := config.StepAbs(o.Path) + path := step.Abs(o.Path) if o.Type == Directory { return mkdir(path, 0700) } From 10db335f13899857ae546f91ae0080af21f86124 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 10 Aug 2021 00:38:30 -0700 Subject: [PATCH 06/34] mv pkg config -> step --- ca/client.go | 4 ++-- cmd/step-ca/main.go | 6 +++--- pki/pki.go | 16 ++++++++-------- pki/templates.go | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ca/client.go b/ca/client.go index cfeddba0..aa1e38dd 100644 --- a/ca/client.go +++ b/ca/client.go @@ -29,7 +29,7 @@ import ( "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/ca/identity" "github.com/smallstep/certificates/errs" - "go.step.sm/cli-utils/config" + "go.step.sm/cli-utils/step" "go.step.sm/crypto/jose" "go.step.sm/crypto/keyutil" "go.step.sm/crypto/pemutil" @@ -1295,7 +1295,7 @@ func createCertificateRequest(commonName string, sans []string, key crypto.Priva // getRootCAPath returns the path where the root CA is stored based on the // STEPPATH environment variable. func getRootCAPath() string { - return filepath.Join(config.StepPath(), "certs", "root_ca.crt") + return filepath.Join(step.Path(), "certs", "root_ca.crt") } func readJSON(r io.ReadCloser, v interface{}) error { diff --git a/cmd/step-ca/main.go b/cmd/step-ca/main.go index 01d800d8..f40ddf5f 100644 --- a/cmd/step-ca/main.go +++ b/cmd/step-ca/main.go @@ -21,7 +21,7 @@ import ( "github.com/urfave/cli" "go.step.sm/cli-utils/command" "go.step.sm/cli-utils/command/version" - "go.step.sm/cli-utils/config" + "go.step.sm/cli-utils/step" "go.step.sm/cli-utils/ui" "go.step.sm/cli-utils/usage" @@ -49,7 +49,7 @@ var ( ) func init() { - config.Set("Smallstep CA", Version, BuildTime) + step.Set("Smallstep CA", Version, BuildTime) authority.GlobalVersion.Version = Version rand.Seed(time.Now().UnixNano()) } @@ -115,7 +115,7 @@ func main() { app := cli.NewApp() app.Name = "step-ca" app.HelpName = "step-ca" - app.Version = config.Version() + app.Version = step.Version() app.Usage = "an online certificate authority for secure automated certificate management" app.UsageText = `**step-ca** [**--password-file**=] [**--ssh-host-password-file**=] [**--ssh-user-password-file**=] diff --git a/pki/pki.go b/pki/pki.go index 61e20b6b..5f2afedd 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -29,9 +29,9 @@ import ( "github.com/smallstep/certificates/kms" kmsapi "github.com/smallstep/certificates/kms/apiv1" "github.com/smallstep/nosql" - "go.step.sm/cli-utils/config" "go.step.sm/cli-utils/errs" "go.step.sm/cli-utils/fileutil" + "go.step.sm/cli-utils/step" "go.step.sm/cli-utils/ui" "go.step.sm/crypto/jose" "go.step.sm/crypto/pemutil" @@ -89,42 +89,42 @@ const ( // GetDBPath returns the path where the file-system persistence is stored // based on the STEPPATH environment variable. func GetDBPath() string { - return filepath.Join(config.StepPath(), dbPath) + return filepath.Join(step.Path(), dbPath) } // GetConfigPath returns the directory where the configuration files are stored // based on the STEPPATH environment variable. func GetConfigPath() string { - return filepath.Join(config.StepPath(), configPath) + return filepath.Join(step.Path(), configPath) } // GetPublicPath returns the directory where the public keys are stored based on // the STEPPATH environment variable. func GetPublicPath() string { - return filepath.Join(config.StepPath(), publicPath) + return filepath.Join(step.Path(), publicPath) } // GetSecretsPath returns the directory where the private keys are stored based // on the STEPPATH environment variable. func GetSecretsPath() string { - return filepath.Join(config.StepPath(), privatePath) + return filepath.Join(step.Path(), privatePath) } // GetRootCAPath returns the path where the root CA is stored based on the // STEPPATH environment variable. func GetRootCAPath() string { - return filepath.Join(config.StepPath(), publicPath, "root_ca.crt") + return filepath.Join(step.Path(), publicPath, "root_ca.crt") } // GetOTTKeyPath returns the path where the one-time token key is stored based // on the STEPPATH environment variable. func GetOTTKeyPath() string { - return filepath.Join(config.StepPath(), privatePath, "ott_key") + return filepath.Join(step.Path(), privatePath, "ott_key") } // GetTemplatesPath returns the path where the templates are stored. func GetTemplatesPath() string { - return filepath.Join(config.StepPath(), templatesPath) + return filepath.Join(step.Path(), templatesPath) } // GetProvisioners returns the map of provisioners on the given CA. diff --git a/pki/templates.go b/pki/templates.go index 3506a96d..0ccbed8b 100644 --- a/pki/templates.go +++ b/pki/templates.go @@ -6,9 +6,9 @@ import ( "github.com/pkg/errors" "github.com/smallstep/certificates/templates" - "go.step.sm/cli-utils/config" "go.step.sm/cli-utils/errs" "go.step.sm/cli-utils/fileutil" + "go.step.sm/cli-utils/step" ) // getTemplates returns all the templates enabled @@ -44,7 +44,7 @@ func generateTemplates(t *templates.Templates) error { if !ok { return errors.Errorf("template %s does not exists", t.Name) } - if err := fileutil.WriteFile(config.StepAbs(t.TemplatePath), []byte(data), 0644); err != nil { + if err := fileutil.WriteFile(step.Abs(t.TemplatePath), []byte(data), 0644); err != nil { return err } } @@ -53,7 +53,7 @@ func generateTemplates(t *templates.Templates) error { if !ok { return errors.Errorf("template %s does not exists", t.Name) } - if err := fileutil.WriteFile(config.StepAbs(t.TemplatePath), []byte(data), 0644); err != nil { + if err := fileutil.WriteFile(step.Abs(t.TemplatePath), []byte(data), 0644); err != nil { return err } } From 7eeebca529cfdf914101a89c23e762b72816651f Mon Sep 17 00:00:00 2001 From: max furman Date: Fri, 13 Aug 2021 00:16:41 -0700 Subject: [PATCH 07/34] Enable step path contexts in identity and pki paths --- ca/identity/identity.go | 8 ++++---- pki/pki.go | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/ca/identity/identity.go b/ca/identity/identity.go index 14a22eb9..7d80ef70 100644 --- a/ca/identity/identity.go +++ b/ca/identity/identity.go @@ -40,10 +40,10 @@ const TunnelTLS Type = "tTLS" const DefaultLeeway = 1 * time.Minute // IdentityFile contains the location of the identity file. -var IdentityFile = filepath.Join(step.Path(), "config", "identity.json") +var IdentityFile = filepath.Join(step.ProfilePath(), "config", "identity.json") // DefaultsFile contains the location of the defaults file. -var DefaultsFile = filepath.Join(step.Path(), "config", "defaults.json") +var DefaultsFile = filepath.Join(step.ProfilePath(), "config", "defaults.json") // Identity represents the identity file that can be used to authenticate with // the CA. @@ -80,8 +80,8 @@ func LoadDefaultIdentity() (*Identity, error) { // configDir and identityDir are used in WriteDefaultIdentity for testing // purposes. var ( - configDir = filepath.Join(step.Path(), "config") - identityDir = filepath.Join(step.Path(), "identity") + configDir = filepath.Join(step.ProfilePath(), "config") + identityDir = filepath.Join(step.ProfilePath(), "identity") ) // WriteDefaultIdentity writes the given certificates and key and the diff --git a/pki/pki.go b/pki/pki.go index 5f2afedd..b0f2c886 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -10,6 +10,7 @@ import ( "encoding/json" "encoding/pem" "fmt" + "io/ioutil" "net" "os" "path/filepath" @@ -98,6 +99,12 @@ func GetConfigPath() string { return filepath.Join(step.Path(), configPath) } +// GetProfileConfigPath returns the directory where the profile configuration +// files are stored based on the STEPPATH environment variable. +func GetProfileConfigPath() string { + return filepath.Join(step.ProfilePath(), configPath) +} + // GetPublicPath returns the directory where the public keys are stored based on // the STEPPATH environment variable. func GetPublicPath() string { @@ -367,6 +374,21 @@ func New(o apiv1.Options, opts ...Option) (*PKI, error) { } } + // Create profile directory and stub for default profile configuration. + if currentCtx := step.GetCurrentContext(); currentCtx != nil { + profile := GetProfileConfigPath() + if err := os.MkdirAll(profile, 0700); err != nil { + return nil, errs.FileError(err, profile) + } + if p.profileDefaults, err = getPath(profile, "defaults.json"); err != nil { + return nil, err + } + if err := ioutil.WriteFile(p.profileDefaults, + []byte("{}"), 0600); err != nil { + return nil, err + } + } + if p.Defaults.CaUrl == "" { p.Defaults.CaUrl = p.DnsNames[0] _, port, err := net.SplitHostPort(p.Address) @@ -958,6 +980,9 @@ func (p *PKI) Save(opt ...ConfigOption) error { } ui.PrintSelected("Default configuration", p.defaults) + if p.profileDefaults != "" { + ui.PrintSelected("Profile default configuration", p.profileDefaults) + } ui.PrintSelected("Certificate Authority configuration", p.config) if p.options.deploymentType != LinkedDeployment { ui.Println() From ed4b56732e00cf1ed34e377641a98a959a4e3bc3 Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 18 Oct 2021 13:56:24 -0700 Subject: [PATCH 08/34] updates after rebase to keep up with master --- authority/export.go | 6 +++--- authority/provisioners.go | 6 +++--- pki/pki.go | 21 +++++++++++---------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/authority/export.go b/authority/export.go index 8a5a257f..dce52292 100644 --- a/authority/export.go +++ b/authority/export.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" "github.com/smallstep/certificates/authority/provisioner" - "go.step.sm/cli-utils/config" + "go.step.sm/cli-utils/step" "go.step.sm/linkedca" "google.golang.org/protobuf/types/known/structpb" ) @@ -245,7 +245,7 @@ func mustReadFileOrURI(fn string, m map[string][]byte) string { return "" } - stepPath := filepath.ToSlash(config.StepPath()) + stepPath := filepath.ToSlash(step.Path()) if !strings.HasSuffix(stepPath, "/") { stepPath += "/" } @@ -257,7 +257,7 @@ func mustReadFileOrURI(fn string, m map[string][]byte) string { panic(err) } if ok { - b, err := ioutil.ReadFile(config.StepAbs(fn)) + b, err := ioutil.ReadFile(step.Abs(fn)) if err != nil { panic(errors.Wrapf(err, "error reading %s", fn)) } diff --git a/authority/provisioners.go b/authority/provisioners.go index 7e02126f..8aebcc3e 100644 --- a/authority/provisioners.go +++ b/authority/provisioners.go @@ -13,7 +13,7 @@ import ( "github.com/smallstep/certificates/authority/config" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/errs" - step "go.step.sm/cli-utils/config" + "go.step.sm/cli-utils/step" "go.step.sm/cli-utils/ui" "go.step.sm/crypto/jose" "go.step.sm/linkedca" @@ -523,7 +523,7 @@ func provisionerOptionsToLinkedca(p *provisioner.Options) (*linkedca.Template, * if p.X509.Template != "" { x509Template.Template = []byte(p.SSH.Template) } else if p.X509.TemplateFile != "" { - filename := step.StepAbs(p.X509.TemplateFile) + filename := step.Abs(p.X509.TemplateFile) if x509Template.Template, err = ioutil.ReadFile(filename); err != nil { return nil, nil, errors.Wrap(err, "error reading x509 template") } @@ -539,7 +539,7 @@ func provisionerOptionsToLinkedca(p *provisioner.Options) (*linkedca.Template, * if p.SSH.Template != "" { sshTemplate.Template = []byte(p.SSH.Template) } else if p.SSH.TemplateFile != "" { - filename := step.StepAbs(p.SSH.TemplateFile) + filename := step.Abs(p.SSH.TemplateFile) if sshTemplate.Template, err = ioutil.ReadFile(filename); err != nil { return nil, nil, errors.Wrap(err, "error reading ssh template") } diff --git a/pki/pki.go b/pki/pki.go index b0f2c886..8bc07dae 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -293,16 +293,17 @@ func WithKeyURIs(rootKey, intermediateKey, hostKey, userKey string) Option { // PKI represents the Public Key Infrastructure used by a certificate authority. type PKI struct { linkedca.Configuration - Defaults linkedca.Defaults - casOptions apiv1.Options - caService apiv1.CertificateAuthorityService - caCreator apiv1.CertificateAuthorityCreator - keyManager kmsapi.KeyManager - config string - defaults string - ottPublicKey *jose.JSONWebKey - ottPrivateKey *jose.JSONWebEncryption - options *options + Defaults linkedca.Defaults + casOptions apiv1.Options + caService apiv1.CertificateAuthorityService + caCreator apiv1.CertificateAuthorityCreator + keyManager kmsapi.KeyManager + config string + defaults string + profileDefaults string + ottPublicKey *jose.JSONWebKey + ottPrivateKey *jose.JSONWebEncryption + options *options } // New creates a new PKI configuration. From e5951fd84c0a043965e9533f4a12b89070dfa37f Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 20 Oct 2021 12:41:24 -0700 Subject: [PATCH 09/34] Use methods in the step package * rather than variables set at execution time, which may not match the actual current context --- ca/identity/client.go | 14 ++++++++------ ca/identity/identity.go | 30 +++++++++++++----------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/ca/identity/client.go b/ca/identity/client.go index 4377638f..6f862115 100644 --- a/ca/identity/client.go +++ b/ca/identity/client.go @@ -10,6 +10,7 @@ import ( "net/url" "github.com/pkg/errors" + "go.step.sm/cli-utils/step" ) // Client wraps http.Client with a transport using the step root and identity. @@ -27,21 +28,22 @@ func (c *Client) ResolveReference(ref *url.URL) *url.URL { // $STEPPATH/config/defaults.json and the identity defined in // $STEPPATH/config/identity.json func LoadClient() (*Client, error) { - b, err := ioutil.ReadFile(DefaultsFile) + defaultsFile := step.DefaultsFile() + b, err := ioutil.ReadFile(defaultsFile) if err != nil { - return nil, errors.Wrapf(err, "error reading %s", DefaultsFile) + return nil, errors.Wrapf(err, "error reading %s", defaultsFile) } var defaults defaultsConfig if err := json.Unmarshal(b, &defaults); err != nil { - return nil, errors.Wrapf(err, "error unmarshaling %s", DefaultsFile) + return nil, errors.Wrapf(err, "error unmarshaling %s", defaultsFile) } if err := defaults.Validate(); err != nil { - return nil, errors.Wrapf(err, "error validating %s", DefaultsFile) + return nil, errors.Wrapf(err, "error validating %s", defaultsFile) } caURL, err := url.Parse(defaults.CaURL) if err != nil { - return nil, errors.Wrapf(err, "error validating %s", DefaultsFile) + return nil, errors.Wrapf(err, "error validating %s", defaultsFile) } if caURL.Scheme == "" { caURL.Scheme = "https" @@ -52,7 +54,7 @@ func LoadClient() (*Client, error) { return nil, err } if err := identity.Validate(); err != nil { - return nil, errors.Wrapf(err, "error validating %s", IdentityFile) + return nil, errors.Wrapf(err, "error validating %s", step.IdentityFile()) } if kind := identity.Kind(); kind != MutualTLS { return nil, errors.Errorf("unsupported identity %s: only mTLS is currently supported", kind) diff --git a/ca/identity/identity.go b/ca/identity/identity.go index 7d80ef70..e8760c50 100644 --- a/ca/identity/identity.go +++ b/ca/identity/identity.go @@ -39,12 +39,6 @@ const TunnelTLS Type = "tTLS" // DefaultLeeway is the duration for matching not before claims. const DefaultLeeway = 1 * time.Minute -// IdentityFile contains the location of the identity file. -var IdentityFile = filepath.Join(step.ProfilePath(), "config", "identity.json") - -// DefaultsFile contains the location of the defaults file. -var DefaultsFile = filepath.Join(step.ProfilePath(), "config", "defaults.json") - // Identity represents the identity file that can be used to authenticate with // the CA. type Identity struct { @@ -74,23 +68,25 @@ func LoadIdentity(filename string) (*Identity, error) { // LoadDefaultIdentity loads the default identity. func LoadDefaultIdentity() (*Identity, error) { - return LoadIdentity(IdentityFile) + return LoadIdentity(step.IdentityFile()) } -// configDir and identityDir are used in WriteDefaultIdentity for testing -// purposes. -var ( - configDir = filepath.Join(step.ProfilePath(), "config") - identityDir = filepath.Join(step.ProfilePath(), "identity") -) +func profileConfigDir() string { + return filepath.Join(step.ProfilePath(), "config") +} + +func profileIdentityDir() string { + return filepath.Join(step.ProfilePath(), "identity") +} // WriteDefaultIdentity writes the given certificates and key and the // identity.json pointing to the new files. func WriteDefaultIdentity(certChain []api.Certificate, key crypto.PrivateKey) error { - if err := os.MkdirAll(configDir, 0700); err != nil { + if err := os.MkdirAll(profileConfigDir(), 0700); err != nil { return errors.Wrap(err, "error creating config directory") } + identityDir := profileIdentityDir() if err := os.MkdirAll(identityDir, 0700); err != nil { return errors.Wrap(err, "error creating identity directory") } @@ -127,7 +123,7 @@ func WriteDefaultIdentity(certChain []api.Certificate, key crypto.PrivateKey) er }); err != nil { return errors.Wrap(err, "error writing identity json") } - if err := ioutil.WriteFile(IdentityFile, buf.Bytes(), 0600); err != nil { + if err := ioutil.WriteFile(step.IdentityFile(), buf.Bytes(), 0600); err != nil { return errors.Wrap(err, "error writing identity certificate") } @@ -136,7 +132,7 @@ func WriteDefaultIdentity(certChain []api.Certificate, key crypto.PrivateKey) er // WriteIdentityCertificate writes the identity certificate to disk. func WriteIdentityCertificate(certChain []api.Certificate) error { - filename := filepath.Join(identityDir, "identity.crt") + filename := filepath.Join(profileIdentityDir(), "identity.crt") return writeCertificate(filename, certChain) } @@ -319,7 +315,7 @@ func (i *Identity) Renew(client Renewer) error { return errors.Wrap(err, "error encoding identity certificate") } } - certFilename := filepath.Join(identityDir, "identity.crt") + certFilename := filepath.Join(profileIdentityDir(), "identity.crt") if err := ioutil.WriteFile(certFilename, buf.Bytes(), 0600); err != nil { return errors.Wrap(err, "error writing identity certificate") } From d777fc23c26ab9d3347bdfe060e036a8ea1dab38 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 28 Oct 2021 23:58:18 -0700 Subject: [PATCH 10/34] Add ca.WithInsecure and use methods for file names --- ca/client.go | 13 ++++++++++++- ca/identity/identity.go | 4 ++-- pki/pki.go | 7 ++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ca/client.go b/ca/client.go index aa1e38dd..9bcf1eb4 100644 --- a/ca/client.go +++ b/ca/client.go @@ -226,7 +226,7 @@ func (o *clientOptions) getTransport(endpoint string) (tr http.RoundTripper, err return tr, nil } -// WithTransport adds a custom transport to the Client. It will fail if a +// WithTransport adds a custom transport to the Client. It will fail if a // previous option to create the transport has been configured. func WithTransport(tr http.RoundTripper) ClientOption { return func(o *clientOptions) error { @@ -238,6 +238,17 @@ func WithTransport(tr http.RoundTripper) ClientOption { } } +// WithInsecure adds a insecure transport that bypasses TLS verification. +func WithInsecure() ClientOption { + return func(o *clientOptions) error { + o.transport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + return nil + } +} + // WithRootFile will create the transport using the given root certificate. It // will fail if a previous option to create the transport has been configured. func WithRootFile(filename string) ClientOption { diff --git a/ca/identity/identity.go b/ca/identity/identity.go index e8760c50..c294d982 100644 --- a/ca/identity/identity.go +++ b/ca/identity/identity.go @@ -72,11 +72,11 @@ func LoadDefaultIdentity() (*Identity, error) { } func profileConfigDir() string { - return filepath.Join(step.ProfilePath(), "config") + return filepath.Join(step.Path(), "config") } func profileIdentityDir() string { - return filepath.Join(step.ProfilePath(), "identity") + return filepath.Join(step.Path(), "identity") } // WriteDefaultIdentity writes the given certificates and key and the diff --git a/pki/pki.go b/pki/pki.go index 8bc07dae..ae6b712c 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -376,15 +376,12 @@ func New(o apiv1.Options, opts ...Option) (*PKI, error) { } // Create profile directory and stub for default profile configuration. - if currentCtx := step.GetCurrentContext(); currentCtx != nil { + if currentCtx := step.Contexts().GetCurrent(); currentCtx != nil { profile := GetProfileConfigPath() if err := os.MkdirAll(profile, 0700); err != nil { return nil, errs.FileError(err, profile) } - if p.profileDefaults, err = getPath(profile, "defaults.json"); err != nil { - return nil, err - } - if err := ioutil.WriteFile(p.profileDefaults, + if err := ioutil.WriteFile(step.ProfileDefaultsFile(), []byte("{}"), 0600); err != nil { return nil, err } From b080b7582bbceee5d9ab5ad3fb0dd784dc276a51 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 9 Nov 2021 15:26:34 -0800 Subject: [PATCH 11/34] Template updates to support multiple SSH include snippets --- templates/templates.go | 20 ++++++++++++++------ templates/values.go | 11 +++++++---- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/templates/templates.go b/templates/templates.go index 4fb831d4..aa77a2ff 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -20,6 +20,8 @@ type TemplateType string const ( // Snippet will mark a template as a part of a file. Snippet TemplateType = "snippet" + // FullSnippet will mark a template that includes header and footer as a part of a file. + FullSnippet TemplateType = "fullSnippet" // File will mark a templates as a full file. File TemplateType = "file" // Directory will mark a template as a directory. @@ -99,7 +101,7 @@ func (t *SSHTemplates) Validate() (err error) { return } -// Template represents on template file. +// Template represents a template file. type Template struct { *template.Template Name string `json:"name"` @@ -118,8 +120,8 @@ func (t *Template) Validate() error { return nil case t.Name == "": return errors.New("template name cannot be empty") - case t.Type != Snippet && t.Type != File && t.Type != Directory: - return errors.Errorf("invalid template type %s, it must be %s, %s, or %s", t.Type, Snippet, File, Directory) + case t.Type != Snippet && t.Type != File && t.Type != Directory && t.Type != FullSnippet: + return errors.Errorf("invalid template type %s, it must be %s, %s, %s, or %s", t.Type, Snippet, FullSnippet, File, Directory) case t.TemplatePath == "" && t.Type != Directory && len(t.Content) == 0: return errors.New("template template cannot be empty") case t.TemplatePath != "" && t.Type == Directory: @@ -257,11 +259,17 @@ func (o *Output) Write() error { return err } - if o.Type == File { + switch o.Type { + case File: return fileutil.WriteFile(path, o.Content, 0600) + case Snippet: + return fileutil.WriteSnippet(path, o.Content, 0600) + case FullSnippet: + lines := strings.Split(string(o.Content), "\n") + return fileutil.WriteFullSnippet(path, o.Content, lines[0], lines[len(lines)-1], 0600) + default: + return errors.Errorf("unexpected output template type %s", string(o.Type)) } - - return fileutil.WriteSnippet(path, o.Content, 0600) } func mkdir(path string, perm os.FileMode) error { diff --git a/templates/values.go b/templates/values.go index 972b1d55..0117cf52 100644 --- a/templates/values.go +++ b/templates/values.go @@ -23,7 +23,7 @@ var DefaultSSHTemplates = SSHTemplates{ User: []Template{ { Name: "include.tpl", - Type: Snippet, + Type: FullSnippet, TemplatePath: "templates/ssh/include.tpl", Path: "~/.ssh/config", Comment: "#", @@ -67,18 +67,21 @@ var DefaultSSHTemplateData = map[string]string{ // include.tpl adds the step ssh config file. // // Note: on windows `Include C:\...` is treated as a relative path. - "include.tpl": `Host * + "include.tpl": `{{- if .User.Authority }}# {{ .User.Authority }} +{{ end }}# autogenerated by step +# @ {{ now }} +Host * {{- if or .User.GOOS "none" | eq "windows" }} Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config" {{- else }} Include "{{.User.StepPath}}/ssh/config" -{{- end }}`, +{{ end }}# end`, // config.tpl is the step ssh config file, it includes the Match rule and // references the step known_hosts file. // // Note: on windows ProxyCommand requires the full path - "config.tpl": `Match exec "step ssh check-host %h" + "config.tpl": `Match exec "step ssh{{- if .User.Context }} --context {{ .User.Context }}{{- end }} check-host %h" {{- if .User.User }} User {{.User.User}} {{- end }} From da74fa2eb9c3d03917012265664772062c360349 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 9 Nov 2021 17:25:03 -0800 Subject: [PATCH 12/34] Rename FullSnippet to Fragment and remove unused replace in go.mod --- go.mod | 2 -- templates/templates.go | 12 ++++++------ templates/values.go | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 3b7c0f3a..346e0102 100644 --- a/go.mod +++ b/go.mod @@ -49,5 +49,3 @@ require ( //replace go.step.sm/crypto => ../crypto replace go.step.sm/cli-utils => ../cli-utils - -replace go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 => github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568 diff --git a/templates/templates.go b/templates/templates.go index aa77a2ff..bfc5b596 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -20,8 +20,8 @@ type TemplateType string const ( // Snippet will mark a template as a part of a file. Snippet TemplateType = "snippet" - // FullSnippet will mark a template that includes header and footer as a part of a file. - FullSnippet TemplateType = "fullSnippet" + // Fragment will mark a template that includes header and footer as a part of a file. + Fragment TemplateType = "fragment" // File will mark a templates as a full file. File TemplateType = "file" // Directory will mark a template as a directory. @@ -120,8 +120,8 @@ func (t *Template) Validate() error { return nil case t.Name == "": return errors.New("template name cannot be empty") - case t.Type != Snippet && t.Type != File && t.Type != Directory && t.Type != FullSnippet: - return errors.Errorf("invalid template type %s, it must be %s, %s, %s, or %s", t.Type, Snippet, FullSnippet, File, Directory) + case t.Type != Snippet && t.Type != File && t.Type != Directory && t.Type != Fragment: + return errors.Errorf("invalid template type %s, it must be %s, %s, %s, or %s", t.Type, Snippet, Fragment, File, Directory) case t.TemplatePath == "" && t.Type != Directory && len(t.Content) == 0: return errors.New("template template cannot be empty") case t.TemplatePath != "" && t.Type == Directory: @@ -264,9 +264,9 @@ func (o *Output) Write() error { return fileutil.WriteFile(path, o.Content, 0600) case Snippet: return fileutil.WriteSnippet(path, o.Content, 0600) - case FullSnippet: + case Fragment: lines := strings.Split(string(o.Content), "\n") - return fileutil.WriteFullSnippet(path, o.Content, lines[0], lines[len(lines)-1], 0600) + return fileutil.WriteFragment(path, o.Content, lines[0], lines[len(lines)-1], 0600) default: return errors.Errorf("unexpected output template type %s", string(o.Type)) } diff --git a/templates/values.go b/templates/values.go index 0117cf52..3749f9f0 100644 --- a/templates/values.go +++ b/templates/values.go @@ -23,7 +23,7 @@ var DefaultSSHTemplates = SSHTemplates{ User: []Template{ { Name: "include.tpl", - Type: FullSnippet, + Type: Fragment, TemplatePath: "templates/ssh/include.tpl", Path: "~/.ssh/config", Comment: "#", From 74eea883434a78f89544804336e8e0f9aa78a7a4 Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 10 Nov 2021 00:42:57 -0800 Subject: [PATCH 13/34] Replace Fragment template with Line --- templates/templates.go | 13 ++++++------ templates/values.go | 45 +++++++++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/templates/templates.go b/templates/templates.go index bfc5b596..ab0f1040 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -20,8 +20,8 @@ type TemplateType string const ( // Snippet will mark a template as a part of a file. Snippet TemplateType = "snippet" - // Fragment will mark a template that includes header and footer as a part of a file. - Fragment TemplateType = "fragment" + // Line is a template for a single line in a file. + Line TemplateType = "line" // File will mark a templates as a full file. File TemplateType = "file" // Directory will mark a template as a directory. @@ -120,8 +120,8 @@ func (t *Template) Validate() error { return nil case t.Name == "": return errors.New("template name cannot be empty") - case t.Type != Snippet && t.Type != File && t.Type != Directory && t.Type != Fragment: - return errors.Errorf("invalid template type %s, it must be %s, %s, %s, or %s", t.Type, Snippet, Fragment, File, Directory) + case t.Type != Snippet && t.Type != File && t.Type != Directory && t.Type != Line: + return errors.Errorf("invalid template type %s, it must be %s, %s, %s, or %s", t.Type, Snippet, Line, File, Directory) case t.TemplatePath == "" && t.Type != Directory && len(t.Content) == 0: return errors.New("template template cannot be empty") case t.TemplatePath != "" && t.Type == Directory: @@ -264,9 +264,8 @@ func (o *Output) Write() error { return fileutil.WriteFile(path, o.Content, 0600) case Snippet: return fileutil.WriteSnippet(path, o.Content, 0600) - case Fragment: - lines := strings.Split(string(o.Content), "\n") - return fileutil.WriteFragment(path, o.Content, lines[0], lines[len(lines)-1], 0600) + case Line: + return fileutil.WriteLine(path, o.Content, 0600) default: return errors.Errorf("unexpected output template type %s", string(o.Type)) } diff --git a/templates/values.go b/templates/values.go index 3749f9f0..60c0ad8f 100644 --- a/templates/values.go +++ b/templates/values.go @@ -22,12 +22,19 @@ type StepSSH struct { var DefaultSSHTemplates = SSHTemplates{ User: []Template{ { - Name: "include.tpl", - Type: Fragment, - TemplatePath: "templates/ssh/include.tpl", + Name: "base_config.tpl", + Type: Snippet, + TemplatePath: "templates/ssh/base_config.tpl", Path: "~/.ssh/config", Comment: "#", }, + { + Name: "include.tpl", + Type: Line, + TemplatePath: "templates/ssh/include.tpl", + Path: "~/.ssh/include", + Comment: "#", + }, { Name: "config.tpl", Type: File, @@ -64,18 +71,28 @@ var DefaultSSHTemplates = SSHTemplates{ // DefaultSSHTemplateData contains the data of the default templates used on ssh. var DefaultSSHTemplateData = map[string]string{ + // base_config.tpl adds the step ssh config file. + // + // Note: on windows `Include C:\...` is treated as a relative path. + "base_config.tpl": `Host * +{{- if or .User.GOOS "none" | eq "windows" }} +{{- if .User.Authority }} + Include "{{ .User.Home | replace "\\" "/" | trimPrefix "C:" }}/.ssh/include" +{{- else }} + Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config" +{{- end }} +{{- else }} +{{- if .User.Authority }} + Include "{{.User.Home}}/.ssh/include" +{{- else }} + Include "{{.User.StepPath}}/ssh/config" +{{- end }} +{{- end }}`, + // include.tpl adds the step ssh config file. // // Note: on windows `Include C:\...` is treated as a relative path. - "include.tpl": `{{- if .User.Authority }}# {{ .User.Authority }} -{{ end }}# autogenerated by step -# @ {{ now }} -Host * -{{- if or .User.GOOS "none" | eq "windows" }} - Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config" -{{- else }} - Include "{{.User.StepPath}}/ssh/config" -{{ end }}# end`, + "include.tpl": `{{- if or .User.GOOS "none" | eq "windows" }}Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config"{{- else }}Include "{{.User.StepPath}}/ssh/config"{{- end }}`, // config.tpl is the step ssh config file, it includes the Match rule and // references the step known_hosts file. @@ -87,10 +104,10 @@ Host * {{- end }} {{- if or .User.GOOS "none" | eq "windows" }} UserKnownHostsFile "{{.User.StepPath}}\ssh\known_hosts" - ProxyCommand C:\Windows\System32\cmd.exe /c step ssh proxycommand %r %h %p + ProxyCommand C:\Windows\System32\cmd.exe /c step ssh proxycommand{{- if .User.Context }} --context {{ .User.Context }}{{- end }} %r %h %p {{- else }} UserKnownHostsFile "{{.User.StepPath}}/ssh/known_hosts" - ProxyCommand step ssh proxycommand %r %h %p + ProxyCommand step ssh proxycommand{{- if .User.Context }} --context {{ .User.Context }}{{- end }} %r %h %p {{- end }} `, From 9d4a7cf9fcd4dc155f373dfed3ac7b3db406746d Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 10 Nov 2021 14:53:44 -0800 Subject: [PATCH 14/34] Update includes template to use STEPPATH as the replace var --- templates/templates.go | 3 +++ templates/values.go | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/templates/templates.go b/templates/templates.go index ab0f1040..3a708731 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -249,6 +249,9 @@ type Output struct { // Write writes the Output to the filesystem as a directory, file or snippet. func (o *Output) Write() error { + // Replace ${STEPPATH} with the base step path. + o.Path = strings.Replace(o.Path, "${STEPPATH}", step.BasePath(), -1) + path := step.Abs(o.Path) if o.Type == Directory { return mkdir(path, 0700) diff --git a/templates/values.go b/templates/values.go index 60c0ad8f..c59843af 100644 --- a/templates/values.go +++ b/templates/values.go @@ -29,10 +29,10 @@ var DefaultSSHTemplates = SSHTemplates{ Comment: "#", }, { - Name: "include.tpl", + Name: "includes.tpl", Type: Line, - TemplatePath: "templates/ssh/include.tpl", - Path: "~/.ssh/include", + TemplatePath: "templates/ssh/includes.tpl", + Path: "${STEPPATH}/ssh/includes", Comment: "#", }, { @@ -77,22 +77,22 @@ var DefaultSSHTemplateData = map[string]string{ "base_config.tpl": `Host * {{- if or .User.GOOS "none" | eq "windows" }} {{- if .User.Authority }} - Include "{{ .User.Home | replace "\\" "/" | trimPrefix "C:" }}/.ssh/include" + Include "{{ .User.StepBasePath | replace "\\" "/" | trimPrefix "C:" }}/ssh/includes" {{- else }} Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config" {{- end }} {{- else }} {{- if .User.Authority }} - Include "{{.User.Home}}/.ssh/include" + Include "{{.User.StepBasePath}}/ssh/includes" {{- else }} Include "{{.User.StepPath}}/ssh/config" {{- end }} {{- end }}`, - // include.tpl adds the step ssh config file. + // includes.tpl adds the step ssh config file. // // Note: on windows `Include C:\...` is treated as a relative path. - "include.tpl": `{{- if or .User.GOOS "none" | eq "windows" }}Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config"{{- else }}Include "{{.User.StepPath}}/ssh/config"{{- end }}`, + "includes.tpl": `{{- if or .User.GOOS "none" | eq "windows" }}Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config"{{- else }}Include "{{.User.StepPath}}/ssh/config"{{- end }}`, // config.tpl is the step ssh config file, it includes the Match rule and // references the step known_hosts file. From c8560b4854766f920ff10f5668b9f4dfa322425d Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 10 Nov 2021 23:23:10 -0800 Subject: [PATCH 15/34] updated method name in cli-utils --- templates/templates.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/templates.go b/templates/templates.go index 3a708731..e760f0a4 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -268,7 +268,7 @@ func (o *Output) Write() error { case Snippet: return fileutil.WriteSnippet(path, o.Content, 0600) case Line: - return fileutil.WriteLine(path, o.Content, 0600) + return fileutil.PrependLine(path, o.Content, 0600) default: return errors.Errorf("unexpected output template type %s", string(o.Type)) } From 3e9830e36322e5387ae4fe48b2c6f129384188d4 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 11 Nov 2021 13:49:32 -0800 Subject: [PATCH 16/34] Use profileDefaults in PKI - write profile defaults at the same time as authority defaults --- pki/pki.go | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/pki/pki.go b/pki/pki.go index ae6b712c..58f256b1 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -10,7 +10,6 @@ import ( "encoding/json" "encoding/pem" "fmt" - "io/ioutil" "net" "os" "path/filepath" @@ -99,12 +98,6 @@ func GetConfigPath() string { return filepath.Join(step.Path(), configPath) } -// GetProfileConfigPath returns the directory where the profile configuration -// files are stored based on the STEPPATH environment variable. -func GetProfileConfigPath() string { - return filepath.Join(step.ProfilePath(), configPath) -} - // GetPublicPath returns the directory where the public keys are stored based on // the STEPPATH environment variable. func GetPublicPath() string { @@ -375,18 +368,6 @@ func New(o apiv1.Options, opts ...Option) (*PKI, error) { } } - // Create profile directory and stub for default profile configuration. - if currentCtx := step.Contexts().GetCurrent(); currentCtx != nil { - profile := GetProfileConfigPath() - if err := os.MkdirAll(profile, 0700); err != nil { - return nil, errs.FileError(err, profile) - } - if err := ioutil.WriteFile(step.ProfileDefaultsFile(), - []byte("{}"), 0600); err != nil { - return nil, err - } - } - if p.Defaults.CaUrl == "" { p.Defaults.CaUrl = p.DnsNames[0] _, port, err := net.SplitHostPort(p.Address) @@ -435,6 +416,10 @@ func New(o apiv1.Options, opts ...Option) (*PKI, error) { if p.defaults, err = getPath(cfg, "defaults.json"); err != nil { return nil, err } + if c := step.Contexts().GetCurrent(); c != nil { + p.profileDefaults = c.ProfileDefaultsFile() + } + if p.config, err = getPath(cfg, "ca.json"); err != nil { return nil, err } @@ -964,6 +949,11 @@ func (p *PKI) Save(opt ...ConfigOption) error { if err = fileutil.WriteFile(p.defaults, b, 0644); err != nil { return errs.FileError(err, p.defaults) } + if p.profileDefaults != "" { + if err = fileutil.WriteFile(p.profileDefaults, []byte("{}"), 0644); err != nil { + return errs.FileError(err, p.profileDefaults) + } + } // Generate and write templates if err := generateTemplates(cfg.Templates); err != nil { @@ -979,7 +969,7 @@ func (p *PKI) Save(opt ...ConfigOption) error { ui.PrintSelected("Default configuration", p.defaults) if p.profileDefaults != "" { - ui.PrintSelected("Profile default configuration", p.profileDefaults) + ui.PrintSelected("Default profile configuration", p.profileDefaults) } ui.PrintSelected("Certificate Authority configuration", p.config) if p.options.deploymentType != LinkedDeployment { From 43cba993bbe3abc68275a2fac1a2353b2091f255 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 11 Nov 2021 22:05:47 -0800 Subject: [PATCH 17/34] PR fixes - Line -> PrependLine - dont' overwrite profileDefaults - update ssh/config.tpl to always include includes file --- pki/pki.go | 6 +++++- templates/templates.go | 11 ++++++----- templates/values.go | 22 +++++++++++----------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/pki/pki.go b/pki/pki.go index 58f256b1..ea2da61e 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -950,7 +950,11 @@ func (p *PKI) Save(opt ...ConfigOption) error { return errs.FileError(err, p.defaults) } if p.profileDefaults != "" { - if err = fileutil.WriteFile(p.profileDefaults, []byte("{}"), 0644); err != nil { + if _, err := os.Stat(p.profileDefaults); os.IsNotExist(err) { + if err = fileutil.WriteFile(p.profileDefaults, []byte("{}"), 0644); err != nil { + return errs.FileError(err, p.profileDefaults) + } + } else if err != nil { return errs.FileError(err, p.profileDefaults) } } diff --git a/templates/templates.go b/templates/templates.go index e760f0a4..dee7aa5f 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -20,8 +20,9 @@ type TemplateType string const ( // Snippet will mark a template as a part of a file. Snippet TemplateType = "snippet" - // Line is a template for a single line in a file. - Line TemplateType = "line" + // PrependLine is a template for prepending a single line to a file. If the + // line already exists in the file it will be removed first. + PrependLine TemplateType = "prepend-line" // File will mark a templates as a full file. File TemplateType = "file" // Directory will mark a template as a directory. @@ -120,8 +121,8 @@ func (t *Template) Validate() error { return nil case t.Name == "": return errors.New("template name cannot be empty") - case t.Type != Snippet && t.Type != File && t.Type != Directory && t.Type != Line: - return errors.Errorf("invalid template type %s, it must be %s, %s, %s, or %s", t.Type, Snippet, Line, File, Directory) + case t.Type != Snippet && t.Type != File && t.Type != Directory && t.Type != PrependLine: + return errors.Errorf("invalid template type %s, it must be %s, %s, %s, or %s", t.Type, Snippet, PrependLine, File, Directory) case t.TemplatePath == "" && t.Type != Directory && len(t.Content) == 0: return errors.New("template template cannot be empty") case t.TemplatePath != "" && t.Type == Directory: @@ -267,7 +268,7 @@ func (o *Output) Write() error { return fileutil.WriteFile(path, o.Content, 0600) case Snippet: return fileutil.WriteSnippet(path, o.Content, 0600) - case Line: + case PrependLine: return fileutil.PrependLine(path, o.Content, 0600) default: return errors.Errorf("unexpected output template type %s", string(o.Type)) diff --git a/templates/values.go b/templates/values.go index c59843af..c5e3f291 100644 --- a/templates/values.go +++ b/templates/values.go @@ -22,23 +22,23 @@ type StepSSH struct { var DefaultSSHTemplates = SSHTemplates{ User: []Template{ { - Name: "base_config.tpl", + Name: "config.tpl", Type: Snippet, - TemplatePath: "templates/ssh/base_config.tpl", + TemplatePath: "templates/ssh/config.tpl", Path: "~/.ssh/config", Comment: "#", }, { - Name: "includes.tpl", - Type: Line, - TemplatePath: "templates/ssh/includes.tpl", + Name: "step_includes.tpl", + Type: PrependLine, + TemplatePath: "templates/ssh/step_includes.tpl", Path: "${STEPPATH}/ssh/includes", Comment: "#", }, { - Name: "config.tpl", + Name: "step_config.tpl", Type: File, - TemplatePath: "templates/ssh/config.tpl", + TemplatePath: "templates/ssh/step_config.tpl", Path: "ssh/config", Comment: "#", }, @@ -76,16 +76,16 @@ var DefaultSSHTemplateData = map[string]string{ // Note: on windows `Include C:\...` is treated as a relative path. "base_config.tpl": `Host * {{- if or .User.GOOS "none" | eq "windows" }} -{{- if .User.Authority }} +{{- if .User.StepBasePath }} Include "{{ .User.StepBasePath | replace "\\" "/" | trimPrefix "C:" }}/ssh/includes" {{- else }} - Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config" + Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/includes" {{- end }} {{- else }} -{{- if .User.Authority }} +{{- if .User.StepBasePath }} Include "{{.User.StepBasePath}}/ssh/includes" {{- else }} - Include "{{.User.StepPath}}/ssh/config" + Include "{{.User.StepPath}}/ssh/includes" {{- end }} {{- end }}`, From fcc15174ea7062736e6040cd97a83e9c261c6d40 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 11 Nov 2021 22:28:25 -0800 Subject: [PATCH 18/34] Rename templates and create profileConfig dir ahead of time. --- pki/pki.go | 26 ++++++++++++++++++-------- templates/values.go | 6 +++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/pki/pki.go b/pki/pki.go index ea2da61e..0c9d91e8 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -87,37 +87,43 @@ const ( ) // GetDBPath returns the path where the file-system persistence is stored -// based on the STEPPATH environment variable. +// based on the $(step path). func GetDBPath() string { return filepath.Join(step.Path(), dbPath) } // GetConfigPath returns the directory where the configuration files are stored -// based on the STEPPATH environment variable. +// based on the $(step path). func GetConfigPath() string { return filepath.Join(step.Path(), configPath) } +// GetProfileConfigPath returns the directory where the profile configuration +// files are stored based on the $(step path). +func GetProfileConfigPath() string { + return filepath.Join(step.ProfilePath(), configPath) +} + // GetPublicPath returns the directory where the public keys are stored based on -// the STEPPATH environment variable. +// the $(step path). func GetPublicPath() string { return filepath.Join(step.Path(), publicPath) } // GetSecretsPath returns the directory where the private keys are stored based -// on the STEPPATH environment variable. +// on the $(step path). func GetSecretsPath() string { return filepath.Join(step.Path(), privatePath) } // GetRootCAPath returns the path where the root CA is stored based on the -// STEPPATH environment variable. +// $(step path). func GetRootCAPath() string { return filepath.Join(step.Path(), publicPath, "root_ca.crt") } // GetOTTKeyPath returns the path where the one-time token key is stored based -// on the STEPPATH environment variable. +// on the $(step path). func GetOTTKeyPath() string { return filepath.Join(step.Path(), privatePath, "ott_key") } @@ -301,6 +307,7 @@ type PKI struct { // New creates a new PKI configuration. func New(o apiv1.Options, opts ...Option) (*PKI, error) { + currentCtx := step.Contexts().GetCurrent() caService, err := cas.New(context.Background(), o) if err != nil { return nil, err @@ -359,6 +366,9 @@ func New(o apiv1.Options, opts ...Option) (*PKI, error) { cfg = GetConfigPath() // Create directories dirs := []string{public, private, cfg, GetTemplatesPath()} + if currentCtx != nil { + dirs = append(dirs, GetProfileConfigPath()) + } for _, name := range dirs { if _, err := os.Stat(name); os.IsNotExist(err) { if err = os.MkdirAll(name, 0700); err != nil { @@ -416,8 +426,8 @@ func New(o apiv1.Options, opts ...Option) (*PKI, error) { if p.defaults, err = getPath(cfg, "defaults.json"); err != nil { return nil, err } - if c := step.Contexts().GetCurrent(); c != nil { - p.profileDefaults = c.ProfileDefaultsFile() + if currentCtx != nil { + p.profileDefaults = currentCtx.ProfileDefaultsFile() } if p.config, err = getPath(cfg, "ca.json"); err != nil { diff --git a/templates/values.go b/templates/values.go index c5e3f291..7a8e1765 100644 --- a/templates/values.go +++ b/templates/values.go @@ -74,7 +74,7 @@ var DefaultSSHTemplateData = map[string]string{ // base_config.tpl adds the step ssh config file. // // Note: on windows `Include C:\...` is treated as a relative path. - "base_config.tpl": `Host * + "config.tpl": `Host * {{- if or .User.GOOS "none" | eq "windows" }} {{- if .User.StepBasePath }} Include "{{ .User.StepBasePath | replace "\\" "/" | trimPrefix "C:" }}/ssh/includes" @@ -92,13 +92,13 @@ var DefaultSSHTemplateData = map[string]string{ // includes.tpl adds the step ssh config file. // // Note: on windows `Include C:\...` is treated as a relative path. - "includes.tpl": `{{- if or .User.GOOS "none" | eq "windows" }}Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config"{{- else }}Include "{{.User.StepPath}}/ssh/config"{{- end }}`, + "step_includes.tpl": `{{- if or .User.GOOS "none" | eq "windows" }}Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config"{{- else }}Include "{{.User.StepPath}}/ssh/config"{{- end }}`, // config.tpl is the step ssh config file, it includes the Match rule and // references the step known_hosts file. // // Note: on windows ProxyCommand requires the full path - "config.tpl": `Match exec "step ssh{{- if .User.Context }} --context {{ .User.Context }}{{- end }} check-host %h" + "step_config.tpl": `Match exec "step ssh{{- if .User.Context }} --context {{ .User.Context }}{{- end }} check-host %h" {{- if .User.User }} User {{.User.User}} {{- end }} From c80a64d0e6673d32161fb5d11944ccfd29c7b9bf Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 11 Nov 2021 22:51:46 -0800 Subject: [PATCH 19/34] ssh/step_config.tpl context flag in wrong spot --- templates/values.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/values.go b/templates/values.go index 7a8e1765..3cace69d 100644 --- a/templates/values.go +++ b/templates/values.go @@ -98,7 +98,7 @@ var DefaultSSHTemplateData = map[string]string{ // references the step known_hosts file. // // Note: on windows ProxyCommand requires the full path - "step_config.tpl": `Match exec "step ssh{{- if .User.Context }} --context {{ .User.Context }}{{- end }} check-host %h" + "step_config.tpl": `Match exec "step ssh check-host{{- if .User.Context }} --context {{ .User.Context }}{{- end }} %h" {{- if .User.User }} User {{.User.User}} {{- end }} From f426c152a935dd9d3e8624785fc6591c80720765 Mon Sep 17 00:00:00 2001 From: max furman Date: Fri, 12 Nov 2021 13:12:11 -0800 Subject: [PATCH 20/34] backwards compatibility for version of cli older than v0.18.0 --- authority/ssh.go | 7 +++++++ templates/templates.go | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/authority/ssh.go b/authority/ssh.go index 762319ae..da93acaf 100644 --- a/authority/ssh.go +++ b/authority/ssh.go @@ -101,6 +101,13 @@ func (a *Authority) GetSSHConfig(ctx context.Context, typ string, data map[strin if err != nil { return nil, err } + + // Backwards compatibility for version of the cli older than v0.18.0 + if o.Name == "step_includes.tpl" && (data == nil || data["Version"] != "v2") { + o.Type = templates.File + o.Path = strings.TrimPrefix(o.Path, "${STEPPATH}/") + } + output = append(output, o) } return output, nil diff --git a/templates/templates.go b/templates/templates.go index dee7aa5f..b18c176c 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -271,7 +271,8 @@ func (o *Output) Write() error { case PrependLine: return fileutil.PrependLine(path, o.Content, 0600) default: - return errors.Errorf("unexpected output template type %s", string(o.Type)) + // Default to using a Snippet type if the type is not known. + return fileutil.WriteSnippet(path, o.Content, 0600) } } From 507be61e8ca1971231ee7df059f500cf6c41c9b3 Mon Sep 17 00:00:00 2001 From: max furman Date: Sat, 13 Nov 2021 14:22:23 -0800 Subject: [PATCH 21/34] Use a more distint map key to indicate template version - make the key a variable that can be reused on the CLI side. --- authority/ssh.go | 2 +- templates/values.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/authority/ssh.go b/authority/ssh.go index da93acaf..d5d6ce45 100644 --- a/authority/ssh.go +++ b/authority/ssh.go @@ -103,7 +103,7 @@ func (a *Authority) GetSSHConfig(ctx context.Context, typ string, data map[strin } // Backwards compatibility for version of the cli older than v0.18.0 - if o.Name == "step_includes.tpl" && (data == nil || data["Version"] != "v2") { + if o.Name == "step_includes.tpl" && (data == nil || data[templates.SSHTemplateVersionKey] != "v2") { o.Type = templates.File o.Path = strings.TrimPrefix(o.Path, "${STEPPATH}/") } diff --git a/templates/values.go b/templates/values.go index 3cace69d..c3362527 100644 --- a/templates/values.go +++ b/templates/values.go @@ -4,6 +4,10 @@ import ( "golang.org/x/crypto/ssh" ) +// SSHTemplateVersionKey is a key that can be submitted by a client to select +// the template version that will be returned by the server. +var SSHTemplateVersionKey = "StepSSHTemplateVersion" + // Step represents the default variables available in the CA. type Step struct { SSH StepSSH From d37313bef4cbfdcb40380b481d71bc9b10936539 Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 15 Nov 2021 10:20:10 -0800 Subject: [PATCH 22/34] Use 0600 for profile defaults file. --- pki/pki.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pki/pki.go b/pki/pki.go index 0c9d91e8..effc1f22 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -959,9 +959,12 @@ func (p *PKI) Save(opt ...ConfigOption) error { if err = fileutil.WriteFile(p.defaults, b, 0644); err != nil { return errs.FileError(err, p.defaults) } + // If we're using contexts then write a blank object to the defualt profile + // configuration location. if p.profileDefaults != "" { if _, err := os.Stat(p.profileDefaults); os.IsNotExist(err) { - if err = fileutil.WriteFile(p.profileDefaults, []byte("{}"), 0644); err != nil { + // Write with 0600 to be consistent with directories structure. + if err = fileutil.WriteFile(p.profileDefaults, []byte("{}"), 0600); err != nil { return errs.FileError(err, p.profileDefaults) } } else if err != nil { From a7d144996f3a1f832419358021cbcfaad79a35fe Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 15 Nov 2021 15:32:07 -0800 Subject: [PATCH 23/34] SSH backwards compat updates - use existence of new value in data map as boolean - add tests for backwards and forwards compatibility - fix old tests that used static dir locations --- authority/ssh.go | 12 +++-- authority/ssh_test.go | 29 ++++++++++++ .../testdata/templates/step_includes.tpl | 1 + ca/identity/client.go | 5 +-- ca/identity/client_test.go | 42 ++++++++++-------- ca/identity/identity.go | 33 ++++++++------ ca/identity/identity_test.go | 44 +++++++++---------- 7 files changed, 105 insertions(+), 61 deletions(-) create mode 100644 authority/testdata/templates/step_includes.tpl diff --git a/authority/ssh.go b/authority/ssh.go index d5d6ce45..1b1645e4 100644 --- a/authority/ssh.go +++ b/authority/ssh.go @@ -102,10 +102,14 @@ func (a *Authority) GetSSHConfig(ctx context.Context, typ string, data map[strin return nil, err } - // Backwards compatibility for version of the cli older than v0.18.0 - if o.Name == "step_includes.tpl" && (data == nil || data[templates.SSHTemplateVersionKey] != "v2") { - o.Type = templates.File - o.Path = strings.TrimPrefix(o.Path, "${STEPPATH}/") + // Backwards compatibility for version of the cli older than v0.18.0. + // Before v0.18.0 we were not passing any value for SSHTemplateVersionKey + // from the cli. + if o.Name == "step_includes.tpl" { + if val, ok := data[templates.SSHTemplateVersionKey]; !ok || val == "" { + o.Type = templates.File + o.Path = strings.TrimPrefix(o.Path, "${STEPPATH}/") + } } output = append(output, o) diff --git a/authority/ssh_test.go b/authority/ssh_test.go index 41df8576..994d015f 100644 --- a/authority/ssh_test.go +++ b/authority/ssh_test.go @@ -501,6 +501,32 @@ func TestAuthority_GetSSHConfig(t *testing.T) { {Name: "sshd_config.tpl", Type: templates.File, Comment: "#", Path: "/etc/ssh/sshd_config", Content: []byte("Match all\n\tTrustedUserCAKeys /etc/ssh/ca.pub\n\tHostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub\n\tHostKey /etc/ssh/ssh_host_ecdsa_key")}, } + tmplConfigUserIncludes := &templates.Templates{ + SSH: &templates.SSHTemplates{ + User: []templates.Template{ + {Name: "step_includes.tpl", Type: templates.PrependLine, TemplatePath: "./testdata/templates/step_includes.tpl", Path: "${STEPPATH}/ssh/includes", Comment: "#"}, + }, + }, + Data: map[string]interface{}{ + "Step": &templates.Step{ + SSH: templates.StepSSH{ + UserKey: user, + HostKey: host, + }, + }, + }, + } + + userOutputEmptyData := []templates.Output{ + {Name: "step_includes.tpl", Type: templates.File, Comment: "#", Path: "ssh/includes", Content: []byte("Include \"/ssh/config\"\n")}, + } + userOutputWithoutTemplateVersion := []templates.Output{ + {Name: "step_includes.tpl", Type: templates.File, Comment: "#", Path: "ssh/includes", Content: []byte("Include \"/home/user/.step/ssh/config\"\n")}, + } + userOutputWithTemplateVersion := []templates.Output{ + {Name: "step_includes.tpl", Type: templates.PrependLine, Comment: "#", Path: "${STEPPATH}/ssh/includes", Content: []byte("Include \"/home/user/.step/ssh/config\"\n")}, + } + tmplConfigErr := &templates.Templates{ SSH: &templates.SSHTemplates{ User: []templates.Template{ @@ -542,6 +568,9 @@ func TestAuthority_GetSSHConfig(t *testing.T) { {"host", fields{tmplConfig, nil, hostSigner}, args{"host", nil}, hostOutput, false}, {"userWithData", fields{tmplConfigWithUserData, userSigner, hostSigner}, args{"user", map[string]string{"StepPath": "/home/user/.step"}}, userOutputWithUserData, false}, {"hostWithData", fields{tmplConfigWithUserData, userSigner, hostSigner}, args{"host", map[string]string{"Certificate": "ssh_host_ecdsa_key-cert.pub", "Key": "ssh_host_ecdsa_key"}}, hostOutputWithUserData, false}, + {"userIncludesEmptyData", fields{tmplConfigUserIncludes, userSigner, hostSigner}, args{"user", nil}, userOutputEmptyData, false}, + {"userIncludesWithoutTemplateVersion", fields{tmplConfigUserIncludes, userSigner, hostSigner}, args{"user", map[string]string{"StepPath": "/home/user/.step"}}, userOutputWithoutTemplateVersion, false}, + {"userIncludesWithTemplateVersion", fields{tmplConfigUserIncludes, userSigner, hostSigner}, args{"user", map[string]string{"StepPath": "/home/user/.step", "StepSSHTemplateVersion": "v2"}}, userOutputWithTemplateVersion, false}, {"disabled", fields{tmplConfig, nil, nil}, args{"host", nil}, nil, true}, {"badType", fields{tmplConfig, userSigner, hostSigner}, args{"bad", nil}, nil, true}, {"userError", fields{tmplConfigErr, userSigner, hostSigner}, args{"user", nil}, nil, true}, diff --git a/authority/testdata/templates/step_includes.tpl b/authority/testdata/templates/step_includes.tpl new file mode 100644 index 00000000..8c481bd8 --- /dev/null +++ b/authority/testdata/templates/step_includes.tpl @@ -0,0 +1 @@ +{{- if or .User.GOOS "none" | eq "windows" }}Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config"{{- else }}Include "{{.User.StepPath}}/ssh/config"{{- end }} diff --git a/ca/identity/client.go b/ca/identity/client.go index 6f862115..97389b2d 100644 --- a/ca/identity/client.go +++ b/ca/identity/client.go @@ -10,7 +10,6 @@ import ( "net/url" "github.com/pkg/errors" - "go.step.sm/cli-utils/step" ) // Client wraps http.Client with a transport using the step root and identity. @@ -28,7 +27,7 @@ func (c *Client) ResolveReference(ref *url.URL) *url.URL { // $STEPPATH/config/defaults.json and the identity defined in // $STEPPATH/config/identity.json func LoadClient() (*Client, error) { - defaultsFile := step.DefaultsFile() + defaultsFile := DefaultsFile() b, err := ioutil.ReadFile(defaultsFile) if err != nil { return nil, errors.Wrapf(err, "error reading %s", defaultsFile) @@ -54,7 +53,7 @@ func LoadClient() (*Client, error) { return nil, err } if err := identity.Validate(); err != nil { - return nil, errors.Wrapf(err, "error validating %s", step.IdentityFile()) + return nil, errors.Wrapf(err, "error validating %s", IdentityFile()) } if kind := identity.Kind(); kind != MutualTLS { return nil, errors.Errorf("unsupported identity %s: only mTLS is currently supported", kind) diff --git a/ca/identity/client_test.go b/ca/identity/client_test.go index 402ec7b8..40a35766 100644 --- a/ca/identity/client_test.go +++ b/ca/identity/client_test.go @@ -11,6 +11,12 @@ import ( "testing" ) +func returnInput(val string) func() string { + return func() string { + return val + } +} + func TestClient(t *testing.T) { oldIdentityFile := IdentityFile oldDefaultsFile := DefaultsFile @@ -19,8 +25,8 @@ func TestClient(t *testing.T) { DefaultsFile = oldDefaultsFile }() - IdentityFile = "testdata/config/identity.json" - DefaultsFile = "testdata/config/defaults.json" + IdentityFile = returnInput("testdata/config/identity.json") + DefaultsFile = returnInput("testdata/config/defaults.json") client, err := LoadClient() if err != nil { @@ -140,36 +146,36 @@ func TestLoadClient(t *testing.T) { wantErr bool }{ {"ok", func() { - IdentityFile = "testdata/config/identity.json" - DefaultsFile = "testdata/config/defaults.json" + IdentityFile = returnInput("testdata/config/identity.json") + DefaultsFile = returnInput("testdata/config/defaults.json") }, expected, false}, {"fail identity", func() { - IdentityFile = "testdata/config/missing.json" - DefaultsFile = "testdata/config/defaults.json" + IdentityFile = returnInput("testdata/config/missing.json") + DefaultsFile = returnInput("testdata/config/defaults.json") }, nil, true}, {"fail identity", func() { - IdentityFile = "testdata/config/fail.json" - DefaultsFile = "testdata/config/defaults.json" + IdentityFile = returnInput("testdata/config/fail.json") + DefaultsFile = returnInput("testdata/config/defaults.json") }, nil, true}, {"fail defaults", func() { - IdentityFile = "testdata/config/identity.json" - DefaultsFile = "testdata/config/missing.json" + IdentityFile = returnInput("testdata/config/identity.json") + DefaultsFile = returnInput("testdata/config/missing.json") }, nil, true}, {"fail defaults", func() { - IdentityFile = "testdata/config/identity.json" - DefaultsFile = "testdata/config/fail.json" + IdentityFile = returnInput("testdata/config/identity.json") + DefaultsFile = returnInput("testdata/config/fail.json") }, nil, true}, {"fail ca", func() { - IdentityFile = "testdata/config/identity.json" - DefaultsFile = "testdata/config/badca.json" + IdentityFile = returnInput("testdata/config/identity.json") + DefaultsFile = returnInput("testdata/config/badca.json") }, nil, true}, {"fail root", func() { - IdentityFile = "testdata/config/identity.json" - DefaultsFile = "testdata/config/badroot.json" + IdentityFile = returnInput("testdata/config/identity.json") + DefaultsFile = returnInput("testdata/config/badroot.json") }, nil, true}, {"fail type", func() { - IdentityFile = "testdata/config/badIdentity.json" - DefaultsFile = "testdata/config/defaults.json" + IdentityFile = returnInput("testdata/config/badIdentity.json") + DefaultsFile = returnInput("testdata/config/defaults.json") }, nil, true}, } for _, tt := range tests { diff --git a/ca/identity/identity.go b/ca/identity/identity.go index c294d982..c9bf765d 100644 --- a/ca/identity/identity.go +++ b/ca/identity/identity.go @@ -39,6 +39,19 @@ const TunnelTLS Type = "tTLS" // DefaultLeeway is the duration for matching not before claims. const DefaultLeeway = 1 * time.Minute +var ( + identityDir = step.IdentityPath + configDir = step.ConfigPath + + // IdentityFile contains a pointer to a function that outputs the location of + // the identity file. + IdentityFile = step.IdentityFile + + // DefaultsFile contains a prointer a function that outputs the location of the + // defaults configuration file. + DefaultsFile = step.DefaultsFile +) + // Identity represents the identity file that can be used to authenticate with // the CA. type Identity struct { @@ -68,25 +81,17 @@ func LoadIdentity(filename string) (*Identity, error) { // LoadDefaultIdentity loads the default identity. func LoadDefaultIdentity() (*Identity, error) { - return LoadIdentity(step.IdentityFile()) -} - -func profileConfigDir() string { - return filepath.Join(step.Path(), "config") -} - -func profileIdentityDir() string { - return filepath.Join(step.Path(), "identity") + return LoadIdentity(IdentityFile()) } // WriteDefaultIdentity writes the given certificates and key and the // identity.json pointing to the new files. func WriteDefaultIdentity(certChain []api.Certificate, key crypto.PrivateKey) error { - if err := os.MkdirAll(profileConfigDir(), 0700); err != nil { + if err := os.MkdirAll(configDir(), 0700); err != nil { return errors.Wrap(err, "error creating config directory") } - identityDir := profileIdentityDir() + identityDir := identityDir() if err := os.MkdirAll(identityDir, 0700); err != nil { return errors.Wrap(err, "error creating identity directory") } @@ -123,7 +128,7 @@ func WriteDefaultIdentity(certChain []api.Certificate, key crypto.PrivateKey) er }); err != nil { return errors.Wrap(err, "error writing identity json") } - if err := ioutil.WriteFile(step.IdentityFile(), buf.Bytes(), 0600); err != nil { + if err := ioutil.WriteFile(IdentityFile(), buf.Bytes(), 0600); err != nil { return errors.Wrap(err, "error writing identity certificate") } @@ -132,7 +137,7 @@ func WriteDefaultIdentity(certChain []api.Certificate, key crypto.PrivateKey) er // WriteIdentityCertificate writes the identity certificate to disk. func WriteIdentityCertificate(certChain []api.Certificate) error { - filename := filepath.Join(profileIdentityDir(), "identity.crt") + filename := filepath.Join(identityDir(), "identity.crt") return writeCertificate(filename, certChain) } @@ -315,7 +320,7 @@ func (i *Identity) Renew(client Renewer) error { return errors.Wrap(err, "error encoding identity certificate") } } - certFilename := filepath.Join(profileIdentityDir(), "identity.crt") + certFilename := filepath.Join(identityDir(), "identity.crt") if err := ioutil.WriteFile(certFilename, buf.Bytes(), 0600); err != nil { return errors.Wrap(err, "error writing identity certificate") } diff --git a/ca/identity/identity_test.go b/ca/identity/identity_test.go index ce64768c..d3b1d541 100644 --- a/ca/identity/identity_test.go +++ b/ca/identity/identity_test.go @@ -33,9 +33,9 @@ func TestLoadDefaultIdentity(t *testing.T) { want *Identity wantErr bool }{ - {"ok", func() { IdentityFile = "testdata/config/identity.json" }, expected, false}, - {"fail read", func() { IdentityFile = "testdata/config/missing.json" }, nil, true}, - {"fail unmarshal", func() { IdentityFile = "testdata/config/fail.json" }, nil, true}, + {"ok", func() { IdentityFile = returnInput("testdata/config/identity.json") }, expected, false}, + {"fail read", func() { IdentityFile = returnInput("testdata/config/missing.json") }, nil, true}, + {"fail unmarshal", func() { IdentityFile = returnInput("testdata/config/fail.json") }, nil, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -217,9 +217,9 @@ func TestWriteDefaultIdentity(t *testing.T) { certChain = append(certChain, api.Certificate{Certificate: c}) } - configDir = filepath.Join(tmpDir, "config") - identityDir = filepath.Join(tmpDir, "identity") - IdentityFile = filepath.Join(tmpDir, "config", "identity.json") + configDir = returnInput(filepath.Join(tmpDir, "config")) + identityDir = returnInput(filepath.Join(tmpDir, "identity")) + IdentityFile = returnInput(filepath.Join(tmpDir, "config", "identity.json")) type args struct { certChain []api.Certificate @@ -233,27 +233,27 @@ func TestWriteDefaultIdentity(t *testing.T) { }{ {"ok", func() {}, args{certChain, key}, false}, {"fail mkdir config", func() { - configDir = filepath.Join(tmpDir, "identity", "identity.crt") - identityDir = filepath.Join(tmpDir, "identity") + configDir = returnInput(filepath.Join(tmpDir, "identity", "identity.crt")) + identityDir = returnInput(filepath.Join(tmpDir, "identity")) }, args{certChain, key}, true}, {"fail mkdir identity", func() { - configDir = filepath.Join(tmpDir, "config") - identityDir = filepath.Join(tmpDir, "identity", "identity.crt") + configDir = returnInput(filepath.Join(tmpDir, "config")) + identityDir = returnInput(filepath.Join(tmpDir, "identity", "identity.crt")) }, args{certChain, key}, true}, {"fail certificate", func() { - configDir = filepath.Join(tmpDir, "config") - identityDir = filepath.Join(tmpDir, "bad-dir") - os.MkdirAll(identityDir, 0600) + configDir = returnInput(filepath.Join(tmpDir, "config")) + identityDir = returnInput(filepath.Join(tmpDir, "bad-dir")) + os.MkdirAll(identityDir(), 0600) }, args{certChain, key}, true}, {"fail key", func() { - configDir = filepath.Join(tmpDir, "config") - identityDir = filepath.Join(tmpDir, "identity") + configDir = returnInput(filepath.Join(tmpDir, "config")) + identityDir = returnInput(filepath.Join(tmpDir, "identity")) }, args{certChain, "badKey"}, true}, {"fail write identity", func() { - configDir = filepath.Join(tmpDir, "bad-dir") - identityDir = filepath.Join(tmpDir, "identity") - IdentityFile = filepath.Join(configDir, "identity.json") - os.MkdirAll(configDir, 0600) + configDir = returnInput(filepath.Join(tmpDir, "bad-dir")) + identityDir = returnInput(filepath.Join(tmpDir, "identity")) + IdentityFile = returnInput(filepath.Join(configDir(), "identity.json")) + os.MkdirAll(configDir(), 0600) }, args{certChain, key}, true}, } @@ -377,7 +377,7 @@ func TestIdentity_Renew(t *testing.T) { } oldIdentityDir := identityDir - identityDir = "testdata/identity" + identityDir = returnInput("testdata/identity") defer func() { identityDir = oldIdentityDir os.RemoveAll(tmpDir) @@ -432,8 +432,8 @@ func TestIdentity_Renew(t *testing.T) { {"fail renew", func() {}, fields{"mTLS", "testdata/identity/identity.crt", "testdata/identity/identity_key"}, args{fail}, true}, {"fail certificate", func() {}, fields{"mTLS", "testdata/certs/server.crt", "testdata/identity/identity_key"}, args{ok}, true}, {"fail write identity", func() { - identityDir = filepath.Join(tmpDir, "bad-dir") - os.MkdirAll(identityDir, 0600) + identityDir = returnInput(filepath.Join(tmpDir, "bad-dir")) + os.MkdirAll(identityDir(), 0600) }, fields{"mTLS", "testdata/identity/identity.crt", "testdata/identity/identity_key"}, args{ok}, true}, } for _, tt := range tests { From 922d2391715901cafa8ed8e7741b0303ff442087 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 16 Nov 2021 10:02:04 -0800 Subject: [PATCH 24/34] Simplify conditional --- authority/ssh.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/authority/ssh.go b/authority/ssh.go index 1b1645e4..bef673bf 100644 --- a/authority/ssh.go +++ b/authority/ssh.go @@ -105,11 +105,9 @@ func (a *Authority) GetSSHConfig(ctx context.Context, typ string, data map[strin // Backwards compatibility for version of the cli older than v0.18.0. // Before v0.18.0 we were not passing any value for SSHTemplateVersionKey // from the cli. - if o.Name == "step_includes.tpl" { - if val, ok := data[templates.SSHTemplateVersionKey]; !ok || val == "" { - o.Type = templates.File - o.Path = strings.TrimPrefix(o.Path, "${STEPPATH}/") - } + if o.Name == "step_includes.tpl" && data[templates.SSHTemplateVersionKey] == "" { + o.Type = templates.File + o.Path = strings.TrimPrefix(o.Path, "${STEPPATH}/") } output = append(output, o) From 555431448c55ae7bb7909097e456d8785a719d7f Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 16 Nov 2021 10:08:54 -0800 Subject: [PATCH 25/34] bump version ofcli-utils --- go.mod | 6 ++++-- go.sum | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 346e0102..221ec171 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,9 @@ require ( github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 github.com/googleapis/gax-go/v2 v2.0.5 + github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/lunixbochs/vtclean v1.0.0 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.13 // indirect github.com/micromdm/scep/v2 v2.1.0 @@ -32,7 +34,7 @@ require ( github.com/smallstep/nosql v0.3.8 github.com/urfave/cli v1.22.4 go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 - go.step.sm/cli-utils v0.6.2 + go.step.sm/cli-utils v0.7.0-rc1 go.step.sm/crypto v0.13.0 go.step.sm/linkedca v0.7.0 golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 @@ -48,4 +50,4 @@ require ( //replace go.step.sm/crypto => ../crypto -replace go.step.sm/cli-utils => ../cli-utils +//replace go.step.sm/cli-utils => ../cli-utils diff --git a/go.sum b/go.sum index 0f12f0a6..619b1cf3 100644 --- a/go.sum +++ b/go.sum @@ -376,6 +376,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo= +github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -561,8 +563,10 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.step.sm/cli-utils v0.6.2 h1:ofa3G/EqE3dTDXmzoXHDZr18qJZoFsKSzbzuF+mxuZU= -go.step.sm/cli-utils v0.6.2/go.mod h1:0tZ8F2QwLgD6KbKj4nrQZhMakTasEAnOcW3Ekc5pnrA= +go.step.sm/cli-utils v0.6.0 h1:sH4FxBcjmbxyilKXheSyJuKF/QjpojpiW90ERwUWOgQ= +go.step.sm/cli-utils v0.6.0/go.mod h1:jklBMavFl2PbmGlyxgax08ZnB0uWpadjuOlSKKXz+0U= +go.step.sm/cli-utils v0.7.0-rc1 h1:f5/dMhmo7j69xVz9DHkcgbDQOE0NdcSwC2fUnvaZD5c= +go.step.sm/cli-utils v0.7.0-rc1/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E= go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0= go.step.sm/crypto v0.13.0 h1:mQuP9Uu2FNmqCJNO0OTbvolnYXzONy4wdUBtUVcP1s8= go.step.sm/crypto v0.13.0/go.mod h1:5YzQ85BujYBu6NH18jw7nFjwuRnDch35nLzH0ES5sKg= From b5bf79b84ef2303c9f8d65138dbe138a66375bb6 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 16 Nov 2021 16:02:19 -0800 Subject: [PATCH 26/34] bump nosql library --- go.mod | 4 +--- go.sum | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 221ec171..88abd20f 100644 --- a/go.mod +++ b/go.mod @@ -20,9 +20,7 @@ require ( github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 github.com/googleapis/gax-go/v2 v2.0.5 - github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect - github.com/lunixbochs/vtclean v1.0.0 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.13 // indirect github.com/micromdm/scep/v2 v2.1.0 @@ -31,7 +29,7 @@ require ( github.com/rs/xid v1.2.1 github.com/sirupsen/logrus v1.4.2 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 - github.com/smallstep/nosql v0.3.8 + github.com/smallstep/nosql v0.3.9 github.com/urfave/cli v1.22.4 go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 go.step.sm/cli-utils v0.7.0-rc1 diff --git a/go.sum b/go.sum index 619b1cf3..96d49594 100644 --- a/go.sum +++ b/go.sum @@ -376,8 +376,6 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo= -github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -498,8 +496,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/smallstep/assert v0.0.0-20180720014142-de77670473b5/go.mod h1:TC9A4+RjIOS+HyTH7wG17/gSqVv95uDw2J64dQZx7RE= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= -github.com/smallstep/nosql v0.3.8 h1:1/EWUbbEdz9ai0g9Fd09VekVjtxp+5+gIHpV2PdwW3o= -github.com/smallstep/nosql v0.3.8/go.mod h1:X2qkYpNcW3yjLUvhEHfgGfClpKbFPapewvx7zo4TOFs= +github.com/smallstep/nosql v0.3.9 h1:YPy5PR3PXClqmpFaVv0wfXDXDc7NXGBE1auyU2c87dc= +github.com/smallstep/nosql v0.3.9/go.mod h1:X2qkYpNcW3yjLUvhEHfgGfClpKbFPapewvx7zo4TOFs= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -563,8 +561,6 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.step.sm/cli-utils v0.6.0 h1:sH4FxBcjmbxyilKXheSyJuKF/QjpojpiW90ERwUWOgQ= -go.step.sm/cli-utils v0.6.0/go.mod h1:jklBMavFl2PbmGlyxgax08ZnB0uWpadjuOlSKKXz+0U= go.step.sm/cli-utils v0.7.0-rc1 h1:f5/dMhmo7j69xVz9DHkcgbDQOE0NdcSwC2fUnvaZD5c= go.step.sm/cli-utils v0.7.0-rc1/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E= go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0= From 196f6b45c96bbf94ef16f34712721b7f363d519b Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 16 Nov 2021 21:43:53 -0800 Subject: [PATCH 27/34] bump cli-utils to 0.7.0 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 88abd20f..2253e816 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/smallstep/nosql v0.3.9 github.com/urfave/cli v1.22.4 go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 - go.step.sm/cli-utils v0.7.0-rc1 + go.step.sm/cli-utils v0.7.0 go.step.sm/crypto v0.13.0 go.step.sm/linkedca v0.7.0 golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 diff --git a/go.sum b/go.sum index 96d49594..4c0d4db1 100644 --- a/go.sum +++ b/go.sum @@ -561,8 +561,8 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.step.sm/cli-utils v0.7.0-rc1 h1:f5/dMhmo7j69xVz9DHkcgbDQOE0NdcSwC2fUnvaZD5c= -go.step.sm/cli-utils v0.7.0-rc1/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E= +go.step.sm/cli-utils v0.7.0 h1:2GvY5Muid1yzp7YQbfCCS+gK3q7zlHjjLL5Z0DXz8ds= +go.step.sm/cli-utils v0.7.0/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E= go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0= go.step.sm/crypto v0.13.0 h1:mQuP9Uu2FNmqCJNO0OTbvolnYXzONy4wdUBtUVcP1s8= go.step.sm/crypto v0.13.0/go.mod h1:5YzQ85BujYBu6NH18jw7nFjwuRnDch35nLzH0ES5sKg= From 41fec1577d0439e3c6666615b378b1b7a8e1698e Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Wed, 17 Nov 2021 11:46:57 -0800 Subject: [PATCH 28/34] Report duration errors directly to the cli. --- authority/provisioner/sign_options.go | 35 +++++++++++++++++++---- authority/provisioner/sign_ssh_options.go | 16 +++++------ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/authority/provisioner/sign_options.go b/authority/provisioner/sign_options.go index 764916b6..7268b63b 100644 --- a/authority/provisioner/sign_options.go +++ b/authority/provisioner/sign_options.go @@ -8,12 +8,15 @@ import ( "crypto/x509/pkix" "encoding/asn1" "encoding/json" + "fmt" "net" + "net/http" "net/url" "reflect" "time" "github.com/pkg/errors" + "github.com/smallstep/certificates/errs" "go.step.sm/crypto/x509util" ) @@ -369,6 +372,28 @@ func newValidityValidator(min, max time.Duration) *validityValidator { return &validityValidator{min: min, max: max} } +// TODO(mariano): refactor errs package to allow sending real errors to the +// user. +func badRequest(format string, args ...interface{}) error { + msg := fmt.Sprintf(format, args...) + return &errs.Error{ + Status: http.StatusBadRequest, + Msg: msg, + Err: errors.New(msg), + } +} + +// TODO(mariano): refactor errs package to allow sending real errors to the +// user. +func unauthorized(format string, args ...interface{}) error { + msg := fmt.Sprintf(format, args...) + return &errs.Error{ + Status: http.StatusUnauthorized, + Msg: msg, + Err: errors.New(msg), + } +} + // Valid validates the certificate validity settings (notBefore/notAfter) and // and total duration. func (v *validityValidator) Valid(cert *x509.Certificate, o SignOptions) error { @@ -381,22 +406,20 @@ func (v *validityValidator) Valid(cert *x509.Certificate, o SignOptions) error { d := na.Sub(nb) if na.Before(now) { - return errors.Errorf("notAfter cannot be in the past; na=%v", na) + return badRequest("notAfter cannot be in the past; na=%v", na) } if na.Before(nb) { - return errors.Errorf("notAfter cannot be before notBefore; na=%v, nb=%v", na, nb) + return badRequest("notAfter cannot be before notBefore; na=%v, nb=%v", na, nb) } if d < v.min { - return errors.Errorf("requested duration of %v is less than the authorized minimum certificate duration of %v", - d, v.min) + return unauthorized("requested duration of %v is less than the authorized minimum certificate duration of %v", d, v.min) } // NOTE: this check is not "technically correct". We're allowing the max // duration of a cert to be "max + backdate" and not all certificates will // be backdated (e.g. if a user passes the NotBefore value then we do not // apply a backdate). This is good enough. if d > v.max+o.Backdate { - return errors.Errorf("requested duration of %v is more than the authorized maximum certificate duration of %v", - d, v.max+o.Backdate) + return unauthorized("requested duration of %v is more than the authorized maximum certificate duration of %v", d, v.max+o.Backdate) } return nil } diff --git a/authority/provisioner/sign_ssh_options.go b/authority/provisioner/sign_ssh_options.go index 158470d1..e594c952 100644 --- a/authority/provisioner/sign_ssh_options.go +++ b/authority/provisioner/sign_ssh_options.go @@ -335,11 +335,11 @@ type sshCertValidityValidator struct { func (v *sshCertValidityValidator) Valid(cert *ssh.Certificate, opts SignSSHOptions) error { switch { case cert.ValidAfter == 0: - return errors.New("ssh certificate validAfter cannot be 0") + return badRequest("ssh certificate validAfter cannot be 0") case cert.ValidBefore < uint64(now().Unix()): - return errors.New("ssh certificate validBefore cannot be in the past") + return badRequest("ssh certificate validBefore cannot be in the past") case cert.ValidBefore < cert.ValidAfter: - return errors.New("ssh certificate validBefore cannot be before validAfter") + return badRequest("ssh certificate validBefore cannot be before validAfter") } var min, max time.Duration @@ -351,9 +351,9 @@ func (v *sshCertValidityValidator) Valid(cert *ssh.Certificate, opts SignSSHOpti min = v.MinHostSSHCertDuration() max = v.MaxHostSSHCertDuration() case 0: - return errors.New("ssh certificate type has not been set") + return badRequest("ssh certificate type has not been set") default: - return errors.Errorf("unknown ssh certificate type %d", cert.CertType) + return badRequest("unknown ssh certificate type %d", cert.CertType) } // To not take into account the backdate, time.Now() will be used to @@ -362,11 +362,9 @@ func (v *sshCertValidityValidator) Valid(cert *ssh.Certificate, opts SignSSHOpti switch { case dur < min: - return errors.Errorf("requested duration of %s is less than minimum "+ - "accepted duration for selected provisioner of %s", dur, min) + return unauthorized("requested duration of %s is less than minimum accepted duration for selected provisioner of %s", dur, min) case dur > max+opts.Backdate: - return errors.Errorf("requested duration of %s is greater than maximum "+ - "accepted duration for selected provisioner of %s", dur, max+opts.Backdate) + return unauthorized("requested duration of %s is greater than maximum accepted duration for selected provisioner of %s", dur, max+opts.Backdate) default: return nil } From df2843657f8a586a5800ab5383f61248df4aaac2 Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 17 Nov 2021 11:51:33 -0800 Subject: [PATCH 29/34] [action] only run codecov for go 1.17 --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 78b59f4b..10e7360d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,6 +58,7 @@ jobs: run: V=1 make ci - name: Codecov + if: matrix.go == '1.17' uses: codecov/codecov-action@v1.2.1 with: file: ./coverage.out # optional From 1aadd63cefc5d9281eb1644dcb505a96073cd2b6 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Wed, 17 Nov 2021 12:00:54 -0800 Subject: [PATCH 30/34] Use always badRequest on duration errors. --- authority/provisioner/sign_options.go | 15 ++------------- authority/provisioner/sign_ssh_options.go | 4 ++-- authority/tls_test.go | 2 +- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/authority/provisioner/sign_options.go b/authority/provisioner/sign_options.go index 7268b63b..6b013fc8 100644 --- a/authority/provisioner/sign_options.go +++ b/authority/provisioner/sign_options.go @@ -383,17 +383,6 @@ func badRequest(format string, args ...interface{}) error { } } -// TODO(mariano): refactor errs package to allow sending real errors to the -// user. -func unauthorized(format string, args ...interface{}) error { - msg := fmt.Sprintf(format, args...) - return &errs.Error{ - Status: http.StatusUnauthorized, - Msg: msg, - Err: errors.New(msg), - } -} - // Valid validates the certificate validity settings (notBefore/notAfter) and // and total duration. func (v *validityValidator) Valid(cert *x509.Certificate, o SignOptions) error { @@ -412,14 +401,14 @@ func (v *validityValidator) Valid(cert *x509.Certificate, o SignOptions) error { return badRequest("notAfter cannot be before notBefore; na=%v, nb=%v", na, nb) } if d < v.min { - return unauthorized("requested duration of %v is less than the authorized minimum certificate duration of %v", d, v.min) + return badRequest("requested duration of %v is less than the authorized minimum certificate duration of %v", d, v.min) } // NOTE: this check is not "technically correct". We're allowing the max // duration of a cert to be "max + backdate" and not all certificates will // be backdated (e.g. if a user passes the NotBefore value then we do not // apply a backdate). This is good enough. if d > v.max+o.Backdate { - return unauthorized("requested duration of %v is more than the authorized maximum certificate duration of %v", d, v.max+o.Backdate) + return badRequest("requested duration of %v is more than the authorized maximum certificate duration of %v", d, v.max+o.Backdate) } return nil } diff --git a/authority/provisioner/sign_ssh_options.go b/authority/provisioner/sign_ssh_options.go index e594c952..878d3d02 100644 --- a/authority/provisioner/sign_ssh_options.go +++ b/authority/provisioner/sign_ssh_options.go @@ -362,9 +362,9 @@ func (v *sshCertValidityValidator) Valid(cert *ssh.Certificate, opts SignSSHOpti switch { case dur < min: - return unauthorized("requested duration of %s is less than minimum accepted duration for selected provisioner of %s", dur, min) + return badRequest("requested duration of %s is less than minimum accepted duration for selected provisioner of %s", dur, min) case dur > max+opts.Backdate: - return unauthorized("requested duration of %s is greater than maximum accepted duration for selected provisioner of %s", dur, max+opts.Backdate) + return badRequest("requested duration of %s is greater than maximum accepted duration for selected provisioner of %s", dur, max+opts.Backdate) default: return nil } diff --git a/authority/tls_test.go b/authority/tls_test.go index f1d1748d..9fb47f00 100644 --- a/authority/tls_test.go +++ b/authority/tls_test.go @@ -310,7 +310,7 @@ func TestAuthority_Sign(t *testing.T) { extraOpts: extraOpts, signOpts: _signOpts, err: errors.New("authority.Sign: requested duration of 25h0m0s is more than the authorized maximum certificate duration of 24h1m0s"), - code: http.StatusUnauthorized, + code: http.StatusBadRequest, } }, "fail validate sans when adding common name not in claims": func(t *testing.T) *signTest { From acd0bac02523ff35681e938c606f653b8d9844a6 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Wed, 17 Nov 2021 12:03:29 -0800 Subject: [PATCH 31/34] Remove extra and in comment. --- authority/provisioner/sign_options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/authority/provisioner/sign_options.go b/authority/provisioner/sign_options.go index 6b013fc8..95f7fc39 100644 --- a/authority/provisioner/sign_options.go +++ b/authority/provisioner/sign_options.go @@ -384,7 +384,7 @@ func badRequest(format string, args ...interface{}) error { } // Valid validates the certificate validity settings (notBefore/notAfter) and -// and total duration. +// total duration. func (v *validityValidator) Valid(cert *x509.Certificate, o SignOptions) error { var ( na = cert.NotAfter.Truncate(time.Second) From fca7de6696ac8d366e11b83fe73b6d53e11cebf3 Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 17 Nov 2021 12:33:03 -0800 Subject: [PATCH 32/34] changelog update for 0.18.0 --- CHANGELOG.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a902e001..5e9d0bc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,15 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [Unreleased - 0.17.7] - DATE +## [Unreleased - 0.18.1] - DATE ### Added -- Support for generate extractable keys and certificates on a pkcs#11 module. ### Changed ### Deprecated ### Removed ### Fixed ### Security +## [0.18.0] - 2021-11-17 +### Added +- Support for multiple certificate authority contexts. +- Support for generating extractable keys and certificates on a pkcs#11 module. +### Changed +- Support two latest versions of golang (1.16, 1.17) +### Deprecated +- go 1.15 support + ## [0.17.6] - 2021-10-20 ### Notes - 0.17.5 failed in CI/CD From febb6198823b070f1d26e9e8c6207b4a1c5a8d97 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Wed, 17 Nov 2021 15:48:52 -0800 Subject: [PATCH 33/34] Add some extra validation and print certificate objects This commit also changes the following flags for consistency: - --crt-cert to --crt-cert-obj - --crt-key to --crt-key-obj --- cmd/step-pkcs11-init/main.go | 62 +++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/cmd/step-pkcs11-init/main.go b/cmd/step-pkcs11-init/main.go index 613b8208..5fadf10d 100644 --- a/cmd/step-pkcs11-init/main.go +++ b/cmd/step-pkcs11-init/main.go @@ -58,16 +58,25 @@ func (c *Config) Validate() error { switch { case c.KMS == "": return errors.New("flag `--kms` is required") + case c.CrtPath == "": + return errors.New("flag `--crt-cert-path` is required") case c.RootFile != "" && c.KeyFile == "": - return errors.New("flag `--root-cert-file` requires flag `--key`") + return errors.New("flag `--root-cert-file` requires flag `--root-key-file`") case c.KeyFile != "" && c.RootFile == "": - return errors.New("flag `--key` requires flag `--root-cert-file`") + return errors.New("flag `--root-key-file` requires flag `--root-cert-file`") case c.RootFile == "" && c.RootObject == "": - return errors.New("one of flag `--root` or `--root-cert` is required") - case c.RootFile == "" && c.RootKeyObject == "": - return errors.New("one of flag `--root` or `--root-key` is required") + return errors.New("one of flag `--root-cert-file` or `--root-cert-obj` is required") + case c.KeyFile == "" && c.RootKeyObject == "": + return errors.New("one of flag `--root-key-file` or `--root-key-obj` is required") + case c.CrtKeyPath == "" && c.CrtKeyObject == "": + return errors.New("one of flag `--crt-key-path` or `--crt-key-obj` is required") + case c.RootFile == "" && c.GenerateRoot && c.RootKeyObject == "": + return errors.New("flag `--root-gen` requires flag `--root-key-obj`") + case c.RootFile == "" && c.GenerateRoot && c.RootPath == "": + return errors.New("flag `--root-gen` requires `--root-cert-path`") default: if c.RootFile != "" { + c.GenerateRoot = false c.RootObject = "" c.RootKeyObject = "" } @@ -101,23 +110,25 @@ func main() { flag.StringVar(&c.Pin, "pin", "", "PKCS #11 PIN") // Option 1: Generate new root flag.BoolVar(&c.GenerateRoot, "root-gen", true, "Enable the generation of a root key.") - flag.StringVar(&c.RootFile, "root-cert-file", "", "Path to the root certificate to use.") + flag.StringVar(&c.RootSubject, "root-name", "PKCS #11 Smallstep Root", "Subject and Issuer of the root certificate.") flag.StringVar(&c.RootObject, "root-cert-obj", "pkcs11:id=7330;object=root-cert", "PKCS #11 URI with object id and label to store the root certificate.") flag.StringVar(&c.RootKeyObject, "root-key-obj", "pkcs11:id=7330;object=root-key", "PKCS #11 URI with object id and label to store the root key.") - flag.StringVar(&c.RootSubject, "root-name", "PKCS #11 Smallstep Root", "Subject and Issuer of the root certificate.") // Option 2: Read root from disk and sign intermediate - flag.StringVar(&c.RootPath, "root-cert-path", "root_ca.crt", "Location to write the root certificate.") + flag.StringVar(&c.RootFile, "root-cert-file", "", "Path to the root certificate to use.") flag.StringVar(&c.KeyFile, "root-key-file", "", "Path to the root key to use.") // Option 3: Generate certificate signing request - flag.StringVar(&c.CrtObject, "crt-cert", "pkcs11:id=7331;object=intermediate-cert", "PKCS #11 URI with object id and label to store the intermediate certificate.") - flag.StringVar(&c.CrtPath, "crt-cert-path", "intermediate_ca.crt", "Location to write the intermediate certificate.") - flag.StringVar(&c.CrtKeyObject, "crt-key", "pkcs11:id=7331;object=intermediate-key", "PKCS #11 URI with object id and label to store the intermediate certificate.") flag.StringVar(&c.CrtSubject, "crt-name", "PKCS #11 Smallstep Intermediate", "Subject of the intermediate certificate.") - flag.StringVar(&c.CrtKeyPath, "crt-key-path", "", "Location to write the intermediate private key.") + flag.StringVar(&c.CrtObject, "crt-cert-obj", "pkcs11:id=7331;object=intermediate-cert", "PKCS #11 URI with object id and label to store the intermediate certificate.") + flag.StringVar(&c.CrtKeyObject, "crt-key-obj", "pkcs11:id=7331;object=intermediate-key", "PKCS #11 URI with object id and label to store the intermediate certificate.") + // SSH certificates + flag.BoolVar(&c.EnableSSH, "ssh", false, "Enable the creation of ssh keys.") flag.StringVar(&c.SSHHostKeyObject, "ssh-host-key", "pkcs11:id=7332;object=ssh-host-key", "PKCS #11 URI with object id and label to store the key used to sign SSH host certificates.") flag.StringVar(&c.SSHUserKeyObject, "ssh-user-key", "pkcs11:id=7333;object=ssh-user-key", "PKCS #11 URI with object id and label to store the key used to sign SSH user certificates.") - - flag.BoolVar(&c.EnableSSH, "ssh", false, "Enable the creation of ssh keys.") + // Output files + flag.StringVar(&c.RootPath, "root-cert-path", "root_ca.crt", "Location to write the root certificate.") + flag.StringVar(&c.CrtPath, "crt-cert-path", "intermediate_ca.crt", "Location to write the intermediate certificate.") + flag.StringVar(&c.CrtKeyPath, "crt-key-path", "", "Location to write the intermediate private key.") + // Others flag.BoolVar(&c.NoCerts, "no-certs", false, "Do not store certificates in the module.") flag.BoolVar(&c.Force, "force", false, "Force the delete of previous keys.") flag.BoolVar(&c.Extractable, "extractable", false, "Allow export of private keys under wrap.") @@ -319,7 +330,7 @@ func createPKI(k kms.KeyManager, c Config) error { return errors.Wrap(err, "error parsing root certificate") } - if cm, ok := k.(kms.CertificateManager); ok && !c.NoCerts { + if cm, ok := k.(kms.CertificateManager); ok && c.RootObject != "" && !c.NoCerts { if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ Name: c.RootObject, Certificate: root, @@ -327,6 +338,8 @@ func createPKI(k kms.KeyManager, c Config) error { }); err != nil { return err } + } else { + c.RootObject = "" } if err := fileutil.WriteFile(c.RootPath, pem.EncodeToMemory(&pem.Block{ @@ -338,6 +351,9 @@ func createPKI(k kms.KeyManager, c Config) error { ui.PrintSelected("Root Key", resp.Name) ui.PrintSelected("Root Certificate", c.RootPath) + if c.RootObject != "" { + ui.PrintSelected("Root Certificate Object", c.RootObject) + } case c.RootFile != "" && c.KeyFile != "": // Read Root From File root, err = pemutil.ReadCertificate(c.RootFile) if err != nil { @@ -421,7 +437,7 @@ func createPKI(k kms.KeyManager, c Config) error { return errors.Wrap(err, "error parsing intermediate certificate") } - if cm, ok := k.(kms.CertificateManager); ok && !c.NoCerts { + if cm, ok := k.(kms.CertificateManager); ok && c.CrtObject != "" && !c.NoCerts { if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ Name: c.CrtObject, Certificate: intermediate, @@ -429,6 +445,8 @@ func createPKI(k kms.KeyManager, c Config) error { }); err != nil { return err } + } else { + c.CrtObject = "" } if err := fileutil.WriteFile(c.CrtPath, pem.EncodeToMemory(&pem.Block{ @@ -437,7 +455,8 @@ func createPKI(k kms.KeyManager, c Config) error { }), 0600); err != nil { return err } - } else { // No root available, generate CSR for external root. + } else { + // No root available, generate CSR for external root. csrTemplate := x509.CertificateRequest{ Subject: pkix.Name{CommonName: c.CrtSubject}, SignatureAlgorithm: x509.ECDSAWithSHA256, @@ -461,7 +480,14 @@ func createPKI(k kms.KeyManager, c Config) error { ui.PrintSelected("Intermediate Key", keyName) } - ui.PrintSelected("Intermediate Certificate", c.CrtPath) + if root != nil { + ui.PrintSelected("Intermediate Certificate", c.CrtPath) + if c.CrtObject != "" { + ui.PrintSelected("Intermediate Certificate Object", c.CrtObject) + } + } else { + ui.PrintSelected("Intermediate Certificate Request", c.CrtPath) + } if c.SSHHostKeyObject != "" { resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ From 8d229b9a60a8e58c93e2479a7c9547ebeaf7d16f Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 17 Nov 2021 21:41:15 -0800 Subject: [PATCH 34/34] update commented template names to match reality --- templates/values.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/values.go b/templates/values.go index c3362527..a760001e 100644 --- a/templates/values.go +++ b/templates/values.go @@ -75,7 +75,7 @@ var DefaultSSHTemplates = SSHTemplates{ // DefaultSSHTemplateData contains the data of the default templates used on ssh. var DefaultSSHTemplateData = map[string]string{ - // base_config.tpl adds the step ssh config file. + // config.tpl adds the step ssh config file. // // Note: on windows `Include C:\...` is treated as a relative path. "config.tpl": `Host * @@ -93,12 +93,12 @@ var DefaultSSHTemplateData = map[string]string{ {{- end }} {{- end }}`, - // includes.tpl adds the step ssh config file. + // step_includes.tpl adds the step ssh config file. // // Note: on windows `Include C:\...` is treated as a relative path. "step_includes.tpl": `{{- if or .User.GOOS "none" | eq "windows" }}Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config"{{- else }}Include "{{.User.StepPath}}/ssh/config"{{- end }}`, - // config.tpl is the step ssh config file, it includes the Match rule and + // step_config.tpl is the step ssh config file, it includes the Match rule and // references the step known_hosts file. // // Note: on windows ProxyCommand requires the full path