Merge branch 'master' into hs/acme-eab

This commit is contained in:
Herman Slatman 2021-08-27 12:50:19 +02:00
commit a98fe03e80
No known key found for this signature in database
GPG key ID: F4D8A44EA0A75A4F
50 changed files with 2790 additions and 739 deletions

View file

@ -18,7 +18,14 @@ You can use it to:
Whatever your use case, `step-ca` is easy to use and hard to misuse, thanks to [safe, sane defaults](https://smallstep.com/docs/step-ca/certificate-authority-server-production#sane-cryptographic-defaults). Whatever your use case, `step-ca` is easy to use and hard to misuse, thanks to [safe, sane defaults](https://smallstep.com/docs/step-ca/certificate-authority-server-production#sane-cryptographic-defaults).
**Questions? Find us in [Discussions](https://github.com/smallstep/certificates/discussions).** ---
**Don't want to run your own CA?**
To get up and running quickly, or as an alternative to running your own `step-ca` server, consider creating a [free hosted smallstep Certificate Manager authority](https://info.smallstep.com/certificate-manager-early-access-mvp/).
---
**Questions? Find us in [Discussions](https://github.com/smallstep/certificates/discussions) or [Join our Discord](https://bit.ly/step-discord).**
[Website](https://smallstep.com/certificates) | [Website](https://smallstep.com/certificates) |
[Documentation](https://smallstep.com/docs) | [Documentation](https://smallstep.com/docs) |
@ -27,7 +34,6 @@ Whatever your use case, `step-ca` is easy to use and hard to misuse, thanks to [
[Contributor's Guide](./docs/CONTRIBUTING.md) [Contributor's Guide](./docs/CONTRIBUTING.md)
[![GitHub release](https://img.shields.io/github/release/smallstep/certificates.svg)](https://github.com/smallstep/certificates/releases/latest) [![GitHub release](https://img.shields.io/github/release/smallstep/certificates.svg)](https://github.com/smallstep/certificates/releases/latest)
[![CA Image](https://images.microbadger.com/badges/image/smallstep/step-ca.svg)](https://microbadger.com/images/smallstep/step-ca)
[![Go Report Card](https://goreportcard.com/badge/github.com/smallstep/certificates)](https://goreportcard.com/report/github.com/smallstep/certificates) [![Go Report Card](https://goreportcard.com/badge/github.com/smallstep/certificates)](https://goreportcard.com/report/github.com/smallstep/certificates)
[![Build Status](https://travis-ci.com/smallstep/certificates.svg?branch=master)](https://travis-ci.com/smallstep/certificates) [![Build Status](https://travis-ci.com/smallstep/certificates.svg?branch=master)](https://travis-ci.com/smallstep/certificates)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
@ -58,10 +64,10 @@ You can issue certificates in exchange for:
- ID tokens from Okta, GSuite, Azure AD, Auth0. - ID tokens from Okta, GSuite, Azure AD, Auth0.
- ID tokens from an OAuth OIDC service that you host, like [Keycloak](https://www.keycloak.org/) or [Dex](https://github.com/dexidp/dex) - ID tokens from an OAuth OIDC service that you host, like [Keycloak](https://www.keycloak.org/) or [Dex](https://github.com/dexidp/dex)
- [Cloud instance identity documents](https://smallstep.com/blog/embarrassingly-easy-certificates-on-aws-azure-gcp/), for VMs on AWS, GCP, and Azure - [Cloud instance identity documents](https://smallstep.com/blog/embarrassingly-easy-certificates-on-aws-azure-gcp/), for VMs on AWS, GCP, and Azure
- [Single-use, short-lived JWK tokens]() issued by your CD tool — Puppet, Chef, Ansible, Terraform, etc. - [Single-use, short-lived JWK tokens](https://smallstep.com/docs/step-ca/provisioners#jwk) issued by your CD tool — Puppet, Chef, Ansible, Terraform, etc.
- A trusted X.509 certificate (X5C provisioner) - A trusted X.509 certificate (X5C provisioner)
- Expiring SSH host certificates needing rotation (the SSHPOP provisioner) - Expiring SSH host certificates needing rotation (the SSHPOP provisioner)
- Learn more in our [provisioner documentation](https://smallstep.com/docs/step-ca/configuration#jwk) - Learn more in our [provisioner documentation](https://smallstep.com/docs/step-ca/provisioners)
### 🏔 Your own private ACME server ### 🏔 Your own private ACME server

View file

@ -64,8 +64,14 @@ type HandlerOptions struct {
// NewHandler returns a new ACME API handler. // NewHandler returns a new ACME API handler.
func NewHandler(ops HandlerOptions) api.RouterHandler { func NewHandler(ops HandlerOptions) api.RouterHandler {
transport := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
client := http.Client{ client := http.Client{
Timeout: 30 * time.Second, Timeout: 30 * time.Second,
Transport: transport,
} }
dialer := &net.Dialer{ dialer := &net.Dialer{
Timeout: 30 * time.Second, Timeout: 30 * time.Second,

View file

@ -10,11 +10,13 @@ import (
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"reflect"
"strings" "strings"
"time" "time"
@ -114,6 +116,17 @@ func http01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWeb
return nil return nil
} }
func tlsAlert(err error) uint8 {
var opErr *net.OpError
if errors.As(err, &opErr) {
v := reflect.ValueOf(opErr.Err)
if v.Kind() == reflect.Uint8 {
return uint8(v.Uint())
}
}
return 0
}
func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo *ValidateChallengeOptions) error { func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo *ValidateChallengeOptions) error {
config := &tls.Config{ config := &tls.Config{
NextProtos: []string{"acme-tls/1"}, NextProtos: []string{"acme-tls/1"},
@ -129,6 +142,14 @@ func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSON
conn, err := vo.TLSDial("tcp", hostPort, config) conn, err := vo.TLSDial("tcp", hostPort, config)
if err != nil { if err != nil {
// With Go 1.17+ tls.Dial fails if there's no overlap between configured
// client and server protocols. When this happens the connection is
// closed with the error no_application_protocol(120) as required by
// RFC7301. See https://golang.org/doc/go1.17#ALPN
if tlsAlert(err) == 120 {
return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType,
"cannot negotiate ALPN acme-tls/1 protocol for tls-alpn-01 challenge"))
}
return storeError(ctx, db, ch, false, WrapError(ErrorConnectionType, err, return storeError(ctx, db, ch, false, WrapError(ErrorConnectionType, err,
"error doing TLS dial for %s", hostPort)) "error doing TLS dial for %s", hostPort))
} }

View file

@ -1395,7 +1395,7 @@ func TestTLSALPN01Validate(t *testing.T) {
assert.Equals(t, updch.Type, ch.Type) assert.Equals(t, updch.Type, ch.Type)
assert.Equals(t, updch.Value, ch.Value) assert.Equals(t, updch.Value, ch.Value)
err := NewError(ErrorConnectionType, "error doing TLS dial for %v:443: tls: DialWithDialer timed out", ch.Value) err := NewError(ErrorConnectionType, "error doing TLS dial for %v:443:", ch.Value)
assert.HasPrefix(t, updch.Error.Err.Error(), err.Err.Error()) assert.HasPrefix(t, updch.Error.Err.Error(), err.Err.Error())
assert.Equals(t, updch.Error.Type, err.Type) assert.Equals(t, updch.Error.Type, err.Type)

View file

@ -124,10 +124,8 @@ func (db *DB) updateAddOrderIDs(ctx context.Context, accID string, addOids ...st
ordersByAccountMux.Lock() ordersByAccountMux.Lock()
defer ordersByAccountMux.Unlock() defer ordersByAccountMux.Unlock()
var oldOids []string
b, err := db.db.Get(ordersByAccountIDTable, []byte(accID)) b, err := db.db.Get(ordersByAccountIDTable, []byte(accID))
var (
oldOids []string
)
if err != nil { if err != nil {
if !nosql.IsErrNotFound(err) { if !nosql.IsErrNotFound(err) {
return nil, errors.Wrapf(err, "error loading orderIDs for account %s", accID) return nil, errors.Wrapf(err, "error loading orderIDs for account %s", accID)

View file

@ -12,6 +12,7 @@ import (
"github.com/smallstep/certificates/acme" "github.com/smallstep/certificates/acme"
"github.com/smallstep/certificates/db" "github.com/smallstep/certificates/db"
"github.com/smallstep/nosql" "github.com/smallstep/nosql"
"github.com/smallstep/nosql/database"
nosqldb "github.com/smallstep/nosql/database" nosqldb "github.com/smallstep/nosql/database"
) )
@ -710,6 +711,34 @@ func TestDB_updateAddOrderIDs(t *testing.T) {
err: errors.Errorf("error saving orderIDs index for account %s", accID), err: errors.Errorf("error saving orderIDs index for account %s", accID),
} }
}, },
"ok/no-old": func(t *testing.T) test {
return test{
db: &db.MockNoSQLDB{
MGet: func(bucket, key []byte) ([]byte, error) {
switch string(bucket) {
case string(ordersByAccountIDTable):
return nil, database.ErrNotFound
default:
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
return nil, errors.New("force")
}
},
MCmpAndSwap: func(bucket, key, old, nu []byte) ([]byte, bool, error) {
switch string(bucket) {
case string(ordersByAccountIDTable):
assert.Equals(t, key, []byte(accID))
assert.Equals(t, old, nil)
assert.Equals(t, nu, nil)
return nil, true, nil
default:
assert.FatalError(t, errors.Errorf("unexpected bucket %s", string(bucket)))
return nil, false, errors.New("force")
}
},
},
res: []string{},
}
},
"ok/all-old-not-pending": func(t *testing.T) test { "ok/all-old-not-pending": func(t *testing.T) test {
oldOids := []string{"foo", "bar"} oldOids := []string{"foo", "bar"}
bOldOids, err := json.Marshal(oldOids) bOldOids, err := json.Marshal(oldOids)

View file

@ -2,6 +2,7 @@ package api
import ( import (
"net/http" "net/http"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/authority/provisioner"
@ -72,7 +73,11 @@ func (h *caHandler) SSHRekey(w http.ResponseWriter, r *http.Request) {
return return
} }
identity, err := h.renewIdentityCertificate(r) // Match identity cert with the SSH cert
notBefore := time.Unix(int64(oldCert.ValidAfter), 0)
notAfter := time.Unix(int64(oldCert.ValidBefore), 0)
identity, err := h.renewIdentityCertificate(r, notBefore, notAfter)
if err != nil { if err != nil {
WriteError(w, errs.ForbiddenErr(err)) WriteError(w, errs.ForbiddenErr(err))
return return

View file

@ -1,7 +1,9 @@
package api package api
import ( import (
"crypto/x509"
"net/http" "net/http"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/authority/provisioner"
@ -62,7 +64,11 @@ func (h *caHandler) SSHRenew(w http.ResponseWriter, r *http.Request) {
return return
} }
identity, err := h.renewIdentityCertificate(r) // Match identity cert with the SSH cert
notBefore := time.Unix(int64(oldCert.ValidAfter), 0)
notAfter := time.Unix(int64(oldCert.ValidBefore), 0)
identity, err := h.renewIdentityCertificate(r, notBefore, notAfter)
if err != nil { if err != nil {
WriteError(w, errs.ForbiddenErr(err)) WriteError(w, errs.ForbiddenErr(err))
return return
@ -74,13 +80,28 @@ func (h *caHandler) SSHRenew(w http.ResponseWriter, r *http.Request) {
}, http.StatusCreated) }, http.StatusCreated)
} }
// renewIdentityCertificate request the client TLS certificate if present. // renewIdentityCertificate request the client TLS certificate if present. If notBefore and notAfter are passed the
func (h *caHandler) renewIdentityCertificate(r *http.Request) ([]Certificate, error) { func (h *caHandler) renewIdentityCertificate(r *http.Request, notBefore, notAfter time.Time) ([]Certificate, error) {
if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 { if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 {
return nil, nil return nil, nil
} }
certChain, err := h.Authority.Renew(r.TLS.PeerCertificates[0]) // Clone the certificate as we can modify it.
cert, err := x509.ParseCertificate(r.TLS.PeerCertificates[0].Raw)
if err != nil {
return nil, errors.Wrap(err, "error parsing client certificate")
}
// Enforce the cert to match another certificate, for example an ssh
// certificate.
if !notBefore.IsZero() {
cert.NotBefore = notBefore
}
if !notAfter.IsZero() {
cert.NotAfter = notAfter
}
certChain, err := h.Authority.Renew(cert)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -7,39 +7,40 @@ import (
"crypto/x509" "crypto/x509"
"encoding/hex" "encoding/hex"
"log" "log"
"strings"
"sync" "sync"
"time" "time"
"github.com/smallstep/certificates/cas"
"github.com/smallstep/certificates/scep"
"go.step.sm/linkedca"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/admin" "github.com/smallstep/certificates/authority/admin"
adminDBNosql "github.com/smallstep/certificates/authority/admin/db/nosql" adminDBNosql "github.com/smallstep/certificates/authority/admin/db/nosql"
"github.com/smallstep/certificates/authority/administrator" "github.com/smallstep/certificates/authority/administrator"
"github.com/smallstep/certificates/authority/config" "github.com/smallstep/certificates/authority/config"
"github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/cas"
casapi "github.com/smallstep/certificates/cas/apiv1" casapi "github.com/smallstep/certificates/cas/apiv1"
"github.com/smallstep/certificates/db" "github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/kms" "github.com/smallstep/certificates/kms"
kmsapi "github.com/smallstep/certificates/kms/apiv1" kmsapi "github.com/smallstep/certificates/kms/apiv1"
"github.com/smallstep/certificates/kms/sshagentkms" "github.com/smallstep/certificates/kms/sshagentkms"
"github.com/smallstep/certificates/scep"
"github.com/smallstep/certificates/templates" "github.com/smallstep/certificates/templates"
"github.com/smallstep/nosql" "github.com/smallstep/nosql"
"go.step.sm/crypto/pemutil" "go.step.sm/crypto/pemutil"
"go.step.sm/linkedca"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
// Authority implements the Certificate Authority internal interface. // Authority implements the Certificate Authority internal interface.
type Authority struct { type Authority struct {
config *config.Config config *config.Config
keyManager kms.KeyManager keyManager kms.KeyManager
provisioners *provisioner.Collection provisioners *provisioner.Collection
admins *administrator.Collection admins *administrator.Collection
db db.AuthDB db db.AuthDB
adminDB admin.DB adminDB admin.DB
templates *templates.Templates templates *templates.Templates
linkedCAToken string
// X509 CA // X509 CA
x509CAService cas.CertificateAuthorityService x509CAService cas.CertificateAuthorityService
@ -205,6 +206,11 @@ func (a *Authority) init() error {
var err error var err error
// Automatically enable admin for all linked cas.
if a.linkedCAToken != "" {
a.config.AuthorityConfig.EnableAdmin = true
}
// Initialize step-ca Database if it's not already initialized with WithDB. // Initialize step-ca Database if it's not already initialized with WithDB.
// If a.config.DB is nil then a simple, barebones in memory DB will be used. // If a.config.DB is nil then a simple, barebones in memory DB will be used.
if a.db == nil { if a.db == nil {
@ -442,10 +448,24 @@ func (a *Authority) init() error {
// Initialize step-ca Admin Database if it's not already initialized using // Initialize step-ca Admin Database if it's not already initialized using
// WithAdminDB. // WithAdminDB.
if a.adminDB == nil { if a.adminDB == nil {
// Check if AuthConfig already exists if a.linkedCAToken == "" {
a.adminDB, err = adminDBNosql.New(a.db.(nosql.DB), admin.DefaultAuthorityID) // Check if AuthConfig already exists
if err != nil { a.adminDB, err = adminDBNosql.New(a.db.(nosql.DB), admin.DefaultAuthorityID)
return err if err != nil {
return err
}
} else {
// Use the linkedca client as the admindb.
client, err := newLinkedCAClient(a.linkedCAToken)
if err != nil {
return err
}
// If authorityId is configured make sure it matches the one in the token
if id := a.config.AuthorityConfig.AuthorityID; id != "" && !strings.EqualFold(id, client.authorityID) {
return errors.New("error initializing linkedca: token authority and configured authority do not match")
}
client.Run()
a.adminDB = client
} }
} }
@ -453,7 +473,7 @@ func (a *Authority) init() error {
if err != nil { if err != nil {
return admin.WrapErrorISE(err, "error loading provisioners to initialize authority") return admin.WrapErrorISE(err, "error loading provisioners to initialize authority")
} }
if len(provs) == 0 { if len(provs) == 0 && !strings.EqualFold(a.config.AuthorityConfig.DeploymentType, "linked") {
// Create First Provisioner // Create First Provisioner
prov, err := CreateFirstProvisioner(context.Background(), a.adminDB, a.config.Password) prov, err := CreateFirstProvisioner(context.Background(), a.adminDB, a.config.Password)
if err != nil { if err != nil {
@ -527,6 +547,9 @@ func (a *Authority) CloseForReload() {
if err := a.keyManager.Close(); err != nil { if err := a.keyManager.Close(); err != nil {
log.Printf("error closing the key manager: %v", err) log.Printf("error closing the key manager: %v", err)
} }
if client, ok := a.adminDB.(*linkedCaClient); ok {
client.Stop()
}
} }
// requiresDecrypter returns whether the Authority // requiresDecrypter returns whether the Authority

View file

@ -6,6 +6,7 @@ import (
"crypto/x509" "crypto/x509"
"encoding/hex" "encoding/hex"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time" "time"
@ -173,6 +174,9 @@ func (a *Authority) AuthorizeAdminToken(r *http.Request, token string) (*linkedc
} }
// UseToken stores the token to protect against reuse. // UseToken stores the token to protect against reuse.
//
// This method currently ignores any error coming from the GetTokenID, but it
// should specifically ignore the error provisioner.ErrAllowTokenReuse.
func (a *Authority) UseToken(token string, prov provisioner.Interface) error { func (a *Authority) UseToken(token string, prov provisioner.Interface) error {
if reuseKey, err := prov.GetTokenID(token); err == nil { if reuseKey, err := prov.GetTokenID(token); err == nil {
if reuseKey == "" { if reuseKey == "" {
@ -270,10 +274,19 @@ func (a *Authority) authorizeRevoke(ctx context.Context, token string) error {
// //
// TODO(mariano): should we authorize by default? // TODO(mariano): should we authorize by default?
func (a *Authority) authorizeRenew(cert *x509.Certificate) error { func (a *Authority) authorizeRenew(cert *x509.Certificate) error {
var err error
var isRevoked bool
var opts = []interface{}{errs.WithKeyVal("serialNumber", cert.SerialNumber.String())} var opts = []interface{}{errs.WithKeyVal("serialNumber", cert.SerialNumber.String())}
// Check the passive revocation table. // Check the passive revocation table.
isRevoked, err := a.db.IsRevoked(cert.SerialNumber.String()) serial := cert.SerialNumber.String()
if lca, ok := a.adminDB.(interface {
IsRevoked(string) (bool, error)
}); ok {
isRevoked, err = lca.IsRevoked(serial)
} else {
isRevoked, err = a.db.IsRevoked(serial)
}
if err != nil { if err != nil {
return errs.Wrap(http.StatusInternalServerError, err, "authority.authorizeRenew", opts...) return errs.Wrap(http.StatusInternalServerError, err, "authority.authorizeRenew", opts...)
} }
@ -291,6 +304,28 @@ func (a *Authority) authorizeRenew(cert *x509.Certificate) error {
return nil return nil
} }
// authorizeSSHCertificate returns an error if the given certificate is revoked.
func (a *Authority) authorizeSSHCertificate(ctx context.Context, cert *ssh.Certificate) error {
var err error
var isRevoked bool
serial := strconv.FormatUint(cert.Serial, 10)
if lca, ok := a.adminDB.(interface {
IsSSHRevoked(string) (bool, error)
}); ok {
isRevoked, err = lca.IsSSHRevoked(serial)
} else {
isRevoked, err = a.db.IsSSHRevoked(serial)
}
if err != nil {
return errs.Wrap(http.StatusInternalServerError, err, "authority.authorizeSSHCertificate", errs.WithKeyVal("serialNumber", serial))
}
if isRevoked {
return errs.Unauthorized("authority.authorizeSSHCertificate: certificate has been revoked", errs.WithKeyVal("serialNumber", serial))
}
return nil
}
// authorizeSSHSign loads the provisioner from the token, checks that it has not // authorizeSSHSign loads the provisioner from the token, checks that it has not
// been used again and calls the provisioner AuthorizeSSHSign method. Returns a // been used again and calls the provisioner AuthorizeSSHSign method. Returns a
// list of methods to apply to the signing flow. // list of methods to apply to the signing flow.

View file

@ -75,6 +75,7 @@ type ASN1DN struct {
Locality string `json:"locality,omitempty"` Locality string `json:"locality,omitempty"`
Province string `json:"province,omitempty"` Province string `json:"province,omitempty"`
StreetAddress string `json:"streetAddress,omitempty"` StreetAddress string `json:"streetAddress,omitempty"`
SerialNumber string `json:"serialNumber,omitempty"`
CommonName string `json:"commonName,omitempty"` CommonName string `json:"commonName,omitempty"`
} }
@ -83,8 +84,9 @@ type ASN1DN struct {
// cas.Options. // cas.Options.
type AuthConfig struct { type AuthConfig struct {
*cas.Options *cas.Options
AuthorityID string `json:"authorityID,omitempty"` AuthorityID string `json:"authorityId,omitempty"`
Provisioners provisioner.List `json:"provisioners"` DeploymentType string `json:"deploymentType,omitempty"`
Provisioners provisioner.List `json:"provisioners,omitempty"`
Admins []*linkedca.Admin `json:"-"` Admins []*linkedca.Admin `json:"-"`
Template *ASN1DN `json:"template,omitempty"` Template *ASN1DN `json:"template,omitempty"`
Claims *provisioner.Claims `json:"claims,omitempty"` Claims *provisioner.Claims `json:"claims,omitempty"`
@ -188,9 +190,10 @@ func (c *Config) Validate() error {
switch { switch {
case c.Address == "": case c.Address == "":
return errors.New("address cannot be empty") return errors.New("address cannot be empty")
case len(c.DNSNames) == 0: case len(c.DNSNames) == 0:
return errors.New("dnsNames cannot be empty") return errors.New("dnsNames cannot be empty")
case c.AuthorityConfig == nil:
return errors.New("authority cannot be nil")
} }
// Options holds the RA/CAS configuration. // Options holds the RA/CAS configuration.
@ -222,7 +225,7 @@ func (c *Config) Validate() error {
c.TLS.MaxVersion = DefaultTLSOptions.MaxVersion c.TLS.MaxVersion = DefaultTLSOptions.MaxVersion
} }
if c.TLS.MinVersion == 0 { if c.TLS.MinVersion == 0 {
c.TLS.MinVersion = c.TLS.MaxVersion c.TLS.MinVersion = DefaultTLSOptions.MinVersion
} }
if c.TLS.MinVersion > c.TLS.MaxVersion { if c.TLS.MinVersion > c.TLS.MaxVersion {
return errors.New("tls minVersion cannot exceed tls maxVersion") return errors.New("tls minVersion cannot exceed tls maxVersion")

View file

@ -15,8 +15,9 @@ var (
// DefaultTLSRenegotiation default TLS connection renegotiation policy. // DefaultTLSRenegotiation default TLS connection renegotiation policy.
DefaultTLSRenegotiation = false // Never regnegotiate. DefaultTLSRenegotiation = false // Never regnegotiate.
// DefaultTLSCipherSuites specifies default step ciphersuite(s). // DefaultTLSCipherSuites specifies default step ciphersuite(s).
// These are TLS 1.0 - 1.2 cipher suites.
DefaultTLSCipherSuites = CipherSuites{ DefaultTLSCipherSuites = CipherSuites{
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
} }
// ApprovedTLSCipherSuites smallstep approved ciphersuites. // ApprovedTLSCipherSuites smallstep approved ciphersuites.
@ -26,25 +27,21 @@ var (
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
} }
// DefaultTLSOptions represents the default TLS version as well as the cipher // DefaultTLSOptions represents the default TLS version as well as the cipher
// suites used in the TLS certificates. // suites used in the TLS certificates.
DefaultTLSOptions = TLSOptions{ DefaultTLSOptions = TLSOptions{
CipherSuites: CipherSuites{ CipherSuites: DefaultTLSCipherSuites,
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", MinVersion: DefaultTLSMinVersion,
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", MaxVersion: DefaultTLSMaxVersion,
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", Renegotiation: DefaultTLSRenegotiation,
},
MinVersion: 1.2,
MaxVersion: 1.2,
Renegotiation: false,
} }
) )
@ -119,27 +116,38 @@ func (c CipherSuites) Value() []uint16 {
// cipherSuites has the list of supported cipher suites. // cipherSuites has the list of supported cipher suites.
var cipherSuites = map[string]uint16{ var cipherSuites = map[string]uint16{
"TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, // TLS 1.0 - 1.2 cipher suites.
"TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA,
"TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
"TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
"TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
"TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
"TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
// TLS 1.3 cipher sutes.
"TLS_AES_128_GCM_SHA256": tls.TLS_AES_128_GCM_SHA256,
"TLS_AES_256_GCM_SHA384": tls.TLS_AES_256_GCM_SHA384,
"TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256,
// Legacy names.
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
} }
// TLSOptions represents the TLS options that can be specified on *tls.Config // TLSOptions represents the TLS options that can be specified on *tls.Config

284
authority/export.go Normal file
View file

@ -0,0 +1,284 @@
package authority
import (
"encoding/json"
"io/ioutil"
"net/url"
"path/filepath"
"strings"
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/provisioner"
"go.step.sm/cli-utils/config"
"go.step.sm/linkedca"
"google.golang.org/protobuf/types/known/structpb"
)
// Export creates a linkedca configuration form the current ca.json and loaded
// authorities.
//
// Note that export will not export neither the pki password nor the certificate
// issuer password.
func (a *Authority) Export() (c *linkedca.Configuration, err error) {
// Recover from panics
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
files := make(map[string][]byte)
// The exported configuration should not include the password in it.
c = &linkedca.Configuration{
Version: "1.0",
Root: mustReadFilesOrURIs(a.config.Root, files),
FederatedRoots: mustReadFilesOrURIs(a.config.FederatedRoots, files),
Intermediate: mustReadFileOrURI(a.config.IntermediateCert, files),
IntermediateKey: mustReadFileOrURI(a.config.IntermediateKey, files),
Address: a.config.Address,
InsecureAddress: a.config.InsecureAddress,
DnsNames: a.config.DNSNames,
Db: mustMarshalToStruct(a.config.DB),
Logger: mustMarshalToStruct(a.config.Logger),
Monitoring: mustMarshalToStruct(a.config.Monitoring),
Authority: &linkedca.Authority{
Id: a.config.AuthorityConfig.AuthorityID,
EnableAdmin: a.config.AuthorityConfig.EnableAdmin,
DisableIssuedAtCheck: a.config.AuthorityConfig.DisableIssuedAtCheck,
Backdate: mustDuration(a.config.AuthorityConfig.Backdate),
DeploymentType: a.config.AuthorityConfig.DeploymentType,
},
Files: files,
}
// SSH
if v := a.config.SSH; v != nil {
c.Ssh = &linkedca.SSH{
HostKey: mustReadFileOrURI(v.HostKey, files),
UserKey: mustReadFileOrURI(v.UserKey, files),
AddUserPrincipal: v.AddUserPrincipal,
AddUserCommand: v.AddUserCommand,
}
for _, k := range v.Keys {
typ, ok := linkedca.SSHPublicKey_Type_value[strings.ToUpper(k.Type)]
if !ok {
return nil, errors.Errorf("unsupported ssh key type %s", k.Type)
}
c.Ssh.Keys = append(c.Ssh.Keys, &linkedca.SSHPublicKey{
Type: linkedca.SSHPublicKey_Type(typ),
Federated: k.Federated,
Key: mustMarshalToStruct(k),
})
}
if b := v.Bastion; b != nil {
c.Ssh.Bastion = &linkedca.Bastion{
Hostname: b.Hostname,
User: b.User,
Port: b.Port,
Command: b.Command,
Flags: b.Flags,
}
}
}
// KMS
if v := a.config.KMS; v != nil {
var typ int32
var ok bool
if v.Type == "" {
typ = int32(linkedca.KMS_SOFTKMS)
} else {
typ, ok = linkedca.KMS_Type_value[strings.ToUpper(v.Type)]
if !ok {
return nil, errors.Errorf("unsupported kms type %s", v.Type)
}
}
c.Kms = &linkedca.KMS{
Type: linkedca.KMS_Type(typ),
CredentialsFile: v.CredentialsFile,
Uri: v.URI,
Pin: v.Pin,
ManagementKey: v.ManagementKey,
Region: v.Region,
Profile: v.Profile,
}
}
// Authority
// cas options
if v := a.config.AuthorityConfig.Options; v != nil {
c.Authority.Type = 0
c.Authority.CertificateAuthority = v.CertificateAuthority
c.Authority.CertificateAuthorityFingerprint = v.CertificateAuthorityFingerprint
c.Authority.CredentialsFile = v.CredentialsFile
if iss := v.CertificateIssuer; iss != nil {
typ, ok := linkedca.CertificateIssuer_Type_value[strings.ToUpper(iss.Type)]
if !ok {
return nil, errors.Errorf("unknown certificate issuer type %s", iss.Type)
}
// The exported certificate issuer should not include the password.
c.Authority.CertificateIssuer = &linkedca.CertificateIssuer{
Type: linkedca.CertificateIssuer_Type(typ),
Provisioner: iss.Provisioner,
Certificate: mustReadFileOrURI(iss.Certificate, files),
Key: mustReadFileOrURI(iss.Key, files),
}
}
}
// admins
for {
list, cursor := a.admins.Find("", 100)
c.Authority.Admins = append(c.Authority.Admins, list...)
if cursor == "" {
break
}
}
// provisioners
for {
list, cursor := a.provisioners.Find("", 100)
for _, p := range list {
lp, err := ProvisionerToLinkedca(p)
if err != nil {
return nil, err
}
c.Authority.Provisioners = append(c.Authority.Provisioners, lp)
}
if cursor == "" {
break
}
}
// global claims
c.Authority.Claims = claimsToLinkedca(a.config.AuthorityConfig.Claims)
// Distinguished names template
if v := a.config.AuthorityConfig.Template; v != nil {
c.Authority.Template = &linkedca.DistinguishedName{
Country: v.Country,
Organization: v.Organization,
OrganizationalUnit: v.OrganizationalUnit,
Locality: v.Locality,
Province: v.Province,
StreetAddress: v.StreetAddress,
SerialNumber: v.SerialNumber,
CommonName: v.CommonName,
}
}
// TLS
if v := a.config.TLS; v != nil {
c.Tls = &linkedca.TLS{
MinVersion: v.MinVersion.String(),
MaxVersion: v.MaxVersion.String(),
Renegotiation: v.Renegotiation,
}
for _, cs := range v.CipherSuites.Value() {
c.Tls.CipherSuites = append(c.Tls.CipherSuites, linkedca.TLS_CiperSuite(cs))
}
}
// Templates
if v := a.config.Templates; v != nil {
c.Templates = &linkedca.ConfigTemplates{
Ssh: &linkedca.SSHConfigTemplate{},
Data: mustMarshalToStruct(v.Data),
}
// Remove automatically loaded vars
if c.Templates.Data != nil && c.Templates.Data.Fields != nil {
delete(c.Templates.Data.Fields, "Step")
}
for _, t := range v.SSH.Host {
typ, ok := linkedca.ConfigTemplate_Type_value[strings.ToUpper(string(t.Type))]
if !ok {
return nil, errors.Errorf("unsupported template type %s", t.Type)
}
c.Templates.Ssh.Hosts = append(c.Templates.Ssh.Hosts, &linkedca.ConfigTemplate{
Type: linkedca.ConfigTemplate_Type(typ),
Name: t.Name,
Template: mustReadFileOrURI(t.TemplatePath, files),
Path: t.Path,
Comment: t.Comment,
Requires: t.RequiredData,
Content: t.Content,
})
}
for _, t := range v.SSH.User {
typ, ok := linkedca.ConfigTemplate_Type_value[strings.ToUpper(string(t.Type))]
if !ok {
return nil, errors.Errorf("unsupported template type %s", t.Type)
}
c.Templates.Ssh.Users = append(c.Templates.Ssh.Users, &linkedca.ConfigTemplate{
Type: linkedca.ConfigTemplate_Type(typ),
Name: t.Name,
Template: mustReadFileOrURI(t.TemplatePath, files),
Path: t.Path,
Comment: t.Comment,
Requires: t.RequiredData,
Content: t.Content,
})
}
}
return c, nil
}
func mustDuration(d *provisioner.Duration) string {
if d == nil || d.Duration == 0 {
return ""
}
return d.String()
}
func mustMarshalToStruct(v interface{}) *structpb.Struct {
b, err := json.Marshal(v)
if err != nil {
panic(errors.Wrapf(err, "error marshaling %T", v))
}
var r *structpb.Struct
if err := json.Unmarshal(b, &r); err != nil {
panic(errors.Wrapf(err, "error unmarshaling %T", v))
}
return r
}
func mustReadFileOrURI(fn string, m map[string][]byte) string {
if fn == "" {
return ""
}
stepPath := filepath.ToSlash(config.StepPath())
if !strings.HasSuffix(stepPath, "/") {
stepPath += "/"
}
fn = strings.TrimPrefix(filepath.ToSlash(fn), stepPath)
ok, err := isFilename(fn)
if err != nil {
panic(err)
}
if ok {
b, err := ioutil.ReadFile(config.StepAbs(fn))
if err != nil {
panic(errors.Wrapf(err, "error reading %s", fn))
}
m[fn] = b
return fn
}
return fn
}
func mustReadFilesOrURIs(fns []string, m map[string][]byte) []string {
var result []string
for _, fn := range fns {
result = append(result, mustReadFileOrURI(fn, m))
}
return result
}
func isFilename(fn string) (bool, error) {
u, err := url.Parse(fn)
if err != nil {
return false, errors.Wrapf(err, "error parsing %s", fn)
}
return u.Scheme == "" || u.Scheme == "file", nil
}

490
authority/linkedca.go Normal file
View file

@ -0,0 +1,490 @@
package authority
import (
"context"
"crypto"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"fmt"
"net/url"
"regexp"
"strings"
"time"
"github.com/pkg/errors"
"github.com/smallstep/certificates/db"
"go.step.sm/crypto/jose"
"go.step.sm/crypto/keyutil"
"go.step.sm/crypto/tlsutil"
"go.step.sm/crypto/x509util"
"go.step.sm/linkedca"
"golang.org/x/crypto/ssh"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
const uuidPattern = "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"
type linkedCaClient struct {
renewer *tlsutil.Renewer
client linkedca.MajordomoClient
authorityID string
}
type linkedCAClaims struct {
jose.Claims
SANs []string `json:"sans"`
SHA string `json:"sha"`
}
func newLinkedCAClient(token string) (*linkedCaClient, error) {
tok, err := jose.ParseSigned(token)
if err != nil {
return nil, errors.Wrap(err, "error parsing token")
}
var claims linkedCAClaims
if err := tok.UnsafeClaimsWithoutVerification(&claims); err != nil {
return nil, errors.Wrap(err, "error parsing token")
}
// Validate claims
if len(claims.Audience) != 1 {
return nil, errors.New("error parsing token: invalid aud claim")
}
if claims.SHA == "" {
return nil, errors.New("error parsing token: invalid sha claim")
}
// Get linkedCA endpoint from audience.
u, err := url.Parse(claims.Audience[0])
if err != nil {
return nil, errors.New("error parsing token: invalid aud claim")
}
// Get authority from SANs
authority, err := getAuthority(claims.SANs)
if err != nil {
return nil, err
}
// Create csr to login with
signer, err := keyutil.GenerateDefaultSigner()
if err != nil {
return nil, err
}
csr, err := x509util.CreateCertificateRequest(claims.Subject, claims.SANs, signer)
if err != nil {
return nil, err
}
// Get and verify root certificate
root, err := getRootCertificate(u.Host, claims.SHA)
if err != nil {
return nil, err
}
pool := x509.NewCertPool()
pool.AddCert(root)
// Login with majordomo and get certificates
cert, tlsConfig, err := login(authority, token, csr, signer, u.Host, pool)
if err != nil {
return nil, err
}
// Start TLS renewer and set the GetClientCertificate callback to it.
renewer, err := tlsutil.NewRenewer(cert, tlsConfig, func() (*tls.Certificate, *tls.Config, error) {
return login(authority, token, csr, signer, u.Host, pool)
})
if err != nil {
return nil, err
}
tlsConfig.GetClientCertificate = renewer.GetClientCertificate
// Start mTLS client
conn, err := grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))
if err != nil {
return nil, errors.Wrapf(err, "error connecting %s", u.Host)
}
return &linkedCaClient{
renewer: renewer,
client: linkedca.NewMajordomoClient(conn),
authorityID: authority,
}, nil
}
func (c *linkedCaClient) Run() {
c.renewer.Run()
}
func (c *linkedCaClient) Stop() {
c.renewer.Stop()
}
func (c *linkedCaClient) CreateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
resp, err := c.client.CreateProvisioner(ctx, &linkedca.CreateProvisionerRequest{
Type: prov.Type,
Name: prov.Name,
Details: prov.Details,
Claims: prov.Claims,
X509Template: prov.X509Template,
SshTemplate: prov.SshTemplate,
})
if err != nil {
return errors.Wrap(err, "error creating provisioner")
}
prov.Id = resp.Id
prov.AuthorityId = resp.AuthorityId
return nil
}
func (c *linkedCaClient) GetProvisioner(ctx context.Context, id string) (*linkedca.Provisioner, error) {
resp, err := c.client.GetProvisioner(ctx, &linkedca.GetProvisionerRequest{
Id: id,
})
if err != nil {
return nil, errors.Wrap(err, "error getting provisioners")
}
return resp, nil
}
func (c *linkedCaClient) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error) {
resp, err := c.client.GetConfiguration(ctx, &linkedca.ConfigurationRequest{
AuthorityId: c.authorityID,
})
if err != nil {
return nil, errors.Wrap(err, "error getting provisioners")
}
return resp.Provisioners, nil
}
func (c *linkedCaClient) UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
_, err := c.client.UpdateProvisioner(ctx, &linkedca.UpdateProvisionerRequest{
Id: prov.Id,
Name: prov.Name,
Details: prov.Details,
Claims: prov.Claims,
X509Template: prov.X509Template,
SshTemplate: prov.SshTemplate,
})
return errors.Wrap(err, "error updating provisioner")
}
func (c *linkedCaClient) DeleteProvisioner(ctx context.Context, id string) error {
_, err := c.client.DeleteProvisioner(ctx, &linkedca.DeleteProvisionerRequest{
Id: id,
})
return errors.Wrap(err, "error deleting provisioner")
}
func (c *linkedCaClient) CreateAdmin(ctx context.Context, adm *linkedca.Admin) error {
resp, err := c.client.CreateAdmin(ctx, &linkedca.CreateAdminRequest{
Subject: adm.Subject,
ProvisionerId: adm.ProvisionerId,
Type: adm.Type,
})
if err != nil {
return errors.Wrap(err, "error creating admin")
}
adm.Id = resp.Id
adm.AuthorityId = resp.AuthorityId
return nil
}
func (c *linkedCaClient) GetAdmin(ctx context.Context, id string) (*linkedca.Admin, error) {
resp, err := c.client.GetAdmin(ctx, &linkedca.GetAdminRequest{
Id: id,
})
if err != nil {
return nil, errors.Wrap(err, "error getting admins")
}
return resp, nil
}
func (c *linkedCaClient) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) {
resp, err := c.client.GetConfiguration(ctx, &linkedca.ConfigurationRequest{
AuthorityId: c.authorityID,
})
if err != nil {
return nil, errors.Wrap(err, "error getting admins")
}
return resp.Admins, nil
}
func (c *linkedCaClient) UpdateAdmin(ctx context.Context, adm *linkedca.Admin) error {
_, err := c.client.UpdateAdmin(ctx, &linkedca.UpdateAdminRequest{
Id: adm.Id,
Type: adm.Type,
})
return errors.Wrap(err, "error updating admin")
}
func (c *linkedCaClient) DeleteAdmin(ctx context.Context, id string) error {
_, err := c.client.DeleteAdmin(ctx, &linkedca.DeleteAdminRequest{
Id: id,
})
return errors.Wrap(err, "error deleting admin")
}
func (c *linkedCaClient) StoreCertificateChain(fullchain ...*x509.Certificate) error {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
_, err := c.client.PostCertificate(ctx, &linkedca.CertificateRequest{
PemCertificate: serializeCertificateChain(fullchain[0]),
PemCertificateChain: serializeCertificateChain(fullchain[1:]...),
})
return errors.Wrap(err, "error posting certificate")
}
func (c *linkedCaClient) StoreRenewedCertificate(parent *x509.Certificate, fullchain ...*x509.Certificate) error {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
_, err := c.client.PostCertificate(ctx, &linkedca.CertificateRequest{
PemCertificate: serializeCertificateChain(fullchain[0]),
PemCertificateChain: serializeCertificateChain(fullchain[1:]...),
PemParentCertificate: serializeCertificateChain(parent),
})
return errors.Wrap(err, "error posting certificate")
}
func (c *linkedCaClient) StoreSSHCertificate(crt *ssh.Certificate) error {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
_, err := c.client.PostSSHCertificate(ctx, &linkedca.SSHCertificateRequest{
Certificate: string(ssh.MarshalAuthorizedKey(crt)),
})
return errors.Wrap(err, "error posting ssh certificate")
}
func (c *linkedCaClient) Revoke(crt *x509.Certificate, rci *db.RevokedCertificateInfo) error {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
_, err := c.client.RevokeCertificate(ctx, &linkedca.RevokeCertificateRequest{
Serial: rci.Serial,
PemCertificate: serializeCertificate(crt),
Reason: rci.Reason,
ReasonCode: linkedca.RevocationReasonCode(rci.ReasonCode),
Passive: true,
})
return errors.Wrap(err, "error revoking certificate")
}
func (c *linkedCaClient) RevokeSSH(ssh *ssh.Certificate, rci *db.RevokedCertificateInfo) error {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
_, err := c.client.RevokeSSHCertificate(ctx, &linkedca.RevokeSSHCertificateRequest{
Serial: rci.Serial,
Certificate: serializeSSHCertificate(ssh),
Reason: rci.Reason,
ReasonCode: linkedca.RevocationReasonCode(rci.ReasonCode),
Passive: true,
})
return errors.Wrap(err, "error revoking ssh certificate")
}
func (c *linkedCaClient) IsRevoked(serial string) (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
resp, err := c.client.GetCertificateStatus(ctx, &linkedca.GetCertificateStatusRequest{
Serial: serial,
})
if err != nil {
return false, errors.Wrap(err, "error getting certificate status")
}
return resp.Status != linkedca.RevocationStatus_ACTIVE, nil
}
func (c *linkedCaClient) IsSSHRevoked(serial string) (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
resp, err := c.client.GetSSHCertificateStatus(ctx, &linkedca.GetSSHCertificateStatusRequest{
Serial: serial,
})
if err != nil {
return false, errors.Wrap(err, "error getting certificate status")
}
return resp.Status != linkedca.RevocationStatus_ACTIVE, nil
}
func serializeCertificate(crt *x509.Certificate) string {
if crt == nil {
return ""
}
return string(pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: crt.Raw,
}))
}
func serializeCertificateChain(fullchain ...*x509.Certificate) string {
var chain string
for _, crt := range fullchain {
chain += string(pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: crt.Raw,
}))
}
return chain
}
func serializeSSHCertificate(crt *ssh.Certificate) string {
if crt == nil {
return ""
}
return string(ssh.MarshalAuthorizedKey(crt))
}
func getAuthority(sans []string) (string, error) {
for _, s := range sans {
if strings.HasPrefix(s, "urn:smallstep:authority:") {
if regexp.MustCompile(uuidPattern).MatchString(s[24:]) {
return s[24:], nil
}
}
}
return "", fmt.Errorf("error parsing token: invalid sans claim")
}
// getRootCertificate creates an insecure majordomo client and returns the
// verified root certificate.
func getRootCertificate(endpoint, fingerprint string) (*x509.Certificate, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
conn, err := grpc.DialContext(ctx, endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
InsecureSkipVerify: true,
})))
if err != nil {
return nil, errors.Wrapf(err, "error connecting %s", endpoint)
}
ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
client := linkedca.NewMajordomoClient(conn)
resp, err := client.GetRootCertificate(ctx, &linkedca.GetRootCertificateRequest{
Fingerprint: fingerprint,
})
if err != nil {
return nil, fmt.Errorf("error getting root certificate: %w", err)
}
var block *pem.Block
b := []byte(resp.PemCertificate)
for len(b) > 0 {
block, b = pem.Decode(b)
if block == nil {
break
}
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
continue
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, fmt.Errorf("error parsing certificate: %w", err)
}
// verify the sha256
sum := sha256.Sum256(cert.Raw)
if !strings.EqualFold(fingerprint, hex.EncodeToString(sum[:])) {
return nil, fmt.Errorf("error verifying certificate: SHA256 fingerprint does not match")
}
return cert, nil
}
return nil, fmt.Errorf("error getting root certificate: certificate not found")
}
// login creates a new majordomo client with just the root ca pool and returns
// the signed certificate and tls configuration.
func login(authority, token string, csr *x509.CertificateRequest, signer crypto.PrivateKey, endpoint string, rootCAs *x509.CertPool) (*tls.Certificate, *tls.Config, error) {
// Connect to majordomo
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
conn, err := grpc.DialContext(ctx, endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
RootCAs: rootCAs,
})))
if err != nil {
return nil, nil, errors.Wrapf(err, "error connecting %s", endpoint)
}
// Login to get the signed certificate
ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
client := linkedca.NewMajordomoClient(conn)
resp, err := client.Login(ctx, &linkedca.LoginRequest{
AuthorityId: authority,
Token: token,
PemCertificateRequest: string(pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: csr.Raw,
})),
})
if err != nil {
return nil, nil, errors.Wrapf(err, "error logging in %s", endpoint)
}
// Parse login response
var block *pem.Block
var bundle []*x509.Certificate
rest := []byte(resp.PemCertificateChain)
for {
block, rest = pem.Decode(rest)
if block == nil {
break
}
if block.Type != "CERTIFICATE" {
return nil, nil, errors.New("error decoding login response: pemCertificateChain is not a certificate bundle")
}
crt, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, nil, errors.Wrap(err, "error parsing login response")
}
bundle = append(bundle, crt)
}
if len(bundle) == 0 {
return nil, nil, errors.New("error decoding login response: pemCertificateChain should not be empty")
}
// Build tls.Certificate with PemCertificate and intermediates in the
// PemCertificateChain
cert := &tls.Certificate{
PrivateKey: signer,
}
rest = []byte(resp.PemCertificate)
for {
block, rest = pem.Decode(rest)
if block == nil {
break
}
if block.Type == "CERTIFICATE" {
leaf, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, nil, errors.Wrap(err, "error parsing pemCertificate")
}
cert.Certificate = append(cert.Certificate, block.Bytes)
cert.Leaf = leaf
}
}
// Add intermediates to the tls.Certificate
last := len(bundle) - 1
for i := 0; i < last; i++ {
cert.Certificate = append(cert.Certificate, bundle[i].Raw)
}
// Add root to the pool if it's not there yet
rootCAs.AddCert(bundle[last])
return cert, &tls.Config{
RootCAs: rootCAs,
}, nil
}

View file

@ -196,6 +196,15 @@ func WithAdminDB(db admin.DB) Option {
} }
} }
// WithLinkedCAToken is an option to set the authentication token used to enable
// linked ca.
func WithLinkedCAToken(token string) Option {
return func(a *Authority) error {
a.linkedCAToken = token
return nil
}
}
func readCertificateBundle(pemCerts []byte) ([]*x509.Certificate, error) { func readCertificateBundle(pemCerts []byte) ([]*x509.Certificate, error) {
var block *pem.Block var block *pem.Block
var certs []*x509.Certificate var certs []*x509.Certificate

View file

@ -515,6 +515,11 @@ func (p *AWS) readURL(url string) ([]byte, error) {
var resp *http.Response var resp *http.Response
var err error var err error
// Initialize IMDS versions when this is called from the cli.
if len(p.IMDSVersions) == 0 {
p.IMDSVersions = []string{"v2", "v1"}
}
for _, v := range p.IMDSVersions { for _, v := range p.IMDSVersions {
switch v { switch v {
case "v1": case "v1":

View file

@ -141,6 +141,12 @@ func TestAWS_GetIdentityToken(t *testing.T) {
p7.config.signatureURL = p1.config.signatureURL p7.config.signatureURL = p1.config.signatureURL
p7.config.tokenURL = p1.config.tokenURL p7.config.tokenURL = p1.config.tokenURL
p8, err := generateAWS()
assert.FatalError(t, err)
p8.IMDSVersions = nil
p8.Accounts = p1.Accounts
p8.config = p1.config
caURL := "https://ca.smallstep.com" caURL := "https://ca.smallstep.com"
u, err := url.Parse(caURL) u, err := url.Parse(caURL)
assert.FatalError(t, err) assert.FatalError(t, err)
@ -156,6 +162,7 @@ func TestAWS_GetIdentityToken(t *testing.T) {
wantErr bool wantErr bool
}{ }{
{"ok", p1, args{"foo.local", caURL}, false}, {"ok", p1, args{"foo.local", caURL}, false},
{"ok no imds", p8, args{"foo.local", caURL}, false},
{"fail ca url", p1, args{"foo.local", "://ca.smallstep.com"}, true}, {"fail ca url", p1, args{"foo.local", "://ca.smallstep.com"}, true},
{"fail identityURL", p2, args{"foo.local", caURL}, true}, {"fail identityURL", p2, args{"foo.local", caURL}, true},
{"fail signatureURL", p3, args{"foo.local", caURL}, true}, {"fail signatureURL", p3, args{"foo.local", caURL}, true},

View file

@ -131,9 +131,10 @@ func (p *Azure) GetTokenID(token string) (string, error) {
return "", errors.Wrap(err, "error verifying claims") return "", errors.Wrap(err, "error verifying claims")
} }
// If TOFU is disabled create return the token kid // If TOFU is disabled then allow token re-use. Azure caches the token for
// 24h and without allowing the re-use we cannot use it twice.
if p.DisableTrustOnFirstUse { if p.DisableTrustOnFirstUse {
return claims.ID, nil return "", ErrAllowTokenReuse
} }
sum := sha256.Sum256([]byte(claims.XMSMirID)) sum := sha256.Sum256([]byte(claims.XMSMirID))

View file

@ -72,7 +72,7 @@ func TestAzure_GetTokenID(t *testing.T) {
wantErr bool wantErr bool
}{ }{
{"ok", p1, args{t1}, w1, false}, {"ok", p1, args{t1}, w1, false},
{"ok no TOFU", p2, args{t2}, "the-jti", false}, {"ok no TOFU", p2, args{t2}, "", true},
{"fail token", p1, args{"bad-token"}, "", true}, {"fail token", p1, args{"bad-token"}, "", true},
{"fail claims", p1, args{"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ey.fooo"}, "", true}, {"fail claims", p1, args{"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ey.fooo"}, "", true},
} }

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"crypto/x509" "crypto/x509"
"encoding/json" "encoding/json"
stderrors "errors"
"net/url" "net/url"
"regexp" "regexp"
"strings" "strings"
@ -32,6 +33,17 @@ type Interface interface {
AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certificate, []SignOption, error) AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certificate, []SignOption, error)
} }
// ErrAllowTokenReuse is an error that is returned by provisioners that allows
// the reuse of tokens.
//
// This is, for example, returned by the Azure provisioner when
// DisableTrustOnFirstUse is set to true. Azure caches tokens for up to 24hr and
// has no mechanism for getting a different token - this can be an issue when
// rebooting a VM. In contrast, AWS and GCP have facilities for requesting a new
// token. Therefore, for the Azure provisioner we are enabling token reuse, with
// the understanding that we are not following security best practices
var ErrAllowTokenReuse = stderrors.New("allow token reuse")
// Audiences stores all supported audiences by request type. // Audiences stores all supported audiences by request type.
type Audiences struct { type Audiences struct {
Sign []string Sign []string

View file

@ -8,7 +8,6 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/errs"
"go.step.sm/crypto/jose" "go.step.sm/crypto/jose"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@ -30,7 +29,6 @@ type SSHPOP struct {
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
db db.AuthDB
claimer *Claimer claimer *Claimer
audiences Audiences audiences Audiences
sshPubKeys *SSHKeys sshPubKeys *SSHKeys
@ -102,7 +100,6 @@ func (p *SSHPOP) Init(config Config) error {
} }
p.audiences = config.Audiences.WithFragment(p.GetIDForToken()) p.audiences = config.Audiences.WithFragment(p.GetIDForToken())
p.db = config.DB
p.sshPubKeys = config.SSHKeys p.sshPubKeys = config.SSHKeys
return nil return nil
} }
@ -110,6 +107,8 @@ func (p *SSHPOP) Init(config Config) error {
// authorizeToken performs common jwt authorization actions and returns the // authorizeToken performs common jwt authorization actions and returns the
// claims for case specific downstream parsing. // claims for case specific downstream parsing.
// e.g. a Sign request will auth/validate different fields than a Revoke request. // e.g. a Sign request will auth/validate different fields than a Revoke request.
//
// Checking for certificate revocation has been moved to the authority package.
func (p *SSHPOP) authorizeToken(token string, audiences []string) (*sshPOPPayload, error) { func (p *SSHPOP) authorizeToken(token string, audiences []string) (*sshPOPPayload, error) {
sshCert, jwt, err := ExtractSSHPOPCert(token) sshCert, jwt, err := ExtractSSHPOPCert(token)
if err != nil { if err != nil {
@ -117,14 +116,6 @@ func (p *SSHPOP) authorizeToken(token string, audiences []string) (*sshPOPPayloa
"sshpop.authorizeToken; error extracting sshpop header from token") "sshpop.authorizeToken; error extracting sshpop header from token")
} }
// Check for revocation.
if isRevoked, err := p.db.IsSSHRevoked(strconv.FormatUint(sshCert.Serial, 10)); err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err,
"sshpop.authorizeToken; error checking checking sshpop cert revocation")
} else if isRevoked {
return nil, errs.Unauthorized("sshpop.authorizeToken; sshpop certificate is revoked")
}
// Check validity period of the certificate. // Check validity period of the certificate.
n := time.Now() n := time.Now()
if sshCert.ValidAfter != 0 && time.Unix(int64(sshCert.ValidAfter), 0).After(n) { if sshCert.ValidAfter != 0 && time.Unix(int64(sshCert.ValidAfter), 0).After(n) {

View file

@ -11,7 +11,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/assert" "github.com/smallstep/assert"
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/errs"
"go.step.sm/crypto/jose" "go.step.sm/crypto/jose"
"go.step.sm/crypto/pemutil" "go.step.sm/crypto/pemutil"
@ -83,52 +82,9 @@ func TestSSHPOP_authorizeToken(t *testing.T) {
err: errors.New("sshpop.authorizeToken; error extracting sshpop header from token: extractSSHPOPCert; error parsing token: "), err: errors.New("sshpop.authorizeToken; error extracting sshpop header from token: extractSSHPOPCert; error parsing token: "),
} }
}, },
"fail/error-revoked-db-check": func(t *testing.T) test {
p, err := generateSSHPOP()
assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, errors.New("force")
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner)
assert.FatalError(t, err)
tok, err := generateSSHPOPToken(p, cert, jwk)
assert.FatalError(t, err)
return test{
p: p,
token: tok,
code: http.StatusInternalServerError,
err: errors.New("sshpop.authorizeToken; error checking checking sshpop cert revocation: force"),
}
},
"fail/cert-already-revoked": func(t *testing.T) test {
p, err := generateSSHPOP()
assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return true, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner)
assert.FatalError(t, err)
tok, err := generateSSHPOPToken(p, cert, jwk)
assert.FatalError(t, err)
return test{
p: p,
token: tok,
code: http.StatusUnauthorized,
err: errors.New("sshpop.authorizeToken; sshpop certificate is revoked"),
}
},
"fail/cert-not-yet-valid": func(t *testing.T) test { "fail/cert-not-yet-valid": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{ cert, jwk, err := createSSHCert(&ssh.Certificate{
CertType: ssh.UserCert, CertType: ssh.UserCert,
ValidAfter: uint64(time.Now().Add(time.Minute).Unix()), ValidAfter: uint64(time.Now().Add(time.Minute).Unix()),
@ -146,11 +102,6 @@ func TestSSHPOP_authorizeToken(t *testing.T) {
"fail/cert-past-validity": func(t *testing.T) test { "fail/cert-past-validity": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{ cert, jwk, err := createSSHCert(&ssh.Certificate{
CertType: ssh.UserCert, CertType: ssh.UserCert,
ValidBefore: uint64(time.Now().Add(-time.Minute).Unix()), ValidBefore: uint64(time.Now().Add(-time.Minute).Unix()),
@ -168,11 +119,6 @@ func TestSSHPOP_authorizeToken(t *testing.T) {
"fail/no-signer-found": func(t *testing.T) test { "fail/no-signer-found": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.HostCert}, sshSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.HostCert}, sshSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateSSHPOPToken(p, cert, jwk) tok, err := generateSSHPOPToken(p, cert, jwk)
@ -187,11 +133,6 @@ func TestSSHPOP_authorizeToken(t *testing.T) {
"fail/error-parsing-claims-bad-sig": func(t *testing.T) test { "fail/error-parsing-claims-bad-sig": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, _, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner) cert, _, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
otherJWK, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0) otherJWK, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0)
@ -208,11 +149,6 @@ func TestSSHPOP_authorizeToken(t *testing.T) {
"fail/invalid-claims-issuer": func(t *testing.T) test { "fail/invalid-claims-issuer": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateToken("foo", "bar", testAudiences.Sign[0], "", tok, err := generateToken("foo", "bar", testAudiences.Sign[0], "",
@ -228,11 +164,6 @@ func TestSSHPOP_authorizeToken(t *testing.T) {
"fail/invalid-audience": func(t *testing.T) test { "fail/invalid-audience": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateToken("foo", p.GetName(), "invalid-aud", "", tok, err := generateToken("foo", p.GetName(), "invalid-aud", "",
@ -248,11 +179,6 @@ func TestSSHPOP_authorizeToken(t *testing.T) {
"fail/empty-subject": func(t *testing.T) test { "fail/empty-subject": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateToken("", p.GetName(), testAudiences.Sign[0], "", tok, err := generateToken("", p.GetName(), testAudiences.Sign[0], "",
@ -268,11 +194,6 @@ func TestSSHPOP_authorizeToken(t *testing.T) {
"ok": func(t *testing.T) test { "ok": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateSSHPOPToken(p, cert, jwk) tok, err := generateSSHPOPToken(p, cert, jwk)
@ -330,11 +251,6 @@ func TestSSHPOP_AuthorizeSSHRevoke(t *testing.T) {
"fail/subject-not-equal-serial": func(t *testing.T) test { "fail/subject-not-equal-serial": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateToken("foo", p.GetName(), testAudiences.SSHRevoke[0], "", tok, err := generateToken("foo", p.GetName(), testAudiences.SSHRevoke[0], "",
@ -350,11 +266,6 @@ func TestSSHPOP_AuthorizeSSHRevoke(t *testing.T) {
"ok": func(t *testing.T) test { "ok": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{Serial: 123455, CertType: ssh.UserCert}, sshSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{Serial: 123455, CertType: ssh.UserCert}, sshSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateToken("123455", p.GetName(), testAudiences.SSHRevoke[0], "", tok, err := generateToken("123455", p.GetName(), testAudiences.SSHRevoke[0], "",
@ -419,11 +330,6 @@ func TestSSHPOP_AuthorizeSSHRenew(t *testing.T) {
"fail/not-host-cert": func(t *testing.T) test { "fail/not-host-cert": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshUserSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshUserSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateToken("foo", p.GetName(), testAudiences.SSHRenew[0], "", tok, err := generateToken("foo", p.GetName(), testAudiences.SSHRenew[0], "",
@ -439,11 +345,6 @@ func TestSSHPOP_AuthorizeSSHRenew(t *testing.T) {
"ok": func(t *testing.T) test { "ok": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{Serial: 123455, CertType: ssh.HostCert}, sshHostSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{Serial: 123455, CertType: ssh.HostCert}, sshHostSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateToken("123455", p.GetName(), testAudiences.SSHRenew[0], "", tok, err := generateToken("123455", p.GetName(), testAudiences.SSHRenew[0], "",
@ -511,11 +412,6 @@ func TestSSHPOP_AuthorizeSSHRekey(t *testing.T) {
"fail/not-host-cert": func(t *testing.T) test { "fail/not-host-cert": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshUserSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{CertType: ssh.UserCert}, sshUserSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateToken("foo", p.GetName(), testAudiences.SSHRekey[0], "", tok, err := generateToken("foo", p.GetName(), testAudiences.SSHRekey[0], "",
@ -531,11 +427,6 @@ func TestSSHPOP_AuthorizeSSHRekey(t *testing.T) {
"ok": func(t *testing.T) test { "ok": func(t *testing.T) test {
p, err := generateSSHPOP() p, err := generateSSHPOP()
assert.FatalError(t, err) assert.FatalError(t, err)
p.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
cert, jwk, err := createSSHCert(&ssh.Certificate{Serial: 123455, CertType: ssh.HostCert}, sshHostSigner) cert, jwk, err := createSSHCert(&ssh.Certificate{Serial: 123455, CertType: ssh.HostCert}, sshHostSigner)
assert.FatalError(t, err) assert.FatalError(t, err)
tok, err := generateToken("123455", p.GetName(), testAudiences.SSHRekey[0], "", tok, err := generateToken("123455", p.GetName(), testAudiences.SSHRekey[0], "",

View file

@ -4,12 +4,17 @@ import (
"context" "context"
"crypto/x509" "crypto/x509"
"encoding/json" "encoding/json"
"encoding/pem"
"fmt" "fmt"
"io/ioutil"
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/admin" "github.com/smallstep/certificates/authority/admin"
"github.com/smallstep/certificates/authority/config" "github.com/smallstep/certificates/authority/config"
"github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/errs"
step "go.step.sm/cli-utils/config"
"go.step.sm/cli-utils/ui"
"go.step.sm/crypto/jose" "go.step.sm/crypto/jose"
"go.step.sm/linkedca" "go.step.sm/linkedca"
"gopkg.in/square/go-jose.v2/jwt" "gopkg.in/square/go-jose.v2/jwt"
@ -234,6 +239,14 @@ func (a *Authority) RemoveProvisioner(ctx context.Context, id string) error {
} }
func CreateFirstProvisioner(ctx context.Context, db admin.DB, password string) (*linkedca.Provisioner, error) { func CreateFirstProvisioner(ctx context.Context, db admin.DB, password string) (*linkedca.Provisioner, error) {
if password == "" {
pass, err := ui.PromptPasswordGenerate("Please enter the password to encrypt your first provisioner, leave empty and we'll generate one")
if err != nil {
return nil, err
}
password = string(pass)
}
jwk, jwe, err := jose.GenerateDefaultKeyPair([]byte(password)) jwk, jwe, err := jose.GenerateDefaultKeyPair([]byte(password))
if err != nil { if err != nil {
return nil, admin.WrapErrorISE(err, "error generating JWK key pair") return nil, admin.WrapErrorISE(err, "error generating JWK key pair")
@ -398,6 +411,13 @@ func durationsToCertificates(d *linkedca.Durations) (min, max, def *provisioner.
return return
} }
func durationsToLinkedca(d *provisioner.Duration) string {
if d == nil {
return ""
}
return d.Duration.String()
}
// claimsToCertificates converts the linkedca provisioner claims type to the // claimsToCertificates converts the linkedca provisioner claims type to the
// certifictes claims type. // certifictes claims type.
func claimsToCertificates(c *linkedca.Claims) (*provisioner.Claims, error) { func claimsToCertificates(c *linkedca.Claims) (*provisioner.Claims, error) {
@ -438,6 +458,109 @@ func claimsToCertificates(c *linkedca.Claims) (*provisioner.Claims, error) {
return pc, nil return pc, nil
} }
func claimsToLinkedca(c *provisioner.Claims) *linkedca.Claims {
if c == nil {
return nil
}
disableRenewal := config.DefaultDisableRenewal
if c.DisableRenewal != nil {
disableRenewal = *c.DisableRenewal
}
lc := &linkedca.Claims{
DisableRenewal: disableRenewal,
}
if c.DefaultTLSDur != nil || c.MinTLSDur != nil || c.MaxTLSDur != nil {
lc.X509 = &linkedca.X509Claims{
Enabled: true,
Durations: &linkedca.Durations{
Default: durationsToLinkedca(c.DefaultTLSDur),
Min: durationsToLinkedca(c.MinTLSDur),
Max: durationsToLinkedca(c.MaxTLSDur),
},
}
}
if c.EnableSSHCA != nil && *c.EnableSSHCA {
lc.Ssh = &linkedca.SSHClaims{
Enabled: true,
}
if c.DefaultUserSSHDur != nil || c.MinUserSSHDur != nil || c.MaxUserSSHDur != nil {
lc.Ssh.UserDurations = &linkedca.Durations{
Default: durationsToLinkedca(c.DefaultUserSSHDur),
Min: durationsToLinkedca(c.MinUserSSHDur),
Max: durationsToLinkedca(c.MaxUserSSHDur),
}
}
if c.DefaultHostSSHDur != nil || c.MinHostSSHDur != nil || c.MaxHostSSHDur != nil {
lc.Ssh.HostDurations = &linkedca.Durations{
Default: durationsToLinkedca(c.DefaultHostSSHDur),
Min: durationsToLinkedca(c.MinHostSSHDur),
Max: durationsToLinkedca(c.MaxHostSSHDur),
}
}
}
return lc
}
func provisionerOptionsToLinkedca(p *provisioner.Options) (*linkedca.Template, *linkedca.Template, error) {
var err error
var x509Template, sshTemplate *linkedca.Template
if p == nil {
return nil, nil, nil
}
if p.X509 != nil && p.X509.HasTemplate() {
x509Template = &linkedca.Template{
Template: nil,
Data: nil,
}
if p.X509.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 {
return nil, nil, errors.Wrap(err, "error reading x509 template")
}
}
}
if p.SSH != nil && p.SSH.HasTemplate() {
sshTemplate = &linkedca.Template{
Template: nil,
Data: nil,
}
if p.SSH.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 {
return nil, nil, errors.Wrap(err, "error reading ssh template")
}
}
}
return x509Template, sshTemplate, nil
}
func provisionerPEMToLinkedca(b []byte) [][]byte {
var roots [][]byte
var block *pem.Block
for {
if block, b = pem.Decode(b); block == nil {
break
}
roots = append(roots, pem.EncodeToMemory(block))
}
return roots
}
// ProvisionerToCertificates converts the linkedca provisioner type to the certificates provisioner // ProvisionerToCertificates converts the linkedca provisioner type to the certificates provisioner
// interface. // interface.
func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, error) { func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, error) {
@ -448,7 +571,7 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface,
details := p.Details.GetData() details := p.Details.GetData()
if details == nil { if details == nil {
return nil, fmt.Errorf("provisioner does not have any details") return nil, errors.New("provisioner does not have any details")
} }
options := optionsToCertificates(p) options := optionsToCertificates(p)
@ -457,7 +580,7 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface,
case *linkedca.ProvisionerDetails_JWK: case *linkedca.ProvisionerDetails_JWK:
jwk := new(jose.JSONWebKey) jwk := new(jose.JSONWebKey)
if err := json.Unmarshal(d.JWK.PublicKey, &jwk); err != nil { if err := json.Unmarshal(d.JWK.PublicKey, &jwk); err != nil {
return nil, err return nil, errors.Wrap(err, "error unmarshaling public key")
} }
return &provisioner.JWK{ return &provisioner.JWK{
ID: p.Id, ID: p.Id,
@ -589,6 +712,233 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface,
} }
} }
// ProvisionerToLinkedca converts a provisioner.Interface to a
// linkedca.Provisioner type.
func ProvisionerToLinkedca(p provisioner.Interface) (*linkedca.Provisioner, error) {
switch p := p.(type) {
case *provisioner.JWK:
x509Template, sshTemplate, err := provisionerOptionsToLinkedca(p.Options)
if err != nil {
return nil, err
}
publicKey, err := json.Marshal(p.Key)
if err != nil {
return nil, errors.Wrap(err, "error marshaling key")
}
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_JWK,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_JWK{
JWK: &linkedca.JWKProvisioner{
PublicKey: publicKey,
EncryptedPrivateKey: []byte(p.EncryptedKey),
},
},
},
Claims: claimsToLinkedca(p.Claims),
X509Template: x509Template,
SshTemplate: sshTemplate,
}, nil
case *provisioner.OIDC:
x509Template, sshTemplate, err := provisionerOptionsToLinkedca(p.Options)
if err != nil {
return nil, err
}
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_OIDC,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_OIDC{
OIDC: &linkedca.OIDCProvisioner{
ClientId: p.ClientID,
ClientSecret: p.ClientSecret,
ConfigurationEndpoint: p.ConfigurationEndpoint,
Admins: p.Admins,
Domains: p.Domains,
Groups: p.Groups,
ListenAddress: p.ListenAddress,
TenantId: p.TenantID,
},
},
},
Claims: claimsToLinkedca(p.Claims),
X509Template: x509Template,
SshTemplate: sshTemplate,
}, nil
case *provisioner.GCP:
x509Template, sshTemplate, err := provisionerOptionsToLinkedca(p.Options)
if err != nil {
return nil, err
}
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_GCP,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_GCP{
GCP: &linkedca.GCPProvisioner{
ServiceAccounts: p.ServiceAccounts,
ProjectIds: p.ProjectIDs,
DisableCustomSans: p.DisableCustomSANs,
DisableTrustOnFirstUse: p.DisableTrustOnFirstUse,
InstanceAge: p.InstanceAge.String(),
},
},
},
Claims: claimsToLinkedca(p.Claims),
X509Template: x509Template,
SshTemplate: sshTemplate,
}, nil
case *provisioner.AWS:
x509Template, sshTemplate, err := provisionerOptionsToLinkedca(p.Options)
if err != nil {
return nil, err
}
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_AWS,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_AWS{
AWS: &linkedca.AWSProvisioner{
Accounts: p.Accounts,
DisableCustomSans: p.DisableCustomSANs,
DisableTrustOnFirstUse: p.DisableTrustOnFirstUse,
InstanceAge: p.InstanceAge.String(),
},
},
},
Claims: claimsToLinkedca(p.Claims),
X509Template: x509Template,
SshTemplate: sshTemplate,
}, nil
case *provisioner.Azure:
x509Template, sshTemplate, err := provisionerOptionsToLinkedca(p.Options)
if err != nil {
return nil, err
}
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_AZURE,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_Azure{
Azure: &linkedca.AzureProvisioner{
TenantId: p.TenantID,
ResourceGroups: p.ResourceGroups,
Audience: p.Audience,
DisableCustomSans: p.DisableCustomSANs,
DisableTrustOnFirstUse: p.DisableTrustOnFirstUse,
},
},
},
Claims: claimsToLinkedca(p.Claims),
X509Template: x509Template,
SshTemplate: sshTemplate,
}, nil
case *provisioner.ACME:
x509Template, sshTemplate, err := provisionerOptionsToLinkedca(p.Options)
if err != nil {
return nil, err
}
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_ACME,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_ACME{
ACME: &linkedca.ACMEProvisioner{
ForceCn: p.ForceCN,
},
},
},
Claims: claimsToLinkedca(p.Claims),
X509Template: x509Template,
SshTemplate: sshTemplate,
}, nil
case *provisioner.X5C:
x509Template, sshTemplate, err := provisionerOptionsToLinkedca(p.Options)
if err != nil {
return nil, err
}
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_X5C,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_X5C{
X5C: &linkedca.X5CProvisioner{
Roots: provisionerPEMToLinkedca(p.Roots),
},
},
},
Claims: claimsToLinkedca(p.Claims),
X509Template: x509Template,
SshTemplate: sshTemplate,
}, nil
case *provisioner.K8sSA:
x509Template, sshTemplate, err := provisionerOptionsToLinkedca(p.Options)
if err != nil {
return nil, err
}
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_K8SSA,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_K8SSA{
K8SSA: &linkedca.K8SSAProvisioner{
PublicKeys: provisionerPEMToLinkedca(p.PubKeys),
},
},
},
Claims: claimsToLinkedca(p.Claims),
X509Template: x509Template,
SshTemplate: sshTemplate,
}, nil
case *provisioner.SSHPOP:
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_SSHPOP,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_SSHPOP{
SSHPOP: &linkedca.SSHPOPProvisioner{},
},
},
Claims: claimsToLinkedca(p.Claims),
}, nil
case *provisioner.SCEP:
x509Template, sshTemplate, err := provisionerOptionsToLinkedca(p.Options)
if err != nil {
return nil, err
}
return &linkedca.Provisioner{
Id: p.ID,
Type: linkedca.Provisioner_SCEP,
Name: p.GetName(),
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_SCEP{
SCEP: &linkedca.SCEPProvisioner{
ForceCn: p.ForceCN,
Challenge: p.GetChallengePassword(),
Capabilities: p.Capabilities,
MinimumPublicKeyLength: int32(p.MinimumPublicKeyLength),
},
},
},
Claims: claimsToLinkedca(p.Claims),
X509Template: x509Template,
SshTemplate: sshTemplate,
}, nil
default:
return nil, fmt.Errorf("provisioner %s not implemented", p.GetType())
}
}
func parseInstanceAge(age string) (provisioner.Duration, error) { func parseInstanceAge(age string) (provisioner.Duration, error) {
var instanceAge provisioner.Duration var instanceAge provisioner.Duration
if age != "" { if age != "" {

View file

@ -239,7 +239,7 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi
} }
} }
if err = a.db.StoreSSHCertificate(cert); err != nil && err != db.ErrNotImplemented { if err = a.storeSSHCertificate(cert); err != nil && err != db.ErrNotImplemented {
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.SignSSH: error storing certificate in db") return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.SignSSH: error storing certificate in db")
} }
@ -249,7 +249,11 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi
// RenewSSH creates a signed SSH certificate using the old SSH certificate as a template. // RenewSSH creates a signed SSH certificate using the old SSH certificate as a template.
func (a *Authority) RenewSSH(ctx context.Context, oldCert *ssh.Certificate) (*ssh.Certificate, error) { func (a *Authority) RenewSSH(ctx context.Context, oldCert *ssh.Certificate) (*ssh.Certificate, error) {
if oldCert.ValidAfter == 0 || oldCert.ValidBefore == 0 { if oldCert.ValidAfter == 0 || oldCert.ValidBefore == 0 {
return nil, errs.BadRequest("rewnewSSH: cannot renew certificate without validity period") return nil, errs.BadRequest("renewSSH: cannot renew certificate without validity period")
}
if err := a.authorizeSSHCertificate(ctx, oldCert); err != nil {
return nil, err
} }
backdate := a.config.AuthorityConfig.Backdate.Duration backdate := a.config.AuthorityConfig.Backdate.Duration
@ -294,7 +298,7 @@ func (a *Authority) RenewSSH(ctx context.Context, oldCert *ssh.Certificate) (*ss
return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSH: error signing certificate") return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSH: error signing certificate")
} }
if err = a.db.StoreSSHCertificate(cert); err != nil && err != db.ErrNotImplemented { if err = a.storeSSHCertificate(cert); err != nil && err != db.ErrNotImplemented {
return nil, errs.Wrap(http.StatusInternalServerError, err, "renewSSH: error storing certificate in db") return nil, errs.Wrap(http.StatusInternalServerError, err, "renewSSH: error storing certificate in db")
} }
@ -319,6 +323,10 @@ func (a *Authority) RekeySSH(ctx context.Context, oldCert *ssh.Certificate, pub
return nil, errs.BadRequest("rekeySSH; cannot rekey certificate without validity period") return nil, errs.BadRequest("rekeySSH; cannot rekey certificate without validity period")
} }
if err := a.authorizeSSHCertificate(ctx, oldCert); err != nil {
return nil, err
}
backdate := a.config.AuthorityConfig.Backdate.Duration backdate := a.config.AuthorityConfig.Backdate.Duration
duration := time.Duration(oldCert.ValidBefore-oldCert.ValidAfter) * time.Second duration := time.Duration(oldCert.ValidBefore-oldCert.ValidAfter) * time.Second
now := time.Now() now := time.Now()
@ -369,13 +377,23 @@ func (a *Authority) RekeySSH(ctx context.Context, oldCert *ssh.Certificate, pub
} }
} }
if err = a.db.StoreSSHCertificate(cert); err != nil && err != db.ErrNotImplemented { if err = a.storeSSHCertificate(cert); err != nil && err != db.ErrNotImplemented {
return nil, errs.Wrap(http.StatusInternalServerError, err, "rekeySSH; error storing certificate in db") return nil, errs.Wrap(http.StatusInternalServerError, err, "rekeySSH; error storing certificate in db")
} }
return cert, nil return cert, nil
} }
func (a *Authority) storeSSHCertificate(cert *ssh.Certificate) error {
type sshCertificateStorer interface {
StoreSSHCertificate(crt *ssh.Certificate) error
}
if s, ok := a.adminDB.(sshCertificateStorer); ok {
return s.StoreSSHCertificate(cert)
}
return a.db.StoreSSHCertificate(cert)
}
// IsValidForAddUser checks if a user provisioner certificate can be issued to // IsValidForAddUser checks if a user provisioner certificate can be issued to
// the given certificate. // the given certificate.
func IsValidForAddUser(cert *ssh.Certificate) error { func IsValidForAddUser(cert *ssh.Certificate) error {
@ -451,7 +469,7 @@ func (a *Authority) SignSSHAddUser(ctx context.Context, key ssh.PublicKey, subje
} }
cert.Signature = sig cert.Signature = sig
if err = a.db.StoreSSHCertificate(cert); err != nil && err != db.ErrNotImplemented { if err = a.storeSSHCertificate(cert); err != nil && err != db.ErrNotImplemented {
return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSHAddUser: error storing certificate in db") return nil, errs.Wrap(http.StatusInternalServerError, err, "signSSHAddUser: error storing certificate in db")
} }

View file

@ -750,6 +750,11 @@ func TestAuthority_RekeySSH(t *testing.T) {
now := time.Now().UTC() now := time.Now().UTC()
a := testAuthority(t) a := testAuthority(t)
a.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
}
type test struct { type test struct {
auth *Authority auth *Authority
@ -763,6 +768,56 @@ func TestAuthority_RekeySSH(t *testing.T) {
code int code int
} }
tests := map[string]func(t *testing.T) *test{ tests := map[string]func(t *testing.T) *test{
"fail/is-revoked": func(t *testing.T) *test {
auth := testAuthority(t)
auth.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return true, nil
},
}
return &test{
auth: auth,
userSigner: signer,
hostSigner: signer,
cert: &ssh.Certificate{
Serial: 1234567890,
ValidAfter: uint64(now.Unix()),
ValidBefore: uint64(now.Add(time.Hour).Unix()),
CertType: ssh.UserCert,
ValidPrincipals: []string{"foo", "bar"},
KeyId: "foo",
},
key: pub,
signOpts: []provisioner.SignOption{},
err: errors.New("authority.authorizeSSHCertificate: certificate has been revoked"),
code: http.StatusUnauthorized,
}
},
"fail/is-revoked-error": func(t *testing.T) *test {
auth := testAuthority(t)
auth.db = &db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, errors.New("an error")
},
}
return &test{
auth: auth,
userSigner: signer,
hostSigner: signer,
cert: &ssh.Certificate{
Serial: 1234567890,
ValidAfter: uint64(now.Unix()),
ValidBefore: uint64(now.Add(time.Hour).Unix()),
CertType: ssh.UserCert,
ValidPrincipals: []string{"foo", "bar"},
KeyId: "foo",
},
key: pub,
signOpts: []provisioner.SignOption{},
err: errors.New("authority.authorizeSSHCertificate: an error"),
code: http.StatusInternalServerError,
}
},
"fail/opts-type": func(t *testing.T) *test { "fail/opts-type": func(t *testing.T) *test {
return &test{ return &test{
userSigner: signer, userSigner: signer,
@ -831,6 +886,9 @@ func TestAuthority_RekeySSH(t *testing.T) {
"fail/db-store": func(t *testing.T) *test { "fail/db-store": func(t *testing.T) *test {
return &test{ return &test{
auth: testAuthority(t, WithDatabase(&db.MockAuthDB{ auth: testAuthority(t, WithDatabase(&db.MockAuthDB{
MIsSSHRevoked: func(sn string) (bool, error) {
return false, nil
},
MStoreSSHCertificate: func(cert *ssh.Certificate) error { MStoreSSHCertificate: func(cert *ssh.Certificate) error {
return errors.New("force") return errors.New("force")
}, },

View file

@ -21,6 +21,7 @@ import (
"go.step.sm/crypto/keyutil" "go.step.sm/crypto/keyutil"
"go.step.sm/crypto/pemutil" "go.step.sm/crypto/pemutil"
"go.step.sm/crypto/x509util" "go.step.sm/crypto/x509util"
"golang.org/x/crypto/ssh"
) )
// GetTLSOptions returns the tls options configured. // GetTLSOptions returns the tls options configured.
@ -36,7 +37,6 @@ func withDefaultASN1DN(def *config.ASN1DN) provisioner.CertificateModifierFunc {
if def == nil { if def == nil {
return errors.New("default ASN1DN template cannot be nil") return errors.New("default ASN1DN template cannot be nil")
} }
if len(crt.Subject.Country) == 0 && def.Country != "" { if len(crt.Subject.Country) == 0 && def.Country != "" {
crt.Subject.Country = append(crt.Subject.Country, def.Country) crt.Subject.Country = append(crt.Subject.Country, def.Country)
} }
@ -55,7 +55,12 @@ func withDefaultASN1DN(def *config.ASN1DN) provisioner.CertificateModifierFunc {
if len(crt.Subject.StreetAddress) == 0 && def.StreetAddress != "" { if len(crt.Subject.StreetAddress) == 0 && def.StreetAddress != "" {
crt.Subject.StreetAddress = append(crt.Subject.StreetAddress, def.StreetAddress) crt.Subject.StreetAddress = append(crt.Subject.StreetAddress, def.StreetAddress)
} }
if len(crt.Subject.SerialNumber) == 0 && def.SerialNumber != "" {
crt.Subject.SerialNumber = def.SerialNumber
}
if len(crt.Subject.CommonName) == 0 && def.CommonName != "" {
crt.Subject.CommonName = def.CommonName
}
return nil return nil
} }
} }
@ -280,9 +285,15 @@ func (a *Authority) Rekey(oldCert *x509.Certificate, pk crypto.PublicKey) ([]*x5
// `StoreCertificate(...*x509.Certificate) error` instead of just // `StoreCertificate(...*x509.Certificate) error` instead of just
// `StoreCertificate(*x509.Certificate) error`. // `StoreCertificate(*x509.Certificate) error`.
func (a *Authority) storeCertificate(fullchain []*x509.Certificate) error { func (a *Authority) storeCertificate(fullchain []*x509.Certificate) error {
if s, ok := a.db.(interface { type certificateChainStorer interface {
StoreCertificateChain(...*x509.Certificate) error StoreCertificateChain(...*x509.Certificate) error
}); ok { }
// Store certificate in linkedca
if s, ok := a.adminDB.(certificateChainStorer); ok {
return s.StoreCertificateChain(fullchain...)
}
// Store certificate in local db
if s, ok := a.db.(certificateChainStorer); ok {
return s.StoreCertificateChain(fullchain...) return s.StoreCertificateChain(fullchain...)
} }
return a.db.StoreCertificate(fullchain[0]) return a.db.StoreCertificate(fullchain[0])
@ -293,9 +304,15 @@ func (a *Authority) storeCertificate(fullchain []*x509.Certificate) error {
// //
// TODO: at some point we should implement this in the standard implementation. // TODO: at some point we should implement this in the standard implementation.
func (a *Authority) storeRenewedCertificate(oldCert *x509.Certificate, fullchain []*x509.Certificate) error { func (a *Authority) storeRenewedCertificate(oldCert *x509.Certificate, fullchain []*x509.Certificate) error {
if s, ok := a.db.(interface { type renewedCertificateChainStorer interface {
StoreRenewedCertificate(*x509.Certificate, ...*x509.Certificate) error StoreRenewedCertificate(*x509.Certificate, ...*x509.Certificate) error
}); ok { }
// Store certificate in linkedca
if s, ok := a.adminDB.(renewedCertificateChainStorer); ok {
return s.StoreRenewedCertificate(oldCert, fullchain...)
}
// Store certificate in local db
if s, ok := a.db.(renewedCertificateChainStorer); ok {
return s.StoreRenewedCertificate(oldCert, fullchain...) return s.StoreRenewedCertificate(oldCert, fullchain...)
} }
return a.db.StoreCertificate(fullchain[0]) return a.db.StoreCertificate(fullchain[0])
@ -366,7 +383,7 @@ func (a *Authority) Revoke(ctx context.Context, revokeOpts *RevokeOptions) error
} }
rci.ProvisionerID = p.GetID() rci.ProvisionerID = p.GetID()
rci.TokenID, err = p.GetTokenID(revokeOpts.OTT) rci.TokenID, err = p.GetTokenID(revokeOpts.OTT)
if err != nil { if err != nil && !errors.Is(err, provisioner.ErrAllowTokenReuse) {
return errs.Wrap(http.StatusInternalServerError, err, return errs.Wrap(http.StatusInternalServerError, err,
"authority.Revoke; could not get ID for token") "authority.Revoke; could not get ID for token")
} }
@ -381,7 +398,7 @@ func (a *Authority) Revoke(ctx context.Context, revokeOpts *RevokeOptions) error
} }
if provisioner.MethodFromContext(ctx) == provisioner.SSHRevokeMethod { if provisioner.MethodFromContext(ctx) == provisioner.SSHRevokeMethod {
err = a.db.RevokeSSH(rci) err = a.revokeSSH(nil, rci)
} else { } else {
// Revoke an X.509 certificate using CAS. If the certificate is not // Revoke an X.509 certificate using CAS. If the certificate is not
// provided we will try to read it from the db. If the read fails we // provided we will try to read it from the db. If the read fails we
@ -408,7 +425,7 @@ func (a *Authority) Revoke(ctx context.Context, revokeOpts *RevokeOptions) error
} }
// Save as revoked in the Db. // Save as revoked in the Db.
err = a.db.Revoke(rci) err = a.revoke(revokedCert, rci)
} }
switch err { switch err {
case nil: case nil:
@ -423,6 +440,24 @@ func (a *Authority) Revoke(ctx context.Context, revokeOpts *RevokeOptions) error
} }
} }
func (a *Authority) revoke(crt *x509.Certificate, rci *db.RevokedCertificateInfo) error {
if lca, ok := a.adminDB.(interface {
Revoke(*x509.Certificate, *db.RevokedCertificateInfo) error
}); ok {
return lca.Revoke(crt, rci)
}
return a.db.Revoke(rci)
}
func (a *Authority) revokeSSH(crt *ssh.Certificate, rci *db.RevokedCertificateInfo) error {
if lca, ok := a.adminDB.(interface {
RevokeSSH(*ssh.Certificate, *db.RevokedCertificateInfo) error
}); ok {
return lca.RevokeSSH(crt, rci)
}
return a.db.Revoke(rci)
}
// GetTLSCertificate creates a new leaf certificate to be used by the CA HTTPS server. // GetTLSCertificate creates a new leaf certificate to be used by the CA HTTPS server.
func (a *Authority) GetTLSCertificate() (*tls.Certificate, error) { func (a *Authority) GetTLSCertificate() (*tls.Certificate, error) {
fatal := func(err error) (*tls.Certificate, error) { fatal := func(err error) (*tls.Certificate, error) {

View file

@ -30,6 +30,7 @@ import (
type options struct { type options struct {
configFile string configFile string
linkedCAToken string
password []byte password []byte
issuerPassword []byte issuerPassword []byte
database db.AuthDB database db.AuthDB
@ -75,6 +76,13 @@ func WithDatabase(db db.AuthDB) Option {
} }
} }
// WithLinkedCAToken sets the token used to authenticate with the linkedca.
func WithLinkedCAToken(token string) Option {
return func(o *options) {
o.linkedCAToken = token
}
}
// CA is the type used to build the complete certificate authority. It builds // CA is the type used to build the complete certificate authority. It builds
// the HTTP server, set ups the middlewares and the HTTP handlers. // the HTTP server, set ups the middlewares and the HTTP handlers.
type CA struct { type CA struct {
@ -111,6 +119,10 @@ func (ca *CA) Init(config *config.Config) (*CA, error) {
} }
var opts []authority.Option var opts []authority.Option
if ca.opts.linkedCAToken != "" {
opts = append(opts, authority.WithLinkedCAToken(ca.opts.linkedCAToken))
}
if ca.opts.database != nil { if ca.opts.database != nil {
opts = append(opts, authority.WithDatabase(ca.opts.database)) opts = append(opts, authority.WithDatabase(ca.opts.database))
} }
@ -326,6 +338,7 @@ func (ca *CA) Reload() error {
newCA, err := New(config, newCA, err := New(config,
WithPassword(ca.opts.password), WithPassword(ca.opts.password),
WithIssuerPassword(ca.opts.issuerPassword), WithIssuerPassword(ca.opts.issuerPassword),
WithLinkedCAToken(ca.opts.linkedCAToken),
WithConfigFile(ca.opts.configFile), WithConfigFile(ca.opts.configFile),
WithDatabase(ca.auth.GetDatabase()), WithDatabase(ca.auth.GetDatabase()),
) )

7
ca/testdata/ca.json vendored
View file

@ -9,12 +9,11 @@
"logger": {"format": "text"}, "logger": {"format": "text"},
"tls": { "tls": {
"minVersion": 1.2, "minVersion": 1.2,
"maxVersion": 1.2, "maxVersion": 1.3,
"renegotiation": false, "renegotiation": false,
"cipherSuites": [ "cipherSuites": [
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
] ]
}, },
"authority": { "authority": {

View file

@ -38,10 +38,17 @@ type Options struct {
CertificateChain []*x509.Certificate `json:"-"` CertificateChain []*x509.Certificate `json:"-"`
Signer crypto.Signer `json:"-"` Signer crypto.Signer `json:"-"`
// IsCreator is set to true when we're creating a certificate authority. Is // IsCreator is set to true when we're creating a certificate authority. It
// used to skip some validations when initializing a CertificateAuthority. // is used to skip some validations when initializing a
// CertificateAuthority. This option is used on SoftCAS and CloudCAS.
IsCreator bool `json:"-"` IsCreator bool `json:"-"`
// IsCAGetter is set to true when we're just using the
// CertificateAuthorityGetter interface to retrieve the root certificate. It
// is used to skip some validations when initializing a
// CertificateAuthority. This option is used on StepCAS.
IsCAGetter bool `json:"-"`
// KeyManager is the KMS used to generate keys in SoftCAS. // KeyManager is the KMS used to generate keys in SoftCAS.
KeyManager kms.KeyManager `json:"-"` KeyManager kms.KeyManager `json:"-"`

View file

@ -47,10 +47,13 @@ func New(ctx context.Context, opts apiv1.Options) (*StepCAS, error) {
return nil, err return nil, err
} }
// Create configured issuer var iss stepIssuer
iss, err := newStepIssuer(caURL, client, opts.CertificateIssuer) // Create configured issuer unless we only want to use GetCertificateAuthority.
if err != nil { // This avoid the request for the password if not provided.
return nil, err if !opts.IsCAGetter {
if iss, err = newStepIssuer(caURL, client, opts.CertificateIssuer); err != nil {
return nil, err
}
} }
return &StepCAS{ return &StepCAS{

View file

@ -411,6 +411,19 @@ func TestNew(t *testing.T) {
client: client, client: client,
fingerprint: testRootFingerprint, fingerprint: testRootFingerprint,
}, false}, }, false},
{"ok ca getter", args{context.TODO(), apiv1.Options{
IsCAGetter: true,
CertificateAuthority: caURL.String(),
CertificateAuthorityFingerprint: testRootFingerprint,
CertificateIssuer: &apiv1.CertificateIssuer{
Type: "jwk",
Provisioner: "ra@doe.org",
},
}}, &StepCAS{
iss: nil,
client: client,
fingerprint: testRootFingerprint,
}, false},
{"fail authority", args{context.TODO(), apiv1.Options{ {"fail authority", args{context.TODO(), apiv1.Options{
CertificateAuthority: "", CertificateAuthority: "",
CertificateAuthorityFingerprint: testRootFingerprint, CertificateAuthorityFingerprint: testRootFingerprint,

View file

@ -8,11 +8,13 @@ import (
"net" "net"
"net/http" "net/http"
"os" "os"
"strings"
"unicode" "unicode"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/config" "github.com/smallstep/certificates/authority/config"
"github.com/smallstep/certificates/ca" "github.com/smallstep/certificates/ca"
"github.com/smallstep/certificates/pki"
"github.com/urfave/cli" "github.com/urfave/cli"
"go.step.sm/cli-utils/errs" "go.step.sm/cli-utils/errs"
) )
@ -38,6 +40,11 @@ certificate issuer private key used in the RA mode.`,
Name: "resolver", Name: "resolver",
Usage: "address of a DNS resolver to be used instead of the default.", Usage: "address of a DNS resolver to be used instead of the default.",
}, },
cli.StringFlag{
Name: "token",
Usage: "token used to enable the linked ca.",
EnvVar: "STEP_CA_TOKEN",
},
}, },
} }
@ -46,6 +53,7 @@ func appAction(ctx *cli.Context) error {
passFile := ctx.String("password-file") passFile := ctx.String("password-file")
issuerPassFile := ctx.String("issuer-password-file") issuerPassFile := ctx.String("issuer-password-file")
resolver := ctx.String("resolver") resolver := ctx.String("resolver")
token := ctx.String("token")
// If zero cmd line args show help, if >1 cmd line args show error. // If zero cmd line args show help, if >1 cmd line args show error.
if ctx.NArg() == 0 { if ctx.NArg() == 0 {
@ -61,6 +69,18 @@ func appAction(ctx *cli.Context) error {
fatal(err) fatal(err)
} }
if config.AuthorityConfig != nil {
if token == "" && strings.EqualFold(config.AuthorityConfig.DeploymentType, pki.LinkedDeployment.String()) {
return errors.New(`'step-ca' requires the '--token' flag for linked deploy type.
To get a linked authority token:
1. Log in or create a Certificate Manager account at ` + "\033[1mhttps://u.step.sm/linked\033[0m" + `
2. Add a new authority and select "Link a step-ca instance"
3. Follow instructions in browser to start 'step-ca' using the '--token' flag
`)
}
}
var password []byte var password []byte
if passFile != "" { if passFile != "" {
if password, err = ioutil.ReadFile(passFile); err != nil { if password, err = ioutil.ReadFile(passFile); err != nil {
@ -88,7 +108,8 @@ func appAction(ctx *cli.Context) error {
srv, err := ca.New(config, srv, err := ca.New(config,
ca.WithConfigFile(configFile), ca.WithConfigFile(configFile),
ca.WithPassword(password), ca.WithPassword(password),
ca.WithIssuerPassword(issuerPassword)) ca.WithIssuerPassword(issuerPassword),
ca.WithLinkedCAToken(token))
if err != nil { if err != nil {
fatal(err) fatal(err)
} }

113
commands/export.go Normal file
View file

@ -0,0 +1,113 @@
package commands
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"unicode"
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority"
"github.com/smallstep/certificates/authority/config"
"github.com/urfave/cli"
"google.golang.org/protobuf/encoding/protojson"
"go.step.sm/cli-utils/command"
"go.step.sm/cli-utils/errs"
)
func init() {
command.Register(cli.Command{
Name: "export",
Usage: "export the current configuration of step-ca",
UsageText: "**step-ca export** <config>",
Action: exportAction,
Description: `**step-ca export** exports the current configuration of step-ca.
Note that neither the PKI password nor the certificate issuer password will be
included in the export file.
## POSITIONAL ARGUMENTS
<config>
: The ca.json that contains the step-ca configuration.
## EXAMPLES
Export the current configuration:
'''
$ step-ca export $(step path)/config/ca.json
'''`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "password-file",
Usage: `path to the <file> containing the password to decrypt the
intermediate private key.`,
},
cli.StringFlag{
Name: "issuer-password-file",
Usage: `path to the <file> containing the password to decrypt the
certificate issuer private key used in the RA mode.`,
},
},
})
}
func exportAction(ctx *cli.Context) error {
if err := errs.NumberOfArguments(ctx, 1); err != nil {
return err
}
configFile := ctx.Args().Get(0)
passwordFile := ctx.String("password-file")
issuerPasswordFile := ctx.String("issuer-password-file")
config, err := config.LoadConfiguration(configFile)
if err != nil {
return err
}
if err := config.Validate(); err != nil {
return err
}
if passwordFile != "" {
b, err := ioutil.ReadFile(passwordFile)
if err != nil {
return errors.Wrapf(err, "error reading %s", passwordFile)
}
config.Password = string(bytes.TrimRightFunc(b, unicode.IsSpace))
}
if issuerPasswordFile != "" {
b, err := ioutil.ReadFile(issuerPasswordFile)
if err != nil {
return errors.Wrapf(err, "error reading %s", issuerPasswordFile)
}
if config.AuthorityConfig.CertificateIssuer != nil {
config.AuthorityConfig.CertificateIssuer.Password = string(bytes.TrimRightFunc(b, unicode.IsSpace))
}
}
auth, err := authority.New(config)
if err != nil {
return err
}
export, err := auth.Export()
if err != nil {
return err
}
b, err := protojson.Marshal(export)
if err != nil {
return errors.Wrap(err, "error marshaling export")
}
var buf bytes.Buffer
if err := json.Indent(&buf, b, "", "\t"); err != nil {
return errors.Wrap(err, "error indenting export")
}
fmt.Println(buf.String())
return nil
}

View file

@ -163,17 +163,21 @@ func onboardAction(ctx *cli.Context) error {
} }
func onboardPKI(config onboardingConfiguration) (*config.Config, string, error) { func onboardPKI(config onboardingConfiguration) (*config.Config, string, error) {
var opts = []pki.Option{
pki.WithAddress(config.Address),
pki.WithDNSNames([]string{config.DNS}),
pki.WithProvisioner("admin"),
}
p, err := pki.New(apiv1.Options{ p, err := pki.New(apiv1.Options{
Type: apiv1.SoftCAS, Type: apiv1.SoftCAS,
IsCreator: true, IsCreator: true,
}) }, opts...)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
p.SetAddress(config.Address) // Generate pki
p.SetDNSNames([]string{config.DNS})
ui.Println("Generating root certificate...") ui.Println("Generating root certificate...")
root, err := p.GenerateRootCertificate(config.Name, config.Name, config.Name, config.password) root, err := p.GenerateRootCertificate(config.Name, config.Name, config.Name, config.password)
if err != nil { if err != nil {
@ -186,8 +190,12 @@ func onboardPKI(config onboardingConfiguration) (*config.Config, string, error)
return nil, "", err return nil, "", err
} }
// Write files to disk
if err = p.WriteFiles(); err != nil {
return nil, "", err
}
// Generate provisioner // Generate provisioner
p.SetProvisioner("admin")
ui.Println("Generating admin provisioner...") ui.Println("Generating admin provisioner...")
if err = p.GenerateKeyPairs(config.password); err != nil { if err = p.GenerateKeyPairs(config.password); err != nil {
return nil, "", err return nil, "", err

View file

@ -24,4 +24,7 @@ VOLUME ["/home/step"]
STOPSIGNAL SIGTERM STOPSIGNAL SIGTERM
HEALTHCHECK CMD step ca health 2>/dev/null | grep "^ok" >/dev/null HEALTHCHECK CMD step ca health 2>/dev/null | grep "^ok" >/dev/null
COPY docker/entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
CMD exec /usr/local/bin/step-ca --password-file $PWDPATH $CONFIGPATH CMD exec /usr/local/bin/step-ca --password-file $PWDPATH $CONFIGPATH

60
docker/entrypoint.sh Normal file
View file

@ -0,0 +1,60 @@
#!/bin/bash
set -eo pipefail
# Paraphrased from:
# https://github.com/influxdata/influxdata-docker/blob/0d341f18067c4652dfa8df7dcb24d69bf707363d/influxdb/2.0/entrypoint.sh
# (a repo with no LICENSE.md)
export STEPPATH=$(step path)
# List of env vars required for step ca init
declare -ra REQUIRED_INIT_VARS=(DOCKER_STEPCA_INIT_NAME DOCKER_STEPCA_INIT_DNS_NAMES)
# Ensure all env vars required to run step ca init are set.
function init_if_possible () {
local missing_vars=0
for var in "${REQUIRED_INIT_VARS[@]}"; do
if [ -z "${!var}" ]; then
missing_vars=1
fi
done
if [ ${missing_vars} = 1 ]; then
>&2 echo "there is no ca.json config file; please run step ca init, or provide config parameters via DOCKER_STEPCA_INIT_ vars"
else
step_ca_init "${@}"
fi
}
function generate_password () {
set +o pipefail
< /dev/urandom tr -dc A-Za-z0-9 | head -c40
echo
set -o pipefail
}
# Initialize a CA if not already initialized
function step_ca_init () {
local -a setup_args=(
--name "${DOCKER_STEPCA_INIT_NAME}"
--dns "${DOCKER_STEPCA_INIT_DNS_NAMES}"
--provisioner "${DOCKER_STEPCA_INIT_PROVISIONER_NAME:-admin}"
--password-file "${STEPPATH}/password"
--address ":9000"
)
if [ -n "${DOCKER_STEPCA_INIT_PASSWORD}" ]; then
echo "${DOCKER_STEPCA_INIT_PASSWORD}" > "${STEPPATH}/password"
else
generate_password > "${STEPPATH}/password"
fi
if [ -n "${DOCKER_STEPCA_INIT_SSH}" ]; then
setup_args=("${setup_args[@]}" --ssh)
fi
step ca init "${setup_args[@]}"
mv $STEPPATH/password $PWDPATH
}
if [ ! -f "${STEPPATH}/config/ca.json" ]; then
init_if_possible
fi
exec "${@}"

View file

@ -7,12 +7,20 @@ to manage issues, etc.
## Table of Contents ## Table of Contents
* [Building From Source](#building-from-source) - [Contributing to `step certificates`](#contributing-to-step-certificates)
* [Asking Support Questions](#asking-support-questions) - [Table of Contents](#table-of-contents)
* [Reporting Issues](#reporting-issues) - [Building From Source](#building-from-source)
* [Submitting Patches](#submitting-patches) - [Build a standard `step-ca`](#build-a-standard-step-ca)
* [Code Contribution Guidelines](#code-contribution-guidelines) - [Build `step-ca` using CGO](#build-step-ca-using-cgo)
* [Git Commit Message Guidelines](#git-commit-message-guidelines) - [The CGO build enables PKCS #11 and YubiKey PIV support](#the-cgo-build-enables-pkcs-11-and-yubikey-piv-support)
- [1. Install PCSC support](#1-install-pcsc-support)
- [2. Build `step-ca`](#2-build-step-ca)
- [Asking Support Questions](#asking-support-questions)
- [Reporting Issues](#reporting-issues)
- [Code Contribution](#code-contribution)
- [Submitting Patches](#submitting-patches)
- [Code Contribution Guidelines](#code-contribution-guidelines)
- [Git Commit Message Guidelines](#git-commit-message-guidelines)
## Building From Source ## Building From Source
@ -73,7 +81,7 @@ When the build is complete, you will find binaries in `bin/`.
## Asking Support Questions ## Asking Support Questions
Feel free to post a question on our [GitHub Discussions](https://github.com/smallstep/certificates/discussions) page, or find us on [Gitter](https://gitter.im/smallstep/community). Feel free to post a question on our [GitHub Discussions](https://github.com/smallstep/certificates/discussions) page, or find us on [Discord](https://bit.ly/step-discord).
## Reporting Issues ## Reporting Issues

View file

@ -1,7 +1,7 @@
# Provisioners # Provisioners
> Note: The canonical documentation for `step-ca` provisioners now lives at > Note: The canonical documentation for `step-ca` provisioners now lives at
> https://smallstep.com/docs/step-ca/configuration#provisioners. Documentation > https://smallstep.com/docs/step-ca/provisioners. Documentation
> found on this page may be out of date. > found on this page may be out of date.
Provisioners are people or code that are registered with the CA and authorized Provisioners are people or code that are registered with the CA and authorized

View file

@ -202,7 +202,8 @@ through an example.
[Use TLS Everywhere](https://smallstep.com/blog/use-tls.html) and let us know [Use TLS Everywhere](https://smallstep.com/blog/use-tls.html) and let us know
what you think of our tools. Get in touch over what you think of our tools. Get in touch over
[Twitter](twitter.com/smallsteplabs) or through our [Twitter](twitter.com/smallsteplabs) or through our
[GitHub Discussions](https://github.com/smallstep/certificates/discussions) to chat with us in real time. [GitHub Discussions](https://github.com/smallstep/certificates/discussions) to find answers to frequently asked questions.
[Discord](https://bit.ly/step-discord) to chat with us in real time.
## Further Reading ## Further Reading

25
go.mod
View file

@ -7,6 +7,7 @@ require (
github.com/Masterminds/sprig/v3 v3.1.0 github.com/Masterminds/sprig/v3 v3.1.0
github.com/ThalesIgnite/crypto11 v1.2.4 github.com/ThalesIgnite/crypto11 v1.2.4
github.com/aws/aws-sdk-go v1.30.29 github.com/aws/aws-sdk-go v1.30.29
github.com/dgraph-io/ristretto v0.0.4-0.20200906165740-41ebdbffecfd // indirect
github.com/go-chi/chi v4.0.2+incompatible github.com/go-chi/chi v4.0.2+incompatible
github.com/go-kit/kit v0.10.0 // indirect github.com/go-kit/kit v0.10.0 // indirect
github.com/go-piv/piv-go v1.7.0 github.com/go-piv/piv-go v1.7.0
@ -22,27 +23,25 @@ require (
github.com/rs/xid v1.2.1 github.com/rs/xid v1.2.1
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.4.2
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262
github.com/smallstep/nosql v0.3.6 github.com/smallstep/nosql v0.3.8
github.com/stretchr/testify v1.7.0 // indirect
github.com/urfave/cli v1.22.4 github.com/urfave/cli v1.22.4
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1
go.step.sm/cli-utils v0.4.1 go.step.sm/cli-utils v0.4.1
go.step.sm/crypto v0.9.0 go.step.sm/crypto v0.9.2
go.step.sm/linkedca v0.0.0-20210611183751-27424aae8d25 go.step.sm/linkedca v0.5.0
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420 golang.org/x/net v0.0.0-20210825183410-e898025ed96a
google.golang.org/api v0.47.0 google.golang.org/api v0.47.0
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492
google.golang.org/grpc v1.38.0 google.golang.org/grpc v1.39.0
google.golang.org/protobuf v1.26.0 google.golang.org/protobuf v1.27.1
gopkg.in/square/go-jose.v2 v2.5.1 gopkg.in/square/go-jose.v2 v2.5.1
) )
// replace github.com/smallstep/nosql => ../nosql // replace github.com/smallstep/nosql => ../nosql
// replace go.step.sm/crypto => ../crypto
//replace go.step.sm/crypto => ../crypto // replace go.step.sm/cli-utils => ../cli-utils
// replace go.step.sm/linkedca => ../linkedca
//replace go.step.sm/cli-utils => ../cli-utils
//replace go.step.sm/linkedca => ../linkedca //replace go.step.sm/linkedca => ../linkedca

235
go.sum
View file

@ -42,10 +42,6 @@ github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIo
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
@ -55,77 +51,57 @@ github.com/Masterminds/sprig/v3 v3.1.0 h1:j7GpgZ7PdFqNsmncycTHsLmVPf5/3wJtlgW9TN
github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/ThalesIgnite/crypto11 v1.2.4 h1:3MebRK/U0mA2SmSthXAIZAdUA9w8+ZuKem2O6HuR1f8= github.com/ThalesIgnite/crypto11 v1.2.4 h1:3MebRK/U0mA2SmSthXAIZAdUA9w8+ZuKem2O6HuR1f8=
github.com/ThalesIgnite/crypto11 v1.2.4 h1:3MebRK/U0mA2SmSthXAIZAdUA9w8+ZuKem2O6HuR1f8= github.com/ThalesIgnite/crypto11 v1.2.4 h1:3MebRK/U0mA2SmSthXAIZAdUA9w8+ZuKem2O6HuR1f8=
github.com/ThalesIgnite/crypto11 v1.2.4/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= github.com/ThalesIgnite/crypto11 v1.2.4/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE=
github.com/ThalesIgnite/crypto11 v1.2.4/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= github.com/ThalesIgnite/crypto11 v1.2.4/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE=
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0 h1:5hryIiq9gtn+MiLVn0wP37kb/uTeRZgN08WoCsAhIhI=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a h1:pv34s756C4pEXnjgPfGYgdhg/ZdajGhyOvzx8k+23nw=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-lambda-go v1.13.3 h1:SuCy7H3NLyp+1Mrfp+m80jcbi9KYWAs9/BXwppwRDzY=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.30.29 h1:NXNqBS9hjOCpDL8SyCyl38gZX3LLLunKOJc5E7vJ8P0= github.com/aws/aws-sdk-go v1.30.29 h1:NXNqBS9hjOCpDL8SyCyl38gZX3LLLunKOJc5E7vJ8P0=
github.com/aws/aws-sdk-go v1.30.29/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.30.29/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go-v2 v0.18.0 h1:qZ+woO4SamnH/eEbjM2IDLhRNwIwND/RQyVlBLp3Jqg=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/casbin/casbin/v2 v2.1.2 h1:bTwon/ECRx9dwBy2ewRVr5OiqjeXSGiTUY74sDPQi/g=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@ -133,44 +109,36 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5O
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec h1:EdRZT3IeKQmfCSrgo8SZ8V3MEnskuJP0wCYNpe+aiXo=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf h1:CAKfRE2YtTUIjjh1bkBtyYFaUT/WmOqsJjgtihT0vMI=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8=
github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20201003150343-5d1bab4fc658 h1:/WBjuutuivOA02gpDtrvrWKw01ugkyt3QnimB7enbtI= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20201003150343-5d1bab4fc658/go.mod h1:2uGEvGm+JSDLd5UAaKIFSbXDcYyeH0fWJP4N2HMMYMI= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.4-0.20200906165740-41ebdbffecfd h1:KoJOtZf+6wpQaDTuOWGuo61GxcPBIfhwRxRTaTWGCTc= github.com/dgraph-io/ristretto v0.0.4-0.20200906165740-41ebdbffecfd h1:KoJOtZf+6wpQaDTuOWGuo61GxcPBIfhwRxRTaTWGCTc=
github.com/dgraph-io/ristretto v0.0.4-0.20200906165740-41ebdbffecfd/go.mod h1:YylP9MpCYGVZQrly/j/diqcdUetCRRePeBB0c2VGXsA= github.com/dgraph-io/ristretto v0.0.4-0.20200906165740-41ebdbffecfd/go.mod h1:YylP9MpCYGVZQrly/j/diqcdUetCRRePeBB0c2VGXsA=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
@ -178,13 +146,9 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@ -192,32 +156,24 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d h1:QyzYnTnPE15SQyUeqU6qLbWxMkwyAyu+vGksa0b7j00=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db h1:gb2Z18BhTPJPpLQWj4T+rfKHYCHxRHCtRxhKKjRidVw=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8 h1:a9ENSRDFBUPkJ5lCgVZh26+ZbGyoVJG7yb5SSzF5H54=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs= github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.4.0 h1:KeVK+Emj3c3S4eRztFuzbFYb2BAgf2jmwDwyXEri7Lo=
github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
@ -227,17 +183,13 @@ github.com/go-piv/piv-go v1.7.0/go.mod h1:ON2WvQncm7dIkCQ7kYJs+nc3V4jHGfrrJnSF8H
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.6.0 h1:MmJCxYVKTJ0SplGKqFVX3SBnmaUhODHZrrFF6jMbpZk=
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -267,14 +219,11 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -289,13 +238,10 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -320,101 +266,69 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.4.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.4.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c h1:Lh2aW+HnU2Nbe1gqD9SOJLJxW1jBMmQOktN2acDyJk8=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda h1:5ikpG9mYCMFiZX0nkxoV6aU2IpCHPdws3gCNgdZeEV0=
github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda/go.mod h1:MyndkAZd5rUMdNogn35MWXBX1UiBigrU8eTj8DoAC2c= github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda/go.mod h1:MyndkAZd5rUMdNogn35MWXBX1UiBigrU8eTj8DoAC2c=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.3.0 h1:HXNYlRkkM/t+Y/Yhxtwcy02dlYwIaoxzvxPnS+cqy78= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0 h1:UOxjlb4xVNF93jak1mzzoBatyFju9nrkxpVwIp/QqxQ=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0 h1:WhIgCr5a7AaVH6jPUwjtRuuE7/RDufnUvzIr48smyxs=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hudl/fargo v1.3.0 h1:0U6+BtN6LhaYuTnIJq4Wyq5cpn6O2kWrxAtcqBmYY6w=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d h1:/WZQPMZNsjZ7IlCpsLGdQBINg5bxKQ1K1sh6awxLtkA=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0 h1:ZqfnKyx9KGpRcW04j5nnPDgRgoXUeLh2YFBeFzphcA0=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 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 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
@ -422,16 +336,12 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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 h1:143Bb8f8DuGWck/xpNUOckBVYfFbBTnLevfRZ1aVVqo=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= 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 h1:vi1F1IQ8N7hNWytK9DpJsUfQhGuNSc19z330K6vl4zk=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lyft/protoc-gen-validate v0.0.13 h1:KNt/RhmQTOLr7Aj8PsJ7mTronaFyx80mRTT9qF261dA=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 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 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo=
github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
@ -446,132 +356,90 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/micromdm/scep/v2 v2.0.0 h1:cRzcY0S5QX+0+J+7YC4P2uZSnfMup8S8zJu/bLFgOkA= github.com/micromdm/scep/v2 v2.0.0 h1:cRzcY0S5QX+0+J+7YC4P2uZSnfMup8S8zJu/bLFgOkA=
github.com/micromdm/scep/v2 v2.0.0/go.mod h1:ouaDs5tcjOjdHD/h8BGaQsWE87MUnQ/wMTMgfMMIpPc= github.com/micromdm/scep/v2 v2.0.0/go.mod h1:ouaDs5tcjOjdHD/h8BGaQsWE87MUnQ/wMTMgfMMIpPc=
github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f h1:eVB9ELsoq5ouItQBr5Tj334bhPJG/MX+m7rTchmzVUQ= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f h1:eVB9ELsoq5ouItQBr5Tj334bhPJG/MX+m7rTchmzVUQ=
github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2 h1:i2Ly0B+1+rzNZHHWtD4ZwKi+OU5l+uQo1iDHZ2PmiIc=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/newrelic/go-agent v2.15.0+incompatible h1:IB0Fy+dClpBq9aEoIrLyQXzU34JyI1xVTanPLB/+jvU= github.com/newrelic/go-agent v2.15.0+incompatible h1:IB0Fy+dClpBq9aEoIrLyQXzU34JyI1xVTanPLB/+jvU=
github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ= github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ=
github.com/oklog/oklog v0.3.2 h1:wVfs8F+in6nTBMkA7CbRw+zZMIB7nNM825cM1wuzoTk=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5 h1:58+kh9C6jJVXYjt8IE48G2eWl6BjwU5Gj0gqY84fy78=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568 h1:+MPqEswjYiS0S1FCTg8MIhMBMzxiVQ94rooFwvPPiWk= github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568 h1:+MPqEswjYiS0S1FCTg8MIhMBMzxiVQ94rooFwvPPiWk=
github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5 h1:ZCnq+JUrvXcDVhX/xRolRBZifmabN1HcS1wrPSvxhrU=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2 h1:nY8Hti+WKaP0cRsSeQ026wU03QsM762XBeCXBb9NAWI=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4 h1:OYkFijGHoZAYbOIb1LWXrwKQbMMRUv1oQ89blD2Mh2Q=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/performancecopilot/speed v3.0.0+incompatible h1:2WnRzIquHa5QxaJKShDkLM+sc0JPuwhXzK8OYOyt3Vg=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1 h1:F++O52m40owAmADcojzM+9gyjmMOY/T4oYJkgFDH8RE=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0 h1:ElTg5tNp4DqfV7UQjDqv2+RJlNzsDtvNAWccbItceIE=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af h1:gu+uRPtBe88sKxUCEXRoeCvVG90TJmwhiqRpvdhQFng=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@ -579,13 +447,10 @@ github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNue
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f h1:UFr9zpz4xgTnIE5yIMtWAMngCdZ9p/+q6lTbgelo80M=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189 h1:CmSpbxmewNQbzqztaY0bke1qzHhyNyC29wYgh17Gxfo= github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189 h1:CmSpbxmewNQbzqztaY0bke1qzHhyNyC29wYgh17Gxfo=
github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189/go.mod h1:UUwuHEJ9zkkPDxspIHOa59PUeSkGFljESGzbxntLmIg= github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189/go.mod h1:UUwuHEJ9zkkPDxspIHOa59PUeSkGFljESGzbxntLmIg=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da h1:p3Vo3i64TCLY7gIfzeQaUJ+kppEO5WQG3cL8iE8tGHU=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@ -595,15 +460,11 @@ 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-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 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/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
github.com/smallstep/nosql v0.3.6 h1:cq6a3NwjFJxkVlWU1T4qGskcfEXr0fO1WqQrraDO1Po= github.com/smallstep/nosql v0.3.8 h1:1/EWUbbEdz9ai0g9Fd09VekVjtxp+5+gIHpV2PdwW3o=
github.com/smallstep/nosql v0.3.6/go.mod h1:h1zC/Z54uNHc8euquLED4qJNCrMHd3nytA141ZZh4qQ= github.com/smallstep/nosql v0.3.8/go.mod h1:X2qkYpNcW3yjLUvhEHfgGfClpKbFPapewvx7zo4TOFs=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1 h1:oMnRNZXX5j85zso6xCPRNPtmAycat+WcoKbklScLDgQ=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
@ -613,17 +474,13 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a h1:AhmOdSHeswKHBjhsLs/7+1voOxT+LLrSk/Nxvk35fug=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -631,23 +488,18 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -657,7 +509,6 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@ -669,31 +520,20 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 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 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.step.sm/cli-utils v0.2.0 h1:hpVu9+6dpv/7/Bd8nGJFc3V+gQ+TciSJRTu9TavDUQ4= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.step.sm/cli-utils v0.2.0/go.mod h1:+t4qCp5NO+080DdGkJxEh3xL5S4TcYC2JTPLMM72b6Y=
go.step.sm/cli-utils v0.4.0 h1:dni6gR/6/LOqfbzm/yUdgz5O12tkxX17SxA9+pRMidI=
go.step.sm/cli-utils v0.4.0/go.mod h1:1zFgatDqEJ1Y4MNStdWa0b1NPc1fvSHbDJC+wZ6iQlE=
go.step.sm/cli-utils v0.4.1 h1:QztRUhGYjOPM1I2Nmi7V6XejQyVtcESmo+sbegxvX7Q= go.step.sm/cli-utils v0.4.1 h1:QztRUhGYjOPM1I2Nmi7V6XejQyVtcESmo+sbegxvX7Q=
go.step.sm/cli-utils v0.4.1/go.mod h1:hWYVOSlw8W9Pd+BwIbs/aftVVMRms3EG7Q2qLRwc0WA= go.step.sm/cli-utils v0.4.1/go.mod h1:hWYVOSlw8W9Pd+BwIbs/aftVVMRms3EG7Q2qLRwc0WA=
go.step.sm/crypto v0.6.1/go.mod h1:AKS4yMZVZD4EGjpSkY4eibuMenrvKCscb+BpWMet8c0=
go.step.sm/crypto v0.8.3 h1:TO/OPlaUrYXhs8srGEFNyL6OWVQvRmEPCUONNnQUuEM=
go.step.sm/crypto v0.8.3/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
go.step.sm/crypto v0.9.0 h1:q2AllTSnVj4NRtyEPkGW2ohArLmbGbe6ZAL/VIOKDzA=
go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0= go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
go.step.sm/linkedca v0.0.0-20210610014030-59b16916c7e7 h1:hAfzUm80XWGtFnxyVgeT/gc/3XnlVNnHD5HrLbk4Fc0= go.step.sm/crypto v0.9.2 h1:UvQHE4brjAOdgcK2ob6zupL1iRzDd8+QiEvPOeQrm4E=
go.step.sm/linkedca v0.0.0-20210610014030-59b16916c7e7/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= go.step.sm/crypto v0.9.2/go.mod h1:F5OJyPDWntNa1SbuWPxuHJc9bLzu84NzYrrdzDuBugk=
go.step.sm/linkedca v0.0.0-20210611183751-27424aae8d25 h1:ncJqviWswJT19IdnfOYQGKG1zL7IDy4lAJz1PuM3fgw= go.step.sm/linkedca v0.5.0 h1:oZVRSpElM7lAL1XN2YkjdHwI/oIZ+1ULOnuqYPM6xjY=
go.step.sm/linkedca v0.0.0-20210611183751-27424aae8d25/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= go.step.sm/linkedca v0.5.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -706,8 +546,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -786,10 +626,9 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420 h1:a8jGStKg0XqKDlKqjLrXn0ioF5MH36pT7Z0BRTqLhbk=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -870,10 +709,9 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -943,6 +781,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1005,6 +844,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
@ -1022,10 +862,9 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d h1:KzwjikDymrEmYYbdyfievTwjEeGlu+OM6oiKBkF3Jfg= google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492 h1:7yQQsvnwjfEahbNNEKcBHv3mR+HnB1ctGY/z1JXzx8M=
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -1044,6 +883,7 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
@ -1051,8 +891,9 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -1065,33 +906,27 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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 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-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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25 h1:Ev7yu1/f6+d+b3pi5vPdRPc6nNtP1umSfcWiEfRqv6I=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
@ -1107,7 +942,5 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0 h1:ucqkfpjg9WzSUubAO62csmucvxl4/JeW3F4I4909XkM=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

View file

@ -46,8 +46,8 @@ var signatureAlgorithmMapping = map[apiv1.SignatureAlgorithm]interface{}{
4096: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256, 4096: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256,
}, },
apiv1.SHA512WithRSA: map[int]kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm{ apiv1.SHA512WithRSA: map[int]kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm{
0: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256, 0: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512,
4096: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256, 4096: kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512,
}, },
apiv1.SHA256WithRSAPSS: map[int]kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm{ apiv1.SHA256WithRSAPSS: map[int]kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm{
0: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256, 0: kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256,

View file

@ -59,7 +59,9 @@ func Parse(rawuri string) (*URI, error) {
if u.Scheme == "" { if u.Scheme == "" {
return nil, errors.Errorf("error parsing %s: scheme is missing", rawuri) return nil, errors.Errorf("error parsing %s: scheme is missing", rawuri)
} }
v, err := url.ParseQuery(u.Opaque) // Starting with Go 1.17 url.ParseQuery returns an error using semicolon as
// separator.
v, err := url.ParseQuery(strings.ReplaceAll(u.Opaque, ";", "&"))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error parsing %s", rawuri) return nil, errors.Wrapf(err, "error parsing %s", rawuri)
} }

View file

@ -274,3 +274,28 @@ func TestURI_Pin(t *testing.T) {
}) })
} }
} }
func TestURI_String(t *testing.T) {
mustParse := func(s string) *URI {
u, err := Parse(s)
if err != nil {
t.Fatal(err)
}
return u
}
tests := []struct {
name string
uri *URI
want string
}{
{"ok new", New("yubikey", url.Values{"slot-id": []string{"9a"}, "foo": []string{"bar"}}), "yubikey:foo=bar;slot-id=9a"},
{"ok parse", mustParse("yubikey:slot-id=9a;foo=bar?bar=zar"), "yubikey:slot-id=9a;foo=bar?bar=zar"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.uri.String(); got != tt.want {
t.Errorf("URI.String() = %v, want %v", got, tt.want)
}
})
}
}

153
pki/helm.go Normal file
View file

@ -0,0 +1,153 @@
package pki
import (
"io"
"text/template"
"github.com/Masterminds/sprig/v3"
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority"
authconfig "github.com/smallstep/certificates/authority/config"
"github.com/smallstep/certificates/authority/provisioner"
"go.step.sm/linkedca"
)
type helmVariables struct {
*linkedca.Configuration
Defaults *linkedca.Defaults
Password string
EnableSSH bool
TLS authconfig.TLSOptions
Provisioners []provisioner.Interface
}
func (p *PKI) WriteHelmTemplate(w io.Writer) error {
tmpl, err := template.New("helm").Funcs(sprig.TxtFuncMap()).Parse(helmTemplate)
if err != nil {
return errors.Wrap(err, "error writing helm template")
}
// Delete ssh section if it is not enabled
if !p.options.enableSSH {
p.Ssh = nil
}
// Convert provisioner to ca.json
provisioners := make([]provisioner.Interface, len(p.Authority.Provisioners))
for i, p := range p.Authority.Provisioners {
pp, err := authority.ProvisionerToCertificates(p)
if err != nil {
return err
}
provisioners[i] = pp
}
if err := tmpl.Execute(w, helmVariables{
Configuration: &p.Configuration,
Defaults: &p.Defaults,
Password: "",
EnableSSH: p.options.enableSSH,
TLS: authconfig.DefaultTLSOptions,
Provisioners: provisioners,
}); err != nil {
return errors.Wrap(err, "error executing helm template")
}
return nil
}
const helmTemplate = `# Helm template
inject:
enabled: true
# Config contains the configuration files ca.json and defaults.json
config:
files:
ca.json:
root: {{ first .Root }}
federateRoots: []
crt: {{ .Intermediate }}
key: {{ .IntermediateKey }}
{{- if .EnableSSH }}
ssh:
hostKey: {{ .Ssh.HostKey }}
userKey: {{ .Ssh.UserKey }}
{{- end }}
address: {{ .Address }}
dnsNames:
{{- range .DnsNames }}
- {{ . }}
{{- end }}
logger:
format: json
db:
type: badger
dataSource: /home/step/db
authority:
provisioners:
{{- range .Provisioners }}
- {{ . | toJson }}
{{- end }}
tls:
cipherSuites:
{{- range .TLS.CipherSuites }}
- {{ . }}
{{- end }}
minVersion: {{ .TLS.MinVersion }}
maxVersion: {{ .TLS.MaxVersion }}
renegotiation: {{ .TLS.Renegotiation }}
defaults.json:
ca-url: {{ .Defaults.CaUrl }}
ca-config: {{ .Defaults.CaConfig }}
fingerprint: {{ .Defaults.Fingerprint }}
root: {{ .Defaults.Root }}
# Certificates contains the root and intermediate certificate and
# optionally the SSH host and user public keys
certificates:
# intermediate_ca contains the text of the intermediate CA Certificate
intermediate_ca: |
{{- index .Files .Intermediate | toString | nindent 6 }}
# root_ca contains the text of the root CA Certificate
root_ca: |
{{- first .Root | index .Files | toString | nindent 6 }}
{{- if .Ssh }}
# ssh_host_ca contains the text of the public ssh key for the SSH root CA
ssh_host_ca: {{ index .Files .Ssh.HostPublicKey | toString }}
# ssh_user_ca contains the text of the public ssh key for the SSH root CA
ssh_user_ca: {{ index .Files .Ssh.UserPublicKey | toString }}
{{- end }}
# Secrets contains the root and intermediate keys and optionally the SSH
# private keys
secrets:
# ca_password contains the password used to encrypt x509.intermediate_ca_key, ssh.host_ca_key and ssh.user_ca_key
# This value must be base64 encoded.
ca_password: {{ .Password | b64enc }}
provisioner_password: {{ .Password | b64enc}}
x509:
# intermediate_ca_key contains the contents of your encrypted intermediate CA key
intermediate_ca_key: |
{{- index .Files .IntermediateKey | toString | nindent 8 }}
# root_ca_key contains the contents of your encrypted root CA key
# Note that this value can be omitted without impacting the functionality of step-certificates
# If supplied, this should be encrypted using a unique password that is not used for encrypting
# the intermediate_ca_key, ssh.host_ca_key or ssh.user_ca_key.
root_ca_key: |
{{- first .RootKey | index .Files | toString | nindent 8 }}
{{- if .Ssh }}
ssh:
# ssh_host_ca_key contains the contents of your encrypted SSH Host CA key
host_ca_key: |
{{- index .Files .Ssh.HostKey | toString | nindent 8 }}
# ssh_user_ca_key contains the contents of your encrypted SSH User CA key
user_ca_key: |
{{- index .Files .Ssh.UserKey | toString | nindent 8 }}
{{- end }}
`

View file

@ -10,21 +10,23 @@ import (
"encoding/json" "encoding/json"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"html"
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority"
"github.com/smallstep/certificates/authority/admin"
admindb "github.com/smallstep/certificates/authority/admin/db/nosql"
authconfig "github.com/smallstep/certificates/authority/config" authconfig "github.com/smallstep/certificates/authority/config"
"github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/ca" "github.com/smallstep/certificates/ca"
"github.com/smallstep/certificates/cas" "github.com/smallstep/certificates/cas"
"github.com/smallstep/certificates/cas/apiv1" "github.com/smallstep/certificates/cas/apiv1"
"github.com/smallstep/certificates/db" "github.com/smallstep/certificates/db"
"github.com/smallstep/nosql"
"go.step.sm/cli-utils/config" "go.step.sm/cli-utils/config"
"go.step.sm/cli-utils/errs" "go.step.sm/cli-utils/errs"
"go.step.sm/cli-utils/fileutil" "go.step.sm/cli-utils/fileutil"
@ -32,9 +34,40 @@ import (
"go.step.sm/crypto/jose" "go.step.sm/crypto/jose"
"go.step.sm/crypto/keyutil" "go.step.sm/crypto/keyutil"
"go.step.sm/crypto/pemutil" "go.step.sm/crypto/pemutil"
"go.step.sm/linkedca"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
// DeploymentType defines witch type of deployment a user is initializing
type DeploymentType int
const (
// StandaloneDeployment is a deployment where all the components like keys,
// provisioners, admins, certificates and others are managed by the user.
StandaloneDeployment DeploymentType = iota
// LinkedDeployment is a deployment where the keys are managed by the user,
// but provisioners, admins and the record of certificates are managed in
// the cloud.
LinkedDeployment
// HostedDeployment is a deployment where all the components are managed in
// the cloud by smallstep.com/certificate-manager.
HostedDeployment
)
// String returns the string version of the deployment type.
func (d DeploymentType) String() string {
switch d {
case StandaloneDeployment:
return "standalone"
case LinkedDeployment:
return "linked"
case HostedDeployment:
return "hosted"
default:
return "unknown"
}
}
const ( const (
// ConfigPath is the directory name under the step path where the configuration // ConfigPath is the directory name under the step path where the configuration
// files will be stored. // files will be stored.
@ -134,43 +167,125 @@ func GetProvisionerKey(caURL, rootFile, kid string) (string, error) {
return resp.Key, nil return resp.Key, nil
} }
type options struct {
provisioner string
pkiOnly bool
enableACME bool
enableSSH bool
enableAdmin bool
noDB bool
isHelm bool
deploymentType DeploymentType
}
// Option is the type of a configuration option on the pki constructor.
type Option func(p *PKI)
// WithAddress sets the listen address of step-ca.
func WithAddress(s string) Option {
return func(p *PKI) {
p.Address = s
}
}
// WithCaURL sets the default ca-url of step-ca.
func WithCaURL(s string) Option {
return func(p *PKI) {
p.Defaults.CaUrl = s
}
}
// WithDNSNames sets the SANs of step-ca.
func WithDNSNames(s []string) Option {
return func(p *PKI) {
p.DnsNames = s
}
}
// WithProvisioner defines the name of the default provisioner.
func WithProvisioner(s string) Option {
return func(p *PKI) {
p.options.provisioner = s
}
}
// WithPKIOnly will only generate the PKI without the step-ca config files.
func WithPKIOnly() Option {
return func(p *PKI) {
p.options.pkiOnly = true
}
}
// WithACME enables acme provisioner in step-ca.
func WithACME() Option {
return func(p *PKI) {
p.options.enableACME = true
}
}
// WithSSH enables ssh in step-ca.
func WithSSH() Option {
return func(p *PKI) {
p.options.enableSSH = true
}
}
// WithAdmin enables the admin api in step-ca.
func WithAdmin() Option {
return func(p *PKI) {
p.options.enableAdmin = true
}
}
// WithNoDB disables the db in step-ca.
func WithNoDB() Option {
return func(p *PKI) {
p.options.noDB = true
}
}
// WithHelm configures the pki to create a helm values.yaml.
func WithHelm() Option {
return func(p *PKI) {
p.options.isHelm = true
}
}
// WithDeploymentType defines the deployment type of step-ca.
func WithDeploymentType(dt DeploymentType) Option {
return func(p *PKI) {
p.options.deploymentType = dt
}
}
// PKI represents the Public Key Infrastructure used by a certificate authority. // PKI represents the Public Key Infrastructure used by a certificate authority.
type PKI struct { type PKI struct {
casOptions apiv1.Options linkedca.Configuration
caCreator apiv1.CertificateAuthorityCreator Defaults linkedca.Defaults
root, rootKey, rootFingerprint string casOptions apiv1.Options
intermediate, intermediateKey string caService apiv1.CertificateAuthorityService
sshHostPubKey, sshHostKey string caCreator apiv1.CertificateAuthorityCreator
sshUserPubKey, sshUserKey string config string
config, defaults string defaults string
ottPublicKey *jose.JSONWebKey ottPublicKey *jose.JSONWebKey
ottPrivateKey *jose.JSONWebEncryption ottPrivateKey *jose.JSONWebEncryption
provisioner string options *options
address string
dnsNames []string
caURL string
enableSSH bool
} }
// New creates a new PKI configuration. // New creates a new PKI configuration.
func New(opts apiv1.Options) (*PKI, error) { func New(o apiv1.Options, opts ...Option) (*PKI, error) {
caCreator, err := cas.NewCreator(context.Background(), opts) caService, err := cas.New(context.Background(), o)
if err != nil { if err != nil {
return nil, err return nil, err
} }
public := GetPublicPath() var caCreator apiv1.CertificateAuthorityCreator
private := GetSecretsPath() if o.IsCreator {
config := GetConfigPath() creator, ok := caService.(apiv1.CertificateAuthorityCreator)
if !ok {
// Create directories return nil, errors.Errorf("cas type '%s' does not implements CertificateAuthorityCreator", o.Type)
dirs := []string{public, private, config, GetTemplatesPath()}
for _, name := range dirs {
if _, err := os.Stat(name); os.IsNotExist(err) {
if err = os.MkdirAll(name, 0700); err != nil {
return nil, errs.FileError(err, name)
}
} }
caCreator = creator
} }
// get absolute path for dir/name // get absolute path for dir/name
@ -180,45 +295,97 @@ func New(opts apiv1.Options) (*PKI, error) {
} }
p := &PKI{ p := &PKI{
casOptions: opts, Configuration: linkedca.Configuration{
caCreator: caCreator, Address: "127.0.0.1:9000",
provisioner: "step-cli", DnsNames: []string{"127.0.0.1"},
address: "127.0.0.1:9000", Ssh: &linkedca.SSH{},
dnsNames: []string{"127.0.0.1"}, Authority: &linkedca.Authority{},
Files: make(map[string][]byte),
},
casOptions: o,
caCreator: caCreator,
caService: caService,
options: &options{
provisioner: "step-cli",
},
} }
if p.root, err = getPath(public, "root_ca.crt"); err != nil { for _, fn := range opts {
return nil, err fn(p)
} }
if p.rootKey, err = getPath(private, "root_ca_key"); err != nil {
return nil, err // Use /home/step as the step path in helm configurations.
} // Use the current step path when creating pki in files.
if p.intermediate, err = getPath(public, "intermediate_ca.crt"); err != nil { var public, private, config string
return nil, err if p.options.isHelm {
} public = "/home/step/certs"
if p.intermediateKey, err = getPath(private, "intermediate_ca_key"); err != nil { private = "/home/step/secrets"
return nil, err config = "/home/step/config"
} } else {
if p.sshHostPubKey, err = getPath(public, "ssh_host_ca_key.pub"); err != nil { public = GetPublicPath()
return nil, err private = GetSecretsPath()
} config = GetConfigPath()
if p.sshUserPubKey, err = getPath(public, "ssh_user_ca_key.pub"); err != nil { // Create directories
return nil, err dirs := []string{public, private, config, GetTemplatesPath()}
} for _, name := range dirs {
if p.sshHostKey, err = getPath(private, "ssh_host_ca_key"); err != nil { if _, err := os.Stat(name); os.IsNotExist(err) {
return nil, err if err = os.MkdirAll(name, 0700); err != nil {
} return nil, errs.FileError(err, name)
if p.sshUserKey, err = getPath(private, "ssh_user_ca_key"); err != nil { }
return nil, err }
}
if len(config) > 0 {
if p.config, err = getPath(config, "ca.json"); err != nil {
return nil, err
}
if p.defaults, err = getPath(config, "defaults.json"); err != nil {
return nil, err
} }
} }
if p.Defaults.CaUrl == "" {
p.Defaults.CaUrl = p.DnsNames[0]
_, port, err := net.SplitHostPort(p.Address)
if err != nil {
return nil, errors.Wrapf(err, "error parsing %s", p.Address)
}
if port == "443" {
p.Defaults.CaUrl = fmt.Sprintf("https://%s", p.Defaults.CaUrl)
} else {
p.Defaults.CaUrl = fmt.Sprintf("https://%s:%s", p.Defaults.CaUrl, port)
}
}
root, err := getPath(public, "root_ca.crt")
if err != nil {
return nil, err
}
rootKey, err := getPath(private, "root_ca_key")
if err != nil {
return nil, err
}
p.Root = []string{root}
p.RootKey = []string{rootKey}
p.Defaults.Root = root
if p.Intermediate, err = getPath(public, "intermediate_ca.crt"); err != nil {
return nil, err
}
if p.IntermediateKey, err = getPath(private, "intermediate_ca_key"); err != nil {
return nil, err
}
if p.Ssh.HostPublicKey, err = getPath(public, "ssh_host_ca_key.pub"); err != nil {
return nil, err
}
if p.Ssh.UserPublicKey, err = getPath(public, "ssh_user_ca_key.pub"); err != nil {
return nil, err
}
if p.Ssh.HostKey, err = getPath(private, "ssh_host_ca_key"); err != nil {
return nil, err
}
if p.Ssh.UserKey, err = getPath(private, "ssh_user_ca_key"); err != nil {
return nil, err
}
if p.defaults, err = getPath(config, "defaults.json"); err != nil {
return nil, err
}
if p.config, err = getPath(config, "ca.json"); err != nil {
return nil, err
}
p.Defaults.CaConfig = p.config
return p, nil return p, nil
} }
@ -229,27 +396,7 @@ func (p *PKI) GetCAConfigPath() string {
// GetRootFingerprint returns the root fingerprint. // GetRootFingerprint returns the root fingerprint.
func (p *PKI) GetRootFingerprint() string { func (p *PKI) GetRootFingerprint() string {
return p.rootFingerprint return p.Defaults.Fingerprint
}
// SetProvisioner sets the provisioner name of the OTT keys.
func (p *PKI) SetProvisioner(s string) {
p.provisioner = s
}
// SetAddress sets the listening address of the CA.
func (p *PKI) SetAddress(s string) {
p.address = s
}
// SetDNSNames sets the dns names of the CA.
func (p *PKI) SetDNSNames(s []string) {
p.dnsNames = s
}
// SetCAURL sets the ca-url to use in the defaults.json.
func (p *PKI) SetCAURL(s string) {
p.caURL = s
} }
// GenerateKeyPairs generates the key pairs used by the certificate authority. // GenerateKeyPairs generates the key pairs used by the certificate authority.
@ -261,6 +408,38 @@ func (p *PKI) GenerateKeyPairs(pass []byte) error {
return err return err
} }
var claims *linkedca.Claims
if p.options.enableSSH {
claims = &linkedca.Claims{
Ssh: &linkedca.SSHClaims{
Enabled: true,
},
}
}
// Add JWK provisioner to the configuration.
publicKey, err := json.Marshal(p.ottPublicKey)
if err != nil {
return errors.Wrap(err, "error marshaling public key")
}
encryptedKey, err := p.ottPrivateKey.CompactSerialize()
if err != nil {
return errors.Wrap(err, "error serializing private key")
}
p.Authority.Provisioners = append(p.Authority.Provisioners, &linkedca.Provisioner{
Type: linkedca.Provisioner_JWK,
Name: p.options.provisioner,
Claims: claims,
Details: &linkedca.ProvisionerDetails{
Data: &linkedca.ProvisionerDetails_JWK{
JWK: &linkedca.JWKProvisioner{
PublicKey: publicKey,
EncryptedPrivateKey: []byte(encryptedKey),
},
},
},
})
return nil return nil
} }
@ -296,6 +475,21 @@ func (p *PKI) GenerateRootCertificate(name, org, resource string, pass []byte) (
return resp, nil return resp, nil
} }
// WriteRootCertificate writes to the buffer the given certificate and key if given.
func (p *PKI) WriteRootCertificate(rootCrt *x509.Certificate, rootKey interface{}, pass []byte) error {
p.Files[p.Root[0]] = encodeCertificate(rootCrt)
if rootKey != nil {
var err error
p.Files[p.RootKey[0]], err = encodePrivateKey(rootKey, pass)
if err != nil {
return err
}
}
sum := sha256.Sum256(rootCrt.Raw)
p.Defaults.Fingerprint = strings.ToLower(hex.EncodeToString(sum[:]))
return nil
}
// GenerateIntermediateCertificate generates an intermediate certificate with // GenerateIntermediateCertificate generates an intermediate certificate with
// the given name and using the default key type. // the given name and using the default key type.
func (p *PKI) GenerateIntermediateCertificate(name, org, resource string, parent *apiv1.CreateCertificateAuthorityResponse, pass []byte) error { func (p *PKI) GenerateIntermediateCertificate(name, org, resource string, parent *apiv1.CreateCertificateAuthorityResponse, pass []byte) error {
@ -322,46 +516,9 @@ func (p *PKI) GenerateIntermediateCertificate(name, org, resource string, parent
} }
p.casOptions.CertificateAuthority = resp.Name p.casOptions.CertificateAuthority = resp.Name
return p.WriteIntermediateCertificate(resp.Certificate, resp.PrivateKey, pass) p.Files[p.Intermediate] = encodeCertificate(resp.Certificate)
} p.Files[p.IntermediateKey], err = encodePrivateKey(resp.PrivateKey, pass)
return err
// WriteRootCertificate writes to disk the given certificate and key.
func (p *PKI) WriteRootCertificate(rootCrt *x509.Certificate, rootKey interface{}, pass []byte) error {
if err := fileutil.WriteFile(p.root, pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: rootCrt.Raw,
}), 0600); err != nil {
return err
}
if rootKey != nil {
_, err := pemutil.Serialize(rootKey, pemutil.WithPassword(pass), pemutil.ToFile(p.rootKey, 0600))
if err != nil {
return err
}
}
sum := sha256.Sum256(rootCrt.Raw)
p.rootFingerprint = strings.ToLower(hex.EncodeToString(sum[:]))
return nil
}
// WriteIntermediateCertificate writes to disk the given certificate and key.
func (p *PKI) WriteIntermediateCertificate(crt *x509.Certificate, key interface{}, pass []byte) error {
if err := fileutil.WriteFile(p.intermediate, pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: crt.Raw,
}), 0600); err != nil {
return err
}
if key != nil {
_, err := pemutil.Serialize(key, pemutil.WithPassword(pass), pemutil.ToFile(p.intermediateKey, 0600))
if err != nil {
return err
}
}
return nil
} }
// CreateCertificateAuthorityResponse returns a // CreateCertificateAuthorityResponse returns a
@ -379,7 +536,7 @@ func (p *PKI) CreateCertificateAuthorityResponse(cert *x509.Certificate, key cry
// GetCertificateAuthority attempts to load the certificate authority from the // GetCertificateAuthority attempts to load the certificate authority from the
// RA. // RA.
func (p *PKI) GetCertificateAuthority() error { func (p *PKI) GetCertificateAuthority() error {
srv, ok := p.caCreator.(apiv1.CertificateAuthorityGetter) srv, ok := p.caService.(apiv1.CertificateAuthorityGetter)
if !ok { if !ok {
return nil return nil
} }
@ -396,8 +553,8 @@ func (p *PKI) GetCertificateAuthority() error {
} }
// Issuer is in the RA // Issuer is in the RA
p.intermediate = "" p.Intermediate = ""
p.intermediateKey = "" p.IntermediateKey = ""
return nil return nil
} }
@ -405,8 +562,8 @@ func (p *PKI) GetCertificateAuthority() error {
// GenerateSSHSigningKeys generates and encrypts a private key used for signing // GenerateSSHSigningKeys generates and encrypts a private key used for signing
// SSH user certificates and a private key used for signing host certificates. // SSH user certificates and a private key used for signing host certificates.
func (p *PKI) GenerateSSHSigningKeys(password []byte) error { func (p *PKI) GenerateSSHSigningKeys(password []byte) error {
var pubNames = []string{p.sshHostPubKey, p.sshUserPubKey} var pubNames = []string{p.Ssh.HostPublicKey, p.Ssh.UserPublicKey}
var privNames = []string{p.sshHostKey, p.sshUserKey} var privNames = []string{p.Ssh.HostKey, p.Ssh.UserKey}
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
pub, priv, err := keyutil.GenerateDefaultKeyPair() pub, priv, err := keyutil.GenerateDefaultKeyPair()
if err != nil { if err != nil {
@ -419,57 +576,65 @@ func (p *PKI) GenerateSSHSigningKeys(password []byte) error {
if err != nil { if err != nil {
return errors.Wrapf(err, "error converting public key") return errors.Wrapf(err, "error converting public key")
} }
_, err = pemutil.Serialize(priv, pemutil.WithFilename(privNames[i]), pemutil.WithPassword(password)) p.Files[pubNames[i]] = ssh.MarshalAuthorizedKey(sshKey)
p.Files[privNames[i]], err = encodePrivateKey(priv, password)
if err != nil { if err != nil {
return err return err
} }
if err = fileutil.WriteFile(pubNames[i], ssh.MarshalAuthorizedKey(sshKey), 0600); err != nil { }
p.options.enableSSH = true
return nil
}
// WriteFiles writes on disk the previously generated files.
func (p *PKI) WriteFiles() error {
for fn, b := range p.Files {
if err := fileutil.WriteFile(fn, b, 0600); err != nil {
return err return err
} }
} }
p.enableSSH = true
return nil return nil
} }
func (p *PKI) askFeedback() { func (p *PKI) askFeedback() {
ui.Println() ui.Println()
ui.Printf("\033[1mFEEDBACK\033[0m %s %s\n", ui.Println("\033[1mFEEDBACK\033[0m 😍 🍻")
html.UnescapeString("&#"+strconv.Itoa(128525)+";"), ui.Println(" The \033[1mstep\033[0m utility is not instrumented for usage statistics. It does not phone")
html.UnescapeString("&#"+strconv.Itoa(127867)+";")) ui.Println(" home. But your feedback is extremely valuable. Any information you can provide")
ui.Println(" The \033[1mstep\033[0m utility is not instrumented for usage statistics. It does not") ui.Println(" regarding how youre using `step` helps. Please send us a sentence or two,")
ui.Println(" phone home. But your feedback is extremely valuable. Any information you") ui.Println(" good or bad at \033[1mfeedback@smallstep.com\033[0m or join GitHub Discussions")
ui.Println(" can provide regarding how youre using `step` helps. Please send us a") ui.Println(" \033[1mhttps://github.com/smallstep/certificates/discussions\033[0m and our Discord ")
ui.Println(" sentence or two, good or bad: \033[1mfeedback@smallstep.com\033[0m or join") ui.Println(" \033[1mhttps://u.step.sm/discord\033[0m.")
ui.Println(" \033[1mhttps://github.com/smallstep/certificates/discussions\033[0m.")
}
// TellPKI outputs the locations of public and private keys generated if p.options.deploymentType == LinkedDeployment {
// generated for a new PKI. Generally this will consist of a root certificate ui.Println()
// and key and an intermediate certificate and key. ui.Println("\033[1mNEXT STEPS\033[0m")
func (p *PKI) TellPKI() { ui.Println(" 1. Log in or create a Certificate Manager account at \033[1mhttps://u.step.sm/linked\033[0m")
p.tellPKI() ui.Println(" 2. Add a new authority and select \"Link a step-ca instance\"")
p.askFeedback() ui.Println(" 3. Follow instructions in browser to start `step-ca` using the `--token` flag")
ui.Println()
}
} }
func (p *PKI) tellPKI() { func (p *PKI) tellPKI() {
ui.Println() ui.Println()
if p.casOptions.Is(apiv1.SoftCAS) { if p.casOptions.Is(apiv1.SoftCAS) {
ui.PrintSelected("Root certificate", p.root) ui.PrintSelected("Root certificate", p.Root[0])
ui.PrintSelected("Root private key", p.rootKey) ui.PrintSelected("Root private key", p.RootKey[0])
ui.PrintSelected("Root fingerprint", p.rootFingerprint) ui.PrintSelected("Root fingerprint", p.Defaults.Fingerprint)
ui.PrintSelected("Intermediate certificate", p.intermediate) ui.PrintSelected("Intermediate certificate", p.Intermediate)
ui.PrintSelected("Intermediate private key", p.intermediateKey) ui.PrintSelected("Intermediate private key", p.IntermediateKey)
} else if p.rootFingerprint != "" { } else if p.Defaults.Fingerprint != "" {
ui.PrintSelected("Root certificate", p.root) ui.PrintSelected("Root certificate", p.Root[0])
ui.PrintSelected("Root fingerprint", p.rootFingerprint) ui.PrintSelected("Root fingerprint", p.Defaults.Fingerprint)
} else { } else {
ui.Printf(`{{ "%s" | red }} {{ "Root certificate:" | bold }} failed to retrieve it from RA`+"\n", ui.IconBad) ui.Printf(`{{ "%s" | red }} {{ "Root certificate:" | bold }} failed to retrieve it from RA`+"\n", ui.IconBad)
} }
if p.enableSSH { if p.options.enableSSH {
ui.PrintSelected("SSH user root certificate", p.sshUserPubKey) ui.PrintSelected("SSH user public key", p.Ssh.UserPublicKey)
ui.PrintSelected("SSH user root private key", p.sshUserKey) ui.PrintSelected("SSH user private key", p.Ssh.UserKey)
ui.PrintSelected("SSH host root certificate", p.sshHostPubKey) ui.PrintSelected("SSH host public key", p.Ssh.HostPublicKey)
ui.PrintSelected("SSH host root private key", p.sshHostKey) ui.PrintSelected("SSH host private key", p.Ssh.HostKey)
} }
} }
@ -480,176 +645,230 @@ type caDefaults struct {
Root string `json:"root"` Root string `json:"root"`
} }
// Option is the type for modifiers over the auth config object. // ConfigOption is the type for modifiers over the auth config object.
type Option func(c *authconfig.Config) error type ConfigOption func(c *authconfig.Config) error
// WithDefaultDB is a configuration modifier that adds a default DB stanza to
// the authority config.
func WithDefaultDB() Option {
return func(c *authconfig.Config) error {
c.DB = &db.Config{
Type: "badger",
DataSource: GetDBPath(),
}
return nil
}
}
// WithoutDB is a configuration modifier that adds a default DB stanza to
// the authority config.
func WithoutDB() Option {
return func(c *authconfig.Config) error {
c.DB = nil
return nil
}
}
// GenerateConfig returns the step certificates configuration. // GenerateConfig returns the step certificates configuration.
func (p *PKI) GenerateConfig(opt ...Option) (*authconfig.Config, error) { func (p *PKI) GenerateConfig(opt ...ConfigOption) (*authconfig.Config, error) {
key, err := p.ottPrivateKey.CompactSerialize()
if err != nil {
return nil, errors.Wrap(err, "error serializing private key")
}
prov := &provisioner.JWK{
Name: p.provisioner,
Type: "JWK",
Key: p.ottPublicKey,
EncryptedKey: key,
}
var authorityOptions *apiv1.Options var authorityOptions *apiv1.Options
if !p.casOptions.Is(apiv1.SoftCAS) { if !p.casOptions.Is(apiv1.SoftCAS) {
authorityOptions = &p.casOptions authorityOptions = &p.casOptions
} }
config := &authconfig.Config{ config := &authconfig.Config{
Root: []string{p.root}, Root: p.Root,
FederatedRoots: []string{}, FederatedRoots: p.FederatedRoots,
IntermediateCert: p.intermediate, IntermediateCert: p.Intermediate,
IntermediateKey: p.intermediateKey, IntermediateKey: p.IntermediateKey,
Address: p.address, Address: p.Address,
DNSNames: p.dnsNames, DNSNames: p.DnsNames,
Logger: []byte(`{"format": "text"}`), Logger: []byte(`{"format": "text"}`),
DB: &db.Config{ DB: &db.Config{
Type: "badger", Type: "badgerv2",
DataSource: GetDBPath(), DataSource: GetDBPath(),
}, },
AuthorityConfig: &authconfig.AuthConfig{ AuthorityConfig: &authconfig.AuthConfig{
Options: authorityOptions, Options: authorityOptions,
DisableIssuedAtCheck: false, DisableIssuedAtCheck: false,
Provisioners: provisioner.List{prov}, EnableAdmin: false,
},
TLS: &authconfig.TLSOptions{
MinVersion: authconfig.DefaultTLSMinVersion,
MaxVersion: authconfig.DefaultTLSMaxVersion,
Renegotiation: authconfig.DefaultTLSRenegotiation,
CipherSuites: authconfig.DefaultTLSCipherSuites,
}, },
TLS: &authconfig.DefaultTLSOptions,
Templates: p.getTemplates(), Templates: p.getTemplates(),
} }
if p.enableSSH {
enableSSHCA := true // Add linked as a deployment type to detect it on start and provide a
config.SSH = &authconfig.SSHConfig{ // message if the token is not given.
HostKey: p.sshHostKey, if p.options.deploymentType == LinkedDeployment {
UserKey: p.sshUserKey, config.AuthorityConfig.DeploymentType = LinkedDeployment.String()
}
// On standalone deployments add the provisioners to either the ca.json or
// the database.
var provisioners []provisioner.Interface
if p.options.deploymentType == StandaloneDeployment {
key, err := p.ottPrivateKey.CompactSerialize()
if err != nil {
return nil, errors.Wrap(err, "error serializing private key")
} }
// Enable SSH authorization for default JWK provisioner
prov.Claims = &provisioner.Claims{ prov := &provisioner.JWK{
EnableSSHCA: &enableSSHCA, Name: p.options.provisioner,
Type: "JWK",
Key: p.ottPublicKey,
EncryptedKey: key,
} }
// Add default SSHPOP provisioner provisioners = append(provisioners, prov)
sshpop := &provisioner.SSHPOP{
Type: "SSHPOP", // Add default ACME provisioner if enabled
Name: "sshpop", if p.options.enableACME {
Claims: &provisioner.Claims{ provisioners = append(provisioners, &provisioner.ACME{
Type: "ACME",
Name: "acme",
})
}
if p.options.enableSSH {
enableSSHCA := true
config.SSH = &authconfig.SSHConfig{
HostKey: p.Ssh.HostKey,
UserKey: p.Ssh.UserKey,
}
// Enable SSH authorization for default JWK provisioner
prov.Claims = &provisioner.Claims{
EnableSSHCA: &enableSSHCA, EnableSSHCA: &enableSSHCA,
}, }
// Add default SSHPOP provisioner
provisioners = append(provisioners, &provisioner.SSHPOP{
Type: "SSHPOP",
Name: "sshpop",
Claims: &provisioner.Claims{
EnableSSHCA: &enableSSHCA,
},
})
} }
config.AuthorityConfig.Provisioners = append(config.AuthorityConfig.Provisioners, sshpop)
} }
// Apply configuration modifiers // Apply configuration modifiers
for _, o := range opt { for _, o := range opt {
if err = o(config); err != nil { if err := o(config); err != nil {
return nil, err return nil, err
} }
} }
// Set authority.enableAdmin to true
if p.options.enableAdmin {
config.AuthorityConfig.EnableAdmin = true
}
if p.options.deploymentType == StandaloneDeployment {
if !config.AuthorityConfig.EnableAdmin {
config.AuthorityConfig.Provisioners = provisioners
} else {
// At this moment this code path is never used because `step ca
// init` will always set enableAdmin to false for a standalone
// deployment. Once we move `step beta` commands out of the beta we
// should probably default to this route.
//
// Note that we might want to be able to define the database as a
// flag in `step ca init` so we can write to the proper place.
db, err := db.New(config.DB)
if err != nil {
return nil, err
}
adminDB, err := admindb.New(db.(nosql.DB), admin.DefaultAuthorityID)
if err != nil {
return nil, err
}
// Add all the provisioners to the db.
var adminID string
for i, p := range provisioners {
prov, err := authority.ProvisionerToLinkedca(p)
if err != nil {
return nil, err
}
if err := adminDB.CreateProvisioner(context.Background(), prov); err != nil {
return nil, err
}
if i == 0 {
adminID = prov.Id
}
}
// Add the first provisioner as an admin.
if err := adminDB.CreateAdmin(context.Background(), &linkedca.Admin{
AuthorityId: admin.DefaultAuthorityID,
Subject: "step",
Type: linkedca.Admin_SUPER_ADMIN,
ProvisionerId: adminID,
}); err != nil {
return nil, err
}
}
}
return config, nil return config, nil
} }
// Save stores the pki on a json file that will be used as the certificate // Save stores the pki on a json file that will be used as the certificate
// authority configuration. // authority configuration.
func (p *PKI) Save(opt ...Option) error { func (p *PKI) Save(opt ...ConfigOption) error {
// Write generated files
if err := p.WriteFiles(); err != nil {
return err
}
// Display the files written
p.tellPKI() p.tellPKI()
// Generate and write ca.json // Generate and write ca.json
config, err := p.GenerateConfig(opt...) if !p.options.pkiOnly {
if err != nil { config, err := p.GenerateConfig(opt...)
return err
}
b, err := json.MarshalIndent(config, "", "\t")
if err != nil {
return errors.Wrapf(err, "error marshaling %s", p.config)
}
if err = fileutil.WriteFile(p.config, b, 0644); err != nil {
return errs.FileError(err, p.config)
}
// Generate the CA URL.
if p.caURL == "" {
p.caURL = p.dnsNames[0]
var port string
_, port, err = net.SplitHostPort(p.address)
if err != nil { if err != nil {
return errors.Wrapf(err, "error parsing %s", p.address) return err
} }
if port == "443" {
p.caURL = fmt.Sprintf("https://%s", p.caURL) b, err := json.MarshalIndent(config, "", "\t")
} else { if err != nil {
p.caURL = fmt.Sprintf("https://%s:%s", p.caURL, port) return errors.Wrapf(err, "error marshaling %s", p.config)
}
if err = fileutil.WriteFile(p.config, b, 0644); err != nil {
return errs.FileError(err, p.config)
} }
}
// Generate and write defaults.json // Generate and write defaults.json
defaults := &caDefaults{ defaults := &caDefaults{
Root: p.root, Root: p.Defaults.Root,
CAConfig: p.config, CAConfig: p.Defaults.CaConfig,
CAUrl: p.caURL, CAUrl: p.Defaults.CaUrl,
Fingerprint: p.rootFingerprint, Fingerprint: p.Defaults.Fingerprint,
} }
b, err = json.MarshalIndent(defaults, "", "\t") b, err = json.MarshalIndent(defaults, "", "\t")
if err != nil { if err != nil {
return errors.Wrapf(err, "error marshaling %s", p.defaults) return errors.Wrapf(err, "error marshaling %s", p.defaults)
} }
if err = fileutil.WriteFile(p.defaults, b, 0644); err != nil { if err = fileutil.WriteFile(p.defaults, b, 0644); err != nil {
return errs.FileError(err, p.defaults) return errs.FileError(err, p.defaults)
} }
// Generate and write templates // Generate and write templates
if err := generateTemplates(config.Templates); err != nil { if err := generateTemplates(config.Templates); err != nil {
return err return err
} }
if config.DB != nil { if config.DB != nil {
ui.PrintSelected("Database folder", config.DB.DataSource) ui.PrintSelected("Database folder", config.DB.DataSource)
} }
if config.Templates != nil { if config.Templates != nil {
ui.PrintSelected("Templates folder", GetTemplatesPath()) ui.PrintSelected("Templates folder", GetTemplatesPath())
} }
ui.PrintSelected("Default configuration", p.defaults) ui.PrintSelected("Default configuration", p.defaults)
ui.PrintSelected("Certificate Authority configuration", p.config) ui.PrintSelected("Certificate Authority configuration", p.config)
ui.Println() if p.options.deploymentType != LinkedDeployment {
if p.casOptions.Is(apiv1.SoftCAS) { ui.Println()
ui.Println("Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.") if p.casOptions.Is(apiv1.SoftCAS) {
} else { ui.Println("Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.")
ui.Println("Your registration authority is ready to go. To generate certificates for individual services see 'step help ca'.") } else {
ui.Println("Your registration authority is ready to go. To generate certificates for individual services see 'step help ca'.")
}
}
} }
p.askFeedback() p.askFeedback()
return nil return nil
} }
func encodeCertificate(c *x509.Certificate) []byte {
return pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: c.Raw,
})
}
func encodePrivateKey(key crypto.PrivateKey, pass []byte) ([]byte, error) {
block, err := pemutil.Serialize(key, pemutil.WithPassword(pass))
if err != nil {
return nil, err
}
return pem.EncodeToMemory(block), nil
}

View file

@ -13,7 +13,7 @@ import (
// getTemplates returns all the templates enabled // getTemplates returns all the templates enabled
func (p *PKI) getTemplates() *templates.Templates { func (p *PKI) getTemplates() *templates.Templates {
if !p.enableSSH { if !p.options.enableSSH {
return nil return nil
} }
return &templates.Templates{ return &templates.Templates{

4
scripts/README.md Normal file
View file

@ -0,0 +1,4 @@
# Scripts folder
Please note that `install-step-ra.sh` is referenced on the `files.smallstep.com` S3 website bucket as a redirect to `raw.githubusercontent.com`. If you move it, please update the S3 redirect.

265
scripts/install-step-ra.sh Normal file
View file

@ -0,0 +1,265 @@
#!/bin/bash
set -e
# TODO:
# - Parse params using argbash (argbash.io). Here's a template that I have tested but have not implemented yet:
#
# ARG_OPTIONAL_SINGLE([ca-url], , [the URL of the upstream (issuing) step-ca server])
# ARG_OPTIONAL_SINGLE([fingerprint], , [the SHA256 fingerprint of the upstream peer step-ca server])
# ARG_OPTIONAL_SINGLE([provisioner-name], , [the name of a JWK provisioner on the upstream CA that this RA will use])
# ARG_OPTIONAL_SINGLE([provisioner-password-file], , [the name a file containing the upstream JWK provisioner password])
# ARG_OPTIONAL_REPEATED([dns-name], , [DNS name of this RA that will appear on its TLS certificate; you may pass this flag multiple times])
# ARG_OPTIONAL_SINGLE([listen-address], , [the address (and port #) this RA will listen on, eg. :443 or 127.0.0.1:4443])
# ARG_HELP([This script will install and configure a Registration Authority that connects to an upstream CA running step-ca.])
# ARGBASH_GO
echo "This script will install and start a step-ca server running in Registration Authority (RA) mode."
echo ""
echo "You will need an upstream CA (URL and fingerprint)"
echo "Don't have a CA? Sign up for a hosted CA at smallstep.com — or run your own."
echo ""
# Fail if this script is not run as root.
if ! [ $(id -u) = 0 ]; then
echo "This script must be run as root"
exit 1
fi
# Architecture detection
arch=$(uname -m)
case $arch in
x86_64) arch="amd64" ;;
x86) arch="386" ;;
i686) arch="386" ;;
i386) arch="386" ;;
aarch64) arch="arm64" ;;
armv5*) arch="armv5" ;;
armv6*) arch="armv6" ;;
armv7*) arch="armv7" ;;
esac
if [ "$arch" = "armv5" ]; then
echo "This script doesn't work on armv5 machines"
exit 1
fi
if ! hash jq &> /dev/null; then
echo "This script requires the jq commmand; please install it."
exit 1
fi
if ! hash curl &> /dev/null; then
echo "This script requires the curl commmand; please install it."
exit 1
fi
if ! hash tar &> /dev/null; then
echo "This script requires the tar commmand; please install it."
exit 1
fi
while [ $# -gt 0 ]; do
case "$1" in
--ca-url)
CA_URL="$2"
shift
shift
;;
--fingerprint)
CA_FINGERPRINT="$2"
shift
shift
;;
--provisioner-name)
CA_PROVISIONER_NAME="$2"
shift
shift
;;
--provisioner-password-file)
CA_PROVISIONER_JWK_PASSWORD_FILE="$2"
shift
shift
;;
--dns-names)
RA_DNS_NAMES="$2"
shift
shift
;;
--listen-address)
RA_ADDRESS="$2"
shift
shift
;;
*)
shift
;;
esac
done
# Install step
if ! hash step &> /dev/null; then
echo "Installing 'step' in /usr/bin..."
STEP_VERSION=$(curl -s https://api.github.com/repos/smallstep/cli/releases/latest | jq -r '.tag_name')
curl -sLO https://github.com/smallstep/cli/releases/download/$STEP_VERSION/step_linux_${STEP_VERSION:1}_$arch.tar.gz
tar xvzf step_linux_${STEP_VERSION:1}_$arch.tar.gz
install -m 0755 -t /usr/bin step_${STEP_VERSION:1}/bin/step
rm step_linux_${STEP_VERSION:1}_$arch.tar.gz
rm -rf step_${STEP_VERSION:1}
fi
# Prompt for required parameters
if [ -z "$CA_URL" ]; then
CA_URL=""
while [[ $CA_URL = "" ]]; do
read -p "Issuing CA URL: " CA_URL < /dev/tty
done
fi
if [ -z "$CA_FINGERPRINT" ]; then
CA_FINGERPRINT=""
while [[ $CA_FINGERPRINT = "" ]]; do
read -p "Issuing CA Fingerprint: " CA_FINGERPRINT < /dev/tty
done
fi
echo "Bootstrapping with the CA..."
export STEPPATH=$(mktemp -d)
export STEP_CONSOLE=true
step ca bootstrap --ca-url $CA_URL --fingerprint $CA_FINGERPRINT
if [ -z "$CA_PROVISIONER_NAME" ]; then
declare -a provisioners
readarray -t provisioners < <(step ca provisioner list | jq -r '.[] | select(.type == "JWK") | .name')
provisioners+=("Create provisioner")
printf '%s\n' "${provisioners[@]}"
printf "%b" "\nSelect a JWK provisioner:\n" >&2
select provisioner in "${provisioners[@]}"; do
if [ "$provisioner" == "Create provisioner" ]; then
echo "Creating a JWK provisioner on the upstream CA..."
echo ""
read -p "Label your provisioner (e.g. example-ra): " CA_PROVISIONER_NAME < /dev/tty
step beta ca provisioner add $CA_PROVISIONER_NAME --type JWK --create
break
elif [ -n "$provisioner" ]; then
echo "Using existing provisioner $provisioner."
CA_PROVISIONER_NAME=$provisioner
break
else
echo "Invalid selection!"
fi
done
fi
if [ -z "$RA_DNS_NAMES" ]; then
RA_DNS_NAMES=""
while [[ $RA_DNS_NAMES = "" ]]; do
echo "What DNS names or IP addresses will your RA use?"
read -p "(e.g. acme.example.com[,1.1.1.1,etc.]): " RA_DNS_NAMES < /dev/tty
done
fi
if [ -z "$RA_ADDRESS" ]; then
RA_ADDRESS=""
while [[ $RA_ADDRESS = "" ]] ; do
echo "What address should your RA listen on?"
read -p "(e.g. :443 or 10.2.1.201:4430): " RA_ADDRESS < /dev/tty
done
fi
if [ -z "$CA_PROVISIONER_JWK_PASSWORD_FILE" ]; then
read -s -p "Enter the CA Provisioner Password: " CA_PROVISIONER_JWK_PASSWORD < /dev/tty
printf "%b" "\n"
fi
echo "Installing 'step-ca' in /usr/bin..."
CA_VERSION=$(curl -s https://api.github.com/repos/smallstep/certificates/releases/latest | jq -r '.tag_name')
curl -sLO https://github.com/smallstep/certificates/releases/download/$CA_VERSION/step-ca_linux_${CA_VERSION:1}_$arch.tar.gz
tar -xf step-ca_linux_${CA_VERSION:1}_$arch.tar.gz
install -m 0755 -t /usr/bin step-ca_${CA_VERSION:1}/bin/step-ca
setcap CAP_NET_BIND_SERVICE=+eip $(which step-ca)
rm step-ca_linux_${CA_VERSION:1}_$arch.tar.gz
rm -rf step-ca_${CA_VERSION:1}
echo "Creating 'step' user..."
export STEPPATH=/etc/step-ca
useradd --system --home $(step path) --shell /bin/false step
echo "Creating RA configuration..."
mkdir -p $(step path)/db
mkdir -p $(step path)/config
cat <<EOF > $(step path)/config/ca.json
{
"address": "$RA_ADDRESS",
"dnsNames": ["$RA_DNS_NAMES"],
"db": {
"type": "badgerV2",
"dataSource": "/etc/step-ca/db"
},
"logger": {"format": "text"},
"authority": {
"type": "stepcas",
"certificateAuthority": "$CA_URL",
"certificateAuthorityFingerprint": "$CA_FINGERPRINT",
"certificateIssuer": {
"type" : "jwk",
"provisioner": "$CA_PROVISIONER_NAME"
},
"provisioners": [{
"type": "ACME",
"name": "acme"
}]
},
"tls": {
"cipherSuites": [
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
],
"minVersion": 1.2,
"maxVersion": 1.3,
"renegotiation": false
}
}
EOF
if ! [ -z "$CA_PROVISIONER_JWK_PASSWORD" ]; then
echo "Saving provisoiner password to $(step path)/password.txt..."
echo $CA_PROVISIONER_JWK_PASSWORD > $(step path)/password.txt
else
echo "Copying provisioner password file to $(step path)/password.txt..."
cp $CA_PROVISIONER_JWK_PASSWORD_FILE $(step path)/password.txt
fi
chmod 440 $(step path)/password.txt
# Add a service to systemd for the RA.
echo "Creating systemd service step-ca.service..."
curl -sL https://raw.githubusercontent.com/smallstep/certificates/master/systemd/step-ca.service \
-o /etc/systemd/system/step-ca.service
echo "Creating RA mode override /etc/systemd/system/step-ca.service.d/local.conf..."
mkdir /etc/systemd/system/step-ca.service.d
cat <<EOF > /etc/systemd/system/step-ca.service.d/local.conf
[Service]
; The empty ExecStart= clears the inherited ExecStart= value
ExecStart=
ExecStart=/usr/bin/step-ca config/ca.json --issuer-password-file password.txt
EOF
echo "Starting step-ca.service..."
systemctl daemon-reload
chown -R step:step $(step path)
systemctl enable --now step-ca
echo "Adding STEPPATH export to /root/.bash_profile..."
echo "export STEPPATH=$STEPPATH" >> /root/.bash_profile
echo "Finished. Check the journal with journalctl -fu step-ca.service"

View file

@ -12,14 +12,10 @@ Environment=STEPPATH=/etc/step-ca \
CERT_LOCATION=/etc/step/certs/%i.crt \ CERT_LOCATION=/etc/step/certs/%i.crt \
KEY_LOCATION=/etc/step/certs/%i.key KEY_LOCATION=/etc/step/certs/%i.key
; ExecStartPre checks if the certificate is ready for renewal, ; ExecCondition checks if the certificate is ready for renewal,
; based on the exit status of the command. ; based on the exit status of the command.
; (In systemd 243 and above, you can use ExecCondition= here.) ; (In systemd 242 or below, you can use ExecStartPre= here.)
ExecStartPre=/usr/bin/env bash -c \ ExecCondition=/usr/bin/step certificate needs-renewal $CERT_LOCATION
'step certificate inspect $CERT_LOCATION --format json --roots "$STEPPATH/certs/root_ca.crt" | \
jq -e "(((.validity.start | fromdate) + \
((.validity.end | fromdate) - (.validity.start | fromdate)) * 0.66) \
- now) <= 0" > /dev/null'
; ExecStart renews the certificate, if ExecStartPre was successful. ; ExecStart renews the certificate, if ExecStartPre was successful.
ExecStart=/usr/bin/step ca renew --force $CERT_LOCATION $KEY_LOCATION ExecStart=/usr/bin/step ca renew --force $CERT_LOCATION $KEY_LOCATION