// NewNetworkerAPI creates a new server-side Networker API facade. func NewNetworkerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*NetworkerAPI, error) { if !authorizer.AuthMachineAgent() { return nil, common.ErrPerm } getAuthFunc := func() (common.AuthFunc, error) { authEntityTag := authorizer.GetAuthTag() return func(tag names.Tag) bool { if tag == authEntityTag { // A machine agent can always access its own machine. return true } if _, ok := tag.(names.MachineTag); !ok { // Only machine tags are allowed. return false } id := tag.Id() for parentId := state.ParentId(id); parentId != ""; parentId = state.ParentId(parentId) { // Until a top-level machine is reached. // TODO (thumper): remove the names.Tag conversion when gccgo // implements concrete-type-to-interface comparison correctly. if names.Tag(names.NewMachineTag(parentId)) == authEntityTag { // All containers with the authenticated machine as a // parent are accessible by it. return true } } // Not found authorized machine agent among ancestors of the current one. return false }, nil } return &NetworkerAPI{ st: st, resources: resources, authorizer: authorizer, getAuthFunc: getAuthFunc, }, nil }
// NewKeyManagerAPI creates a new server-side keyupdater API end point. func NewKeyManagerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*KeyManagerAPI, error) { // Only clients and environment managers can access the key manager service. if !authorizer.AuthClient() && !authorizer.AuthEnvironManager() { return nil, common.ErrPerm } env, err := st.Environment() if err != nil { return nil, errors.Trace(err) } // For gccgo interface comparisons, we need a Tag. owner := names.Tag(env.Owner()) // TODO(wallyworld) - replace stub with real canRead function // For now, only admins can read authorised ssh keys. canRead := func(user string) bool { // Are we a machine agent operating as the system identity? if user == config.JujuSystemKey { _, ismachinetag := authorizer.GetAuthTag().(names.MachineTag) return ismachinetag } return authorizer.GetAuthTag() == owner } // TODO(wallyworld) - replace stub with real canWrite function // For now, only admins can write authorised ssh keys for users. // Machine agents can write the juju-system-key. canWrite := func(user string) bool { // Are we a machine agent writing the Juju system key. if user == config.JujuSystemKey { _, ismachinetag := authorizer.GetAuthTag().(names.MachineTag) return ismachinetag } // No point looking to see if the user exists as we are not // yet storing keys on the user. return authorizer.GetAuthTag() == owner } return &KeyManagerAPI{ state: st, resources: resources, authorizer: authorizer, canRead: canRead, canWrite: canWrite, check: common.NewBlockChecker(st), }, nil }
// NewDeployerAPI creates a new server-side DeployerAPI facade. func NewDeployerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*DeployerAPI, error) { if !authorizer.AuthMachineAgent() { return nil, common.ErrPerm } getAuthFunc := func() (common.AuthFunc, error) { // Get all units of the machine and cache them. thisMachineTag := authorizer.GetAuthTag() units, err := getAllUnits(st, thisMachineTag) if err != nil { return nil, err } // Then we just check if the unit is already known. return func(tag names.Tag) bool { for _, unit := range units { // TODO (thumper): remove the names.Tag conversion when gccgo // implements concrete-type-to-interface comparison correctly. if names.Tag(names.NewUnitTag(unit)) == tag { return true } } return false }, nil } getCanWatch := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } return &DeployerAPI{ Remover: common.NewRemover(st, true, getAuthFunc), PasswordChanger: common.NewPasswordChanger(st, getAuthFunc), LifeGetter: common.NewLifeGetter(st, getAuthFunc), StateAddresser: common.NewStateAddresser(st), APIAddresser: common.NewAPIAddresser(st, resources), UnitsWatcher: common.NewUnitsWatcher(st, resources, getCanWatch), st: st, resources: resources, authorizer: authorizer, }, nil }