1
0
mirror of https://github.com/smallstep/cli.git synced 2025-08-07 16:02:54 +03:00
Files
step-ca-cli/command/ca/federation.go
Max 60a4eef3de Fix linter warnings (#1450)
* Remove unnecessary utils files in favor of cli-utils package
* Remove nolint:revive directive from bcrypt-pbkdf file
2025-07-10 11:15:28 -07:00

190 lines
4.1 KiB
Go

package ca
import (
"encoding/pem"
"fmt"
"os"
"github.com/pkg/errors"
"github.com/urfave/cli"
"github.com/smallstep/certificates/api"
"github.com/smallstep/certificates/ca"
"github.com/smallstep/certificates/pki"
"github.com/smallstep/cli-utils/command"
"github.com/smallstep/cli-utils/errs"
"github.com/smallstep/cli-utils/fileutil"
"github.com/smallstep/cli-utils/ui"
"go.step.sm/crypto/pemutil"
"github.com/smallstep/cli/flags"
)
type flowType int
const (
rootsFlow flowType = iota
federationFlow
)
func rootsCommand() cli.Command {
return cli.Command{
Name: "roots",
Action: command.ActionFunc(rootsAction),
Usage: "download all the root certificates",
UsageText: `**step ca roots** [<roots-file>]
[**--ca-url**=<uri>] [**--root**=<file>] [**--context**=<name>]`,
Description: `**step ca roots** downloads a certificate bundle with all the root
certificates.
## POSITIONAL ARGUMENTS
<roots-file>
: File to write all the root certificates (PEM format)
## EXAMPLES
Download the roots with flags set by <step ca bootstrap>:
'''
$ step ca roots roots.pem
'''
Download the roots with custom flags:
'''
$ step ca roots roots.pem \
--ca-url https://ca.example.com \
--root /path/to/root_ca.crt
'''
Print the roots using flags set by <step ca bootstrap>:
'''
$ step ca roots
'''`,
Flags: []cli.Flag{
flags.CaURL,
flags.Force,
flags.Root,
flags.Context,
},
}
}
func federationCommand() cli.Command {
return cli.Command{
Name: "federation",
Action: command.ActionFunc(federationAction),
Usage: "download all the federated certificates",
UsageText: `**step ca federation** [<federation-file>]
[**--ca-url**=<uri>] [**--root**=<file>] [**--context**=<name>]`,
Description: `**step ca federation** downloads a certificate bundle with all the root
certificates in the federation.
## POSITIONAL ARGUMENTS
<federation-file>
: File to write federation certificates (PEM format)
## EXAMPLES
Download the federated roots with flags set by <step ca bootstrap>:
'''
$ step ca federation federation.pem
'''
Download the federated roots with custom flags:
'''
$ step ca federation federation.pem \
--ca-url https://ca.example.com \
--root /path/to/root_ca.crt
'''
Print the federated roots using flags set by <step ca bootstrap>:
'''
$ step ca federation
'''`,
Flags: []cli.Flag{
flags.CaURL,
flags.Force,
flags.Root,
flags.Context,
},
}
}
func rootsAction(ctx *cli.Context) error {
return rootsAndFederationFlow(ctx, rootsFlow)
}
func federationAction(ctx *cli.Context) error {
return rootsAndFederationFlow(ctx, federationFlow)
}
func rootsAndFederationFlow(ctx *cli.Context, typ flowType) error {
if err := errs.MinMaxNumberOfArguments(ctx, 0, 1); err != nil {
return err
}
caURL, err := flags.ParseCaURL(ctx)
if err != nil {
return err
}
root := ctx.String("root")
if root == "" {
root = pki.GetRootCAPath()
if _, err := os.Stat(root); err != nil {
return errs.RequiredFlag(ctx, "root")
}
}
client, err := ca.NewClient(caURL, ca.WithRootFile(root))
if err != nil {
return err
}
var certs []api.Certificate
switch typ {
case rootsFlow:
roots, err := client.Roots()
if err != nil {
return err
}
certs = roots.Certificates
case federationFlow:
federation, err := client.Federation()
if err != nil {
return err
}
certs = federation.Certificates
default:
return errors.New("unknown flow type: this should not happen")
}
var data []byte
for _, cert := range certs {
block, err := pemutil.Serialize(cert.Certificate)
if err != nil {
return err
}
data = append(data, pem.EncodeToMemory(block)...)
}
if outFile := ctx.Args().Get(0); outFile != "" {
if err := fileutil.WriteFile(outFile, data, 0o600); err != nil {
return err
}
switch typ {
case rootsFlow:
ui.Printf("The root certificate bundle has been saved in %s.\n", outFile)
case federationFlow:
ui.Printf("The federation certificate bundle has been saved in %s.\n", outFile)
default:
return errors.New("unknown flow type: this should not happen")
}
} else {
fmt.Print(string(data))
}
return nil
}