568da5918b
The `nomad tls cert` command did not create certificates with the correct SANs for them to work with non default domain and region names. This changset updates the code to support non default domains and regions in the certificates.
166 lines
4.9 KiB
Go
166 lines
4.9 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package command
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/posener/complete"
|
|
|
|
"github.com/hashicorp/nomad/helper/flags"
|
|
"github.com/hashicorp/nomad/helper/tlsutil"
|
|
"github.com/hashicorp/nomad/lib/file"
|
|
)
|
|
|
|
type TLSCACreateCommand struct {
|
|
Meta
|
|
|
|
// days is the number of days the CA will be valid for
|
|
days int
|
|
|
|
// constraint boolean enables the name constraint option in the CA which
|
|
// will then reject any domains other than the ones stiputalted in -domain
|
|
// and -addtitional-domain.
|
|
constraint bool
|
|
|
|
// domain is used to provide a custom domain for the CA
|
|
domain string
|
|
|
|
// commonName is used to set a common name for the CA
|
|
commonName string
|
|
|
|
// additionalDomain provides a list of restricted domains to the CA which
|
|
// will then reject any domains other than these.
|
|
additionalDomain flags.StringFlag
|
|
}
|
|
|
|
func (c *TLSCACreateCommand) Help() string {
|
|
helpText := `
|
|
Usage: nomad tls ca create [options]
|
|
|
|
Create a new certificate authority.
|
|
|
|
CA Create Options:
|
|
|
|
-additional-domain
|
|
Add additional DNS zones to the allowed list for the CA. The server will
|
|
reject certificates for DNS names other than those specified in -domain and
|
|
-additional-domain. This flag can be used multiple times. Only used in
|
|
combination with -domain and -name-constraint.
|
|
|
|
-common-name
|
|
Common Name of CA. Defaults to "Nomad Agent CA".
|
|
|
|
-days
|
|
Provide number of days the CA is valid for from now on.
|
|
Defaults to 5 years or 1825 days.
|
|
|
|
-domain
|
|
Domain of Nomad cluster. Only used in combination with -name-constraint.
|
|
Defaults to "nomad".
|
|
|
|
-name-constraint
|
|
Enables the DNS name restriction functionality to the CA. Results in the CA
|
|
rejecting certificates for any other DNS zone. If enabled, localhost and the
|
|
value of -domain will be added to the allowed DNS zones field. If the UI is
|
|
going to be served over HTTPS its hostname must be added with
|
|
-additional-domain. Defaults to false.
|
|
`
|
|
return strings.TrimSpace(helpText)
|
|
}
|
|
|
|
func (c *TLSCACreateCommand) AutocompleteFlags() complete.Flags {
|
|
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
|
|
complete.Flags{
|
|
"-additional-domain": complete.PredictAnything,
|
|
"-common-name": complete.PredictAnything,
|
|
"-days": complete.PredictAnything,
|
|
"-domain": complete.PredictAnything,
|
|
"-name-constraint": complete.PredictAnything,
|
|
})
|
|
}
|
|
|
|
func (c *TLSCACreateCommand) AutocompleteArgs() complete.Predictor {
|
|
return complete.PredictNothing
|
|
}
|
|
|
|
func (c *TLSCACreateCommand) Synopsis() string {
|
|
return "Create a certificate authority for Nomad"
|
|
}
|
|
|
|
func (c *TLSCACreateCommand) Name() string { return "tls ca create" }
|
|
|
|
func (c *TLSCACreateCommand) Run(args []string) int {
|
|
|
|
flagSet := c.Meta.FlagSet(c.Name(), FlagSetClient)
|
|
flagSet.Usage = func() { c.Ui.Output(c.Help()) }
|
|
flagSet.Var(&c.additionalDomain, "additional-domain", "")
|
|
flagSet.IntVar(&c.days, "days", 1825, "")
|
|
flagSet.BoolVar(&c.constraint, "name-constraint", false, "")
|
|
flagSet.StringVar(&c.domain, "domain", "nomad", "")
|
|
flagSet.StringVar(&c.commonName, "common-name", "", "")
|
|
if err := flagSet.Parse(args); err != nil {
|
|
return 1
|
|
}
|
|
|
|
// Check that we got no arguments
|
|
args = flagSet.Args()
|
|
if l := len(args); l < 0 || l > 1 {
|
|
c.Ui.Error("This command takes up to one argument")
|
|
c.Ui.Error(commandErrorText(c))
|
|
return 1
|
|
}
|
|
if c.domain != "" && c.domain != "nomad" && !c.constraint {
|
|
c.Ui.Error("Please provide the -name-constraint flag to use a custom domain constraint")
|
|
return 1
|
|
}
|
|
if c.domain == "nomad" && c.constraint {
|
|
c.Ui.Error("Please provide the -domain flag if you want to enable custom domain constraints")
|
|
return 1
|
|
}
|
|
if c.additionalDomain != nil && c.domain == "" && !c.constraint {
|
|
c.Ui.Error("Please provide the -name-constraint flag to use a custom domain constraints")
|
|
return 1
|
|
}
|
|
|
|
certFileName := fmt.Sprintf("%s-agent-ca.pem", c.domain)
|
|
pkFileName := fmt.Sprintf("%s-agent-ca-key.pem", c.domain)
|
|
|
|
if !(fileDoesNotExist(certFileName)) {
|
|
c.Ui.Error(fmt.Sprintf("CA certificate file '%s' already exists", certFileName))
|
|
return 1
|
|
}
|
|
if !(fileDoesNotExist(pkFileName)) {
|
|
c.Ui.Error(fmt.Sprintf("CA key file '%s' already exists", pkFileName))
|
|
return 1
|
|
}
|
|
|
|
constraints := []string{}
|
|
if c.constraint {
|
|
constraints = []string{c.domain, "localhost", "nomad"}
|
|
constraints = append(constraints, c.additionalDomain...)
|
|
}
|
|
|
|
ca, pk, err := tlsutil.GenerateCA(tlsutil.CAOpts{Name: c.commonName, Days: c.days, Domain: c.domain, PermittedDNSDomains: constraints})
|
|
if err != nil {
|
|
c.Ui.Error(err.Error())
|
|
return 1
|
|
}
|
|
|
|
if err := file.WriteAtomicWithPerms(certFileName, []byte(ca), 0755, 0666); err != nil {
|
|
c.Ui.Error(err.Error())
|
|
return 1
|
|
}
|
|
c.Ui.Output("==> CA certificate saved to: " + certFileName)
|
|
|
|
if err := file.WriteAtomicWithPerms(pkFileName, []byte(pk), 0755, 0600); err != nil {
|
|
c.Ui.Error(err.Error())
|
|
return 1
|
|
}
|
|
c.Ui.Output("==> CA certificate key saved to: " + pkFileName)
|
|
|
|
return 0
|
|
}
|