forked from TrueCloudLab/certificates
Create a way to export ca configurations.
This commit is contained in:
parent
d0c1530f89
commit
dc1ec18b52
4 changed files with 445 additions and 1 deletions
39
authority/export.go
Normal file
39
authority/export.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package authority
|
||||||
|
|
||||||
|
import "go.step.sm/linkedca"
|
||||||
|
|
||||||
|
func (a *Authority) Export() (*linkedca.Configuration, error) {
|
||||||
|
var admins []*linkedca.Admin
|
||||||
|
var provisioners []*linkedca.Provisioner
|
||||||
|
|
||||||
|
for {
|
||||||
|
list, cursor := a.admins.Find("", 100)
|
||||||
|
admins = append(admins, list...)
|
||||||
|
if cursor == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
list, cursor := a.provisioners.Find("", 100)
|
||||||
|
for _, p := range list {
|
||||||
|
lp, err := ProvisionerToLinkedca(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
provisioners = append(provisioners, lp)
|
||||||
|
}
|
||||||
|
if cursor == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global claims for all provisioners.
|
||||||
|
claims := claimsToLinkedca(a.config.AuthorityConfig.Claims)
|
||||||
|
|
||||||
|
return &linkedca.Configuration{
|
||||||
|
Admins: admins,
|
||||||
|
Provisioners: provisioners,
|
||||||
|
Claims: claims,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -4,12 +4,16 @@ 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/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"
|
||||||
|
@ -398,6 +402,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 +449,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) {
|
||||||
|
@ -588,6 +702,223 @@ 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{
|
||||||
|
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{
|
||||||
|
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{
|
||||||
|
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{
|
||||||
|
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{
|
||||||
|
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{
|
||||||
|
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{
|
||||||
|
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{
|
||||||
|
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{
|
||||||
|
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{
|
||||||
|
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 != "" {
|
||||||
|
|
74
commands/export.go
Normal file
74
commands/export.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"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.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
'''`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportAction(ctx *cli.Context) error {
|
||||||
|
if err := errs.NumberOfArguments(ctx, 1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
configFile := ctx.Args().Get(0)
|
||||||
|
|
||||||
|
config, err := config.LoadConfiguration(configFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
2
go.mod
2
go.mod
|
@ -42,6 +42,6 @@ require (
|
||||||
// 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/cli-utils => ../cli-utils
|
||||||
// replace go.step.sm/linkedca => ../linkedca
|
replace go.step.sm/linkedca => ../linkedca
|
||||||
|
|
||||||
replace go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 => github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568
|
replace go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 => github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568
|
||||||
|
|
Loading…
Reference in a new issue