2018-12-19 08:22:49 +00:00
package create
import (
"flag"
"fmt"
"github.com/hashicorp/consul/command/flags"
"github.com/hashicorp/consul/command/tls"
2020-01-31 16:12:36 +00:00
"github.com/hashicorp/consul/lib/file"
2019-06-27 20:22:07 +00:00
"github.com/hashicorp/consul/tlsutil"
2018-12-19 08:22:49 +00:00
"github.com/mitchellh/cli"
)
func New ( ui cli . Ui ) * cmd {
c := & cmd { UI : ui }
c . init ( )
return c
}
type cmd struct {
UI cli . Ui
flags * flag . FlagSet
help string
days int
domain string
2021-01-27 07:52:15 +00:00
clusterID string
2018-12-19 08:22:49 +00:00
constraint bool
2021-01-27 07:52:15 +00:00
commonName string
2018-12-19 08:22:49 +00:00
additionalConstraints flags . AppendSliceValue
}
func ( c * cmd ) init ( ) {
c . flags = flag . NewFlagSet ( "" , flag . ContinueOnError )
2019-03-01 16:25:37 +00:00
// TODO: perhaps add a -years arg to better capture user intent given that leap years are a thing
2018-12-19 08:22:49 +00:00
c . flags . IntVar ( & c . days , "days" , 1825 , "Provide number of days the CA is valid for from now on. Defaults to 5 years." )
c . flags . BoolVar ( & c . constraint , "name-constraint" , false , "Add name constraints for the CA. Results in rejecting " +
"certificates for other DNS than specified. If turned on localhost and -domain will be added to the allowed " +
"DNS. If the UI is going to be served over HTTPS its DNS has to be added with -additional-constraint. It is not " +
"possible to add that after the fact! Defaults to false." )
c . flags . StringVar ( & c . domain , "domain" , "consul" , "Domain of consul cluster. Only used in combination with -name-constraint. Defaults to consul." )
2021-01-27 07:52:15 +00:00
c . flags . StringVar ( & c . clusterID , "cluster-id" , "" , "ClusterID of the consul cluster, requires -domain to be set as well. When used will set URIs with spiffeid." )
c . flags . StringVar ( & c . commonName , "common-name" , "" , "Common Name of CA. Defaults to Consul Agent CA." )
2018-12-19 08:22:49 +00:00
c . flags . Var ( & c . additionalConstraints , "additional-name-constraint" , "Add name constraints for the CA. Results in rejecting certificates " +
"for other DNS than specified. Can be used multiple times. Only used in combination with -name-constraint." )
c . help = flags . Usage ( help , c . flags )
}
func ( c * cmd ) Run ( args [ ] string ) int {
if err := c . flags . Parse ( args ) ; err != nil {
if err == flag . ErrHelp {
return 0
}
c . UI . Error ( fmt . Sprintf ( "Failed to parse args: %v" , err ) )
return 1
}
certFileName := fmt . Sprintf ( "%s-agent-ca.pem" , c . domain )
pkFileName := fmt . Sprintf ( "%s-agent-ca-key.pem" , c . domain )
if ! ( tls . FileDoesNotExist ( certFileName ) ) {
c . UI . Error ( certFileName + " already exists." )
return 1
}
if ! ( tls . FileDoesNotExist ( pkFileName ) ) {
c . UI . Error ( pkFileName + " already exists." )
return 1
}
constraints := [ ] string { }
if c . constraint {
constraints = append ( c . additionalConstraints , [ ] string { c . domain , "localhost" } ... )
}
2020-01-31 16:12:36 +00:00
2021-01-27 07:52:15 +00:00
ca , pk , err := tlsutil . GenerateCA ( tlsutil . CAOpts { Name : c . commonName , Days : c . days , Domain : c . domain , PermittedDNSDomains : constraints , ClusterID : c . clusterID } )
2018-12-19 08:22:49 +00:00
if err != nil {
c . UI . Error ( err . Error ( ) )
2020-01-31 16:12:36 +00:00
return 1
2018-12-19 08:22:49 +00:00
}
2020-01-31 16:12:36 +00:00
if err := file . WriteAtomicWithPerms ( certFileName , [ ] byte ( ca ) , 0755 , 0666 ) ; err != nil {
2018-12-19 08:22:49 +00:00
c . UI . Error ( err . Error ( ) )
2020-01-31 16:12:36 +00:00
return 1
2018-12-19 08:22:49 +00:00
}
c . UI . Output ( "==> Saved " + certFileName )
2020-01-31 16:12:36 +00:00
2021-12-08 19:16:36 +00:00
if err := file . WriteAtomicWithPerms ( pkFileName , [ ] byte ( pk ) , 0755 , 0600 ) ; err != nil {
2018-12-19 08:22:49 +00:00
c . UI . Error ( err . Error ( ) )
2020-01-31 16:12:36 +00:00
return 1
2018-12-19 08:22:49 +00:00
}
c . UI . Output ( "==> Saved " + pkFileName )
return 0
}
func ( c * cmd ) Synopsis ( ) string {
return synopsis
}
func ( c * cmd ) Help ( ) string {
return c . help
}
const synopsis = "Create a new consul CA"
const help = `
Usage : consul tls ca create [ options ]
Create a new consul CA :
$ consul tls ca create
== > saved consul - agent - ca . pem
== > saved consul - agent - ca - key . pem
`