diff --git a/authority/authority.go b/authority/authority.go index a667cfa8..188633c3 100644 --- a/authority/authority.go +++ b/authority/authority.go @@ -73,7 +73,7 @@ type Authority struct { sshCAUserFederatedCerts []ssh.PublicKey sshCAHostFederatedCerts []ssh.PublicKey - // Do not re-initialize + // If true, do not re-initialize initOnce bool startTime time.Time @@ -91,8 +91,11 @@ type Authority struct { adminMutex sync.RWMutex - // Do Not initialize the authority + // If true, do not initialize the authority skipInit bool + + // If true, does not output initialization logs + quietInit bool } // Info contains information about the authority. @@ -600,10 +603,9 @@ func (a *Authority) init() error { return admin.WrapErrorISE(err, "error loading provisioners to initialize authority") } if len(provs) == 0 && !strings.EqualFold(a.config.AuthorityConfig.DeploymentType, "linked") { - var firstJWKProvisioner *linkedca.Provisioner if len(a.config.AuthorityConfig.Provisioners) > 0 { - log.Printf("Starting migration of provisioners") + a.initLogf("Starting migration of provisioners") // Existing provisioners detected; try migrating them to DB storage for _, p := range a.config.AuthorityConfig.Provisioners { lp, err := ProvisionerToLinkedca(p) @@ -619,9 +621,9 @@ func (a *Authority) init() error { // Mark the first JWK provisioner, so that it can be used for administration purposes if firstJWKProvisioner == nil && lp.Type == linkedca.Provisioner_JWK { firstJWKProvisioner = lp - log.Printf("Migrated JWK provisioner %q with admin permissions", p.GetName()) // TODO(hs): change the wording? + a.initLogf("Migrated JWK provisioner %q with admin permissions", p.GetName()) // TODO(hs): change the wording? } else { - log.Printf("Migrated %s provisioner %q", p.GetType(), p.GetName()) + a.initLogf("Migrated %s provisioner %q", p.GetType(), p.GetName()) } } @@ -630,7 +632,12 @@ func (a *Authority) init() error { // every error. The next time the CA runs, it won't have perform the migration, // because there'll be at least a JWK provisioner. - log.Printf("Finished migrating provisioners") + // 1. check if prerequisites for writing files look OK (user/group, permission bits, etc) + // 2. update the configuration to write (internal representation; do a deep copy first?) + // 3. try writing the new ca.json + // 4. on failure, perform rollback of the write (restore original in internal representation) + + a.initLogf("Finished migrating provisioners") } // Create first JWK provisioner for remote administration purposes if none exists yet @@ -639,7 +646,7 @@ func (a *Authority) init() error { if err != nil { return admin.WrapErrorISE(err, "error creating first provisioner") } - log.Printf("Created JWK provisioner %q with admin permissions", firstJWKProvisioner.GetName()) // TODO(hs): change the wording? + a.initLogf("Created JWK provisioner %q with admin permissions", firstJWKProvisioner.GetName()) // TODO(hs): change the wording? } // Create first super admin, belonging to the first JWK provisioner @@ -652,7 +659,7 @@ func (a *Authority) init() error { return admin.WrapErrorISE(err, "error creating first admin") } - log.Printf("Created super admin %q for JWK provisioner %q", firstSuperAdminSubject, firstJWKProvisioner.GetName()) + a.initLogf("Created super admin %q for JWK provisioner %q", firstSuperAdminSubject, firstJWKProvisioner.GetName()) } } @@ -702,6 +709,14 @@ func (a *Authority) init() error { return nil } +// initLogf is used to log initialization information. The output +// can be disabled by starting the CA with the `--quiet` flag. +func (a *Authority) initLogf(format string, v ...any) { + if !a.quietInit { + log.Printf(format, v...) + } +} + // GetID returns the define authority id or a zero uuid. func (a *Authority) GetID() string { const zeroUUID = "00000000-0000-0000-0000-000000000000" diff --git a/authority/options.go b/authority/options.go index f332d4a9..bf443ed6 100644 --- a/authority/options.go +++ b/authority/options.go @@ -86,6 +86,14 @@ func WithDatabase(d db.AuthDB) Option { } } +// WithQuietInit disables log output when the authority is initialized. +func WithQuietInit() Option { + return func(a *Authority) error { + a.quietInit = true + return nil + } +} + // WithWebhookClient sets the http.Client to be used for outbound requests. func WithWebhookClient(c *http.Client) Option { return func(a *Authority) error { diff --git a/ca/ca.go b/ca/ca.go index ab2aa8ac..98f845b0 100644 --- a/ca/ca.go +++ b/ca/ca.go @@ -156,6 +156,10 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) { opts = append(opts, authority.WithDatabase(ca.opts.database)) } + if ca.opts.quiet { + opts = append(opts, authority.WithQuietInit()) + } + webhookTransport := http.DefaultTransport.(*http.Transport).Clone() opts = append(opts, authority.WithWebhookClient(&http.Client{Transport: webhookTransport}))