forked from TrueCloudLab/certificates
Initialize the required config fields on embedded authorities.
This change is to make easier the use of embedded authorities. It can be difficult for third parties to know what fields are required. The new init methods will define the minimum usable configuration.
This commit is contained in:
parent
9499aed6d1
commit
4e544344f9
3 changed files with 45 additions and 26 deletions
|
@ -67,7 +67,6 @@ func New(config *Config, opts ...Option) (*Authority, error) {
|
|||
var a = &Authority{
|
||||
config: config,
|
||||
certificates: new(sync.Map),
|
||||
provisioners: provisioner.NewCollection(config.getAudiences()),
|
||||
}
|
||||
|
||||
// Apply options.
|
||||
|
@ -88,15 +87,9 @@ func New(config *Config, opts ...Option) (*Authority, error) {
|
|||
// NewEmbedded initializes an authority that can be embedded in a different
|
||||
// project without the limitations of the config.
|
||||
func NewEmbedded(opts ...Option) (*Authority, error) {
|
||||
config := &Config{
|
||||
DNSNames: []string{"localhost", "127.0.0.1", "::1"},
|
||||
AuthorityConfig: defaultAuthConfig,
|
||||
TLS: &DefaultTLSOptions,
|
||||
}
|
||||
a := &Authority{
|
||||
config: config,
|
||||
config: &Config{},
|
||||
certificates: new(sync.Map),
|
||||
provisioners: provisioner.NewCollection(config.getAudiences()),
|
||||
}
|
||||
|
||||
// Apply options.
|
||||
|
@ -108,6 +101,8 @@ func NewEmbedded(opts ...Option) (*Authority, error) {
|
|||
|
||||
// Validate required options
|
||||
switch {
|
||||
case a.config == nil:
|
||||
return nil, errors.New("cannot create an authority without a configuration")
|
||||
case len(a.rootX509Certs) == 0 && a.config.Root.HasEmpties():
|
||||
return nil, errors.New("cannot create an authority without a root certificate")
|
||||
case a.x509Issuer == nil && a.config.IntermediateCert == "":
|
||||
|
@ -116,6 +111,9 @@ func NewEmbedded(opts ...Option) (*Authority, error) {
|
|||
return nil, errors.New("cannot create an authority without an issuer signer")
|
||||
}
|
||||
|
||||
// Initialize config required fields.
|
||||
a.config.init()
|
||||
|
||||
// Initialize authority from options or configuration.
|
||||
if err := a.init(); err != nil {
|
||||
return nil, err
|
||||
|
@ -271,9 +269,11 @@ func (a *Authority) init() error {
|
|||
return err
|
||||
}
|
||||
// Initialize provisioners
|
||||
audiences := a.config.getAudiences()
|
||||
a.provisioners = provisioner.NewCollection(audiences)
|
||||
config := provisioner.Config{
|
||||
Claims: claimer.Claims(),
|
||||
Audiences: a.config.getAudiences(),
|
||||
Audiences: audiences,
|
||||
DB: a.db,
|
||||
SSHKeys: &provisioner.SSHKeys{
|
||||
UserKeys: sshKeys.UserKeys,
|
||||
|
|
|
@ -207,6 +207,7 @@ func TestNewEmbedded(t *testing.T) {
|
|||
wantErr bool
|
||||
}{
|
||||
{"ok", args{[]Option{WithX509RootBundle(caPEM), WithX509Signer(crt, key.(crypto.Signer))}}, false},
|
||||
{"ok empty config", args{[]Option{WithConfig(&Config{}), WithX509RootBundle(caPEM), WithX509Signer(crt, key.(crypto.Signer))}}, false},
|
||||
{"ok config file", args{[]Option{WithConfigFile("../ca/testdata/ca.json")}}, false},
|
||||
{"ok config", args{[]Option{WithConfig(&Config{
|
||||
Root: []string{"testdata/certs/root_ca.crt"},
|
||||
|
@ -216,6 +217,7 @@ func TestNewEmbedded(t *testing.T) {
|
|||
AuthorityConfig: &AuthConfig{},
|
||||
})}}, false},
|
||||
{"fail options", args{[]Option{WithX509RootBundle([]byte("bad data"))}}, true},
|
||||
{"fail missing config", args{[]Option{WithConfig(nil), WithX509RootBundle(caPEM), WithX509Signer(crt, key.(crypto.Signer))}}, true},
|
||||
{"fail missing root", args{[]Option{WithX509Signer(crt, key.(crypto.Signer))}}, true},
|
||||
{"fail missing signer", args{[]Option{WithX509RootBundle(caPEM)}}, true},
|
||||
{"fail missing root file", args{[]Option{WithConfig(&Config{
|
||||
|
|
|
@ -75,13 +75,20 @@ type AuthConfig struct {
|
|||
Backdate *provisioner.Duration `json:"backdate,omitempty"`
|
||||
}
|
||||
|
||||
// defaultAuthConfig used when skipping validation.
|
||||
var defaultAuthConfig = &AuthConfig{
|
||||
Provisioners: provisioner.List{},
|
||||
Template: &x509util.ASN1DN{},
|
||||
Backdate: &provisioner.Duration{
|
||||
Duration: defaultBackdate,
|
||||
},
|
||||
// init initializes the required fields in the AuthConfig if they are not
|
||||
// provided.
|
||||
func (c *AuthConfig) init() {
|
||||
if c.Provisioners == nil {
|
||||
c.Provisioners = provisioner.List{}
|
||||
}
|
||||
if c.Template == nil {
|
||||
c.Template = &x509util.ASN1DN{}
|
||||
}
|
||||
if c.Backdate == nil {
|
||||
c.Backdate = &provisioner.Duration{
|
||||
Duration: defaultBackdate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates the authority configuration.
|
||||
|
@ -90,6 +97,9 @@ func (c *AuthConfig) Validate(audiences provisioner.Audiences) error {
|
|||
return errors.New("authority cannot be undefined")
|
||||
}
|
||||
|
||||
// Initialize required fields.
|
||||
c.init()
|
||||
|
||||
// Check that only one K8sSA is enabled
|
||||
var k8sCount int
|
||||
for _, p := range c.Provisioners {
|
||||
|
@ -101,16 +111,8 @@ func (c *AuthConfig) Validate(audiences provisioner.Audiences) error {
|
|||
return errors.New("cannot have more than one kubernetes service account provisioner")
|
||||
}
|
||||
|
||||
if c.Template == nil {
|
||||
c.Template = defaultAuthConfig.Template
|
||||
}
|
||||
|
||||
if c.Backdate != nil {
|
||||
if c.Backdate.Duration < 0 {
|
||||
return errors.New("authority.backdate cannot be less than 0")
|
||||
}
|
||||
} else {
|
||||
c.Backdate = defaultAuthConfig.Backdate
|
||||
if c.Backdate.Duration < 0 {
|
||||
return errors.New("authority.backdate cannot be less than 0")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -133,6 +135,21 @@ func LoadConfiguration(filename string) (*Config, error) {
|
|||
return &c, nil
|
||||
}
|
||||
|
||||
// initializes the minimal configuration required to create an authority. This
|
||||
// is mainly used on embedded authorities.
|
||||
func (c *Config) init() {
|
||||
if c.DNSNames == nil {
|
||||
c.DNSNames = []string{"localhost", "127.0.0.1", "::1"}
|
||||
}
|
||||
if c.TLS == nil {
|
||||
c.TLS = &DefaultTLSOptions
|
||||
}
|
||||
if c.AuthorityConfig == nil {
|
||||
c.AuthorityConfig = &AuthConfig{}
|
||||
}
|
||||
c.AuthorityConfig.init()
|
||||
}
|
||||
|
||||
// Save saves the configuration to the given filename.
|
||||
func (c *Config) Save(filename string) error {
|
||||
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
|
|
Loading…
Reference in a new issue