kubernetes/vendor/github.com/cloudflare/cfssl/cli/sign/sign.go
2018-08-08 21:01:29 -07:00

182 lines
5.0 KiB
Go

// Package sign implements the sign command.
package sign
import (
"encoding/json"
"errors"
"io/ioutil"
"github.com/cloudflare/cfssl/certdb/dbconf"
certsql "github.com/cloudflare/cfssl/certdb/sql"
"github.com/cloudflare/cfssl/cli"
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/cfssl/signer"
"github.com/cloudflare/cfssl/signer/universal"
"github.com/jmoiron/sqlx"
)
// Usage text of 'cfssl sign'
var signerUsageText = `cfssl sign -- signs a client cert with a host name by a given CA and CA key
Usage of sign:
cfssl sign -ca cert -ca-key key [mutual-tls-cert cert] [mutual-tls-key key] [-config config] [-profile profile] [-hostname hostname] [-db-config db-config] CSR [SUBJECT]
cfssl sign -remote remote_host [mutual-tls-cert cert] [mutual-tls-key key] [-config config] [-profile profile] [-label label] [-hostname hostname] CSR [SUBJECT]
Arguments:
CSR: PEM file for certificate request, use '-' for reading PEM from stdin.
Note: CSR can also be supplied via flag values; flag value will take precedence over the argument.
SUBJECT is an optional file containing subject information to use for the certificate instead of the subject information in the CSR.
Flags:
`
// Flags of 'cfssl sign'
var signerFlags = []string{"hostname", "csr", "ca", "ca-key", "config", "profile", "label", "remote",
"mutual-tls-cert", "mutual-tls-key", "db-config"}
// SignerFromConfigAndDB takes the Config and creates the appropriate
// signer.Signer object with a specified db
func SignerFromConfigAndDB(c cli.Config, db *sqlx.DB) (signer.Signer, error) {
// If there is a config, use its signing policy. Otherwise create a default policy.
var policy *config.Signing
if c.CFG != nil {
policy = c.CFG.Signing
} else {
policy = &config.Signing{
Profiles: map[string]*config.SigningProfile{},
Default: config.DefaultConfig(),
}
}
// Make sure the policy reflects the new remote
if c.Remote != "" {
err := policy.OverrideRemotes(c.Remote)
if err != nil {
log.Infof("Invalid remote %v, reverting to configuration default", c.Remote)
return nil, err
}
}
if c.MutualTLSCertFile != "" && c.MutualTLSKeyFile != "" {
err := policy.SetClientCertKeyPairFromFile(c.MutualTLSCertFile, c.MutualTLSKeyFile)
if err != nil {
log.Infof("Invalid mutual-tls-cert: %s or mutual-tls-key: %s, defaulting to no client auth", c.MutualTLSCertFile, c.MutualTLSKeyFile)
return nil, err
}
log.Infof("Using client auth with mutual-tls-cert: %s and mutual-tls-key: %s", c.MutualTLSCertFile, c.MutualTLSKeyFile)
}
if c.TLSRemoteCAs != "" {
err := policy.SetRemoteCAsFromFile(c.TLSRemoteCAs)
if err != nil {
log.Infof("Invalid tls-remote-ca: %s, defaulting to system trust store", c.TLSRemoteCAs)
return nil, err
}
log.Infof("Using trusted CA from tls-remote-ca: %s", c.TLSRemoteCAs)
}
s, err := universal.NewSigner(cli.RootFromConfig(&c), policy)
if err != nil {
return nil, err
}
if db != nil {
dbAccessor := certsql.NewAccessor(db)
s.SetDBAccessor(dbAccessor)
}
return s, nil
}
// SignerFromConfig takes the Config and creates the appropriate
// signer.Signer object
func SignerFromConfig(c cli.Config) (s signer.Signer, err error) {
var db *sqlx.DB
if c.DBConfigFile != "" {
db, err = dbconf.DBFromConfig(c.DBConfigFile)
if err != nil {
return nil, err
}
}
return SignerFromConfigAndDB(c, db)
}
// signerMain is the main CLI of signer functionality.
// [TODO: zi] Decide whether to drop the argument list and only use flags to specify all the inputs.
func signerMain(args []string, c cli.Config) (err error) {
if c.CSRFile == "" {
c.CSRFile, args, err = cli.PopFirstArgument(args)
if err != nil {
return
}
}
var subjectData *signer.Subject
if len(args) > 0 {
var subjectFile string
subjectFile, args, err = cli.PopFirstArgument(args)
if err != nil {
return
}
if len(args) > 0 {
return errors.New("too many arguments are provided, please check with usage")
}
var subjectJSON []byte
subjectJSON, err = ioutil.ReadFile(subjectFile)
if err != nil {
return
}
subjectData = new(signer.Subject)
err = json.Unmarshal(subjectJSON, subjectData)
if err != nil {
return
}
}
csr, err := cli.ReadStdin(c.CSRFile)
if err != nil {
return
}
// Remote can be forced on the command line or in the config
if c.Remote == "" && c.CFG == nil {
if c.CAFile == "" {
log.Error("need CA certificate (provide one with -ca)")
return
}
if c.CAKeyFile == "" {
log.Error("need CA key (provide one with -ca-key)")
return
}
}
s, err := SignerFromConfig(c)
if err != nil {
return
}
req := signer.SignRequest{
Hosts: signer.SplitHosts(c.Hostname),
Request: string(csr),
Subject: subjectData,
Profile: c.Profile,
Label: c.Label,
}
cert, err := s.Sign(req)
if err != nil {
return
}
cli.PrintCert(nil, csr, cert)
return
}
// Command assembles the definition of Command 'sign'
var Command = &cli.Command{UsageText: signerUsageText, Flags: signerFlags, Main: signerMain}