// New returns a new worker that maintains the mongo replica set // with respect to the given state. func New(st *state.State, supportsSpaces bool) (worker.Worker, error) { cfg, err := st.ControllerConfig() if err != nil { return nil, err } shim := &stateShim{ State: st, mongoPort: cfg.StatePort(), apiPort: cfg.APIPort(), } return newWorker(shim, newPublisher(st), supportsSpaces) }
// newExternalMacaroonAuth returns an authenticator that can authenticate // macaroon-based logins for external users. This is just a helper function // for authCtxt.externalMacaroonAuth. func newExternalMacaroonAuth(st *state.State) (*authentication.ExternalMacaroonAuthenticator, error) { controllerCfg, err := st.ControllerConfig() if err != nil { return nil, errors.Annotate(err, "cannot get model config") } idURL := controllerCfg.IdentityURL() if idURL == "" { return nil, errMacaroonAuthNotConfigured } // The identity server has been configured, // so configure the bakery service appropriately. idPK := controllerCfg.IdentityPublicKey() if idPK == nil { // No public key supplied - retrieve it from the identity manager. idPK, err = httpbakery.PublicKeyForLocation(http.DefaultClient, idURL) if err != nil { return nil, errors.Annotate(err, "cannot get identity public key") } } // We pass in nil for the storage, which leads to in-memory storage // being used. We only use in-memory storage for now, since we never // expire the keys, and don't want garbage to accumulate. // // TODO(axw) we should store the key in mongo, so that multiple servers // can authenticate. That will require that we encode the server's ID // in the macaroon ID so that servers don't overwrite each others' keys. svc, _, err := newBakeryService(st, nil, bakery.PublicKeyLocatorMap{idURL: idPK}) if err != nil { return nil, errors.Annotate(err, "cannot make bakery service") } var auth authentication.ExternalMacaroonAuthenticator auth.Service = svc auth.Macaroon, err = svc.NewMacaroon("api-login", nil, nil) if err != nil { return nil, errors.Annotate(err, "cannot make macaroon") } auth.IdentityLocation = idURL return &auth, nil }
func (a *MachineAgent) newApiserverWorker(st *state.State, certChanged chan params.StateServingInfo) (worker.Worker, error) { agentConfig := a.CurrentConfig() // If the configuration does not have the required information, // it is currently not a recoverable error, so we kill the whole // agent, potentially enabling human intervention to fix // the agent's configuration file. info, ok := agentConfig.StateServingInfo() if !ok { return nil, &cmdutil.FatalError{"StateServingInfo not available and we need it"} } cert := []byte(info.Cert) key := []byte(info.PrivateKey) if len(cert) == 0 || len(key) == 0 { return nil, &cmdutil.FatalError{"configuration does not have controller cert/key"} } tag := agentConfig.Tag() dataDir := agentConfig.DataDir() logDir := agentConfig.LogDir() endpoint := net.JoinHostPort("", strconv.Itoa(info.APIPort)) listener, err := net.Listen("tcp", endpoint) if err != nil { return nil, err } // TODO(katco): We should be doing something more serious than // logging audit errors. Failures in the auditing systems should // stop the api server until the problem can be corrected. auditErrorHandler := func(err error) { logger.Criticalf("%v", err) } controllerConfig, err := st.ControllerConfig() if err != nil { return nil, errors.Annotate(err, "cannot fetch the controller config") } server, err := apiserver.NewServer(st, listener, apiserver.ServerConfig{ Clock: clock.WallClock, Cert: cert, Key: key, Tag: tag, DataDir: dataDir, LogDir: logDir, Validator: a.limitLogins, CertChanged: certChanged, NewObserver: newObserverFn( controllerConfig, clock.WallClock, jujuversion.Current, agentConfig.Model().Id(), newAuditEntrySink(st, logDir), auditErrorHandler, ), }) if err != nil { return nil, errors.Annotate(err, "cannot start api server worker") } return server, nil }