github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/keyupdater/authorisedkeys.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package keyupdater 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/utils/ssh" 9 "gopkg.in/juju/names.v2" 10 11 "github.com/juju/juju/apiserver/common" 12 "github.com/juju/juju/apiserver/facade" 13 "github.com/juju/juju/apiserver/params" 14 "github.com/juju/juju/state" 15 "github.com/juju/juju/state/watcher" 16 ) 17 18 func init() { 19 common.RegisterStandardFacade("KeyUpdater", 1, NewKeyUpdaterAPI) 20 } 21 22 // KeyUpdater defines the methods on the keyupdater API end point. 23 type KeyUpdater interface { 24 AuthorisedKeys(args params.Entities) (params.StringsResults, error) 25 WatchAuthorisedKeys(args params.Entities) (params.NotifyWatchResults, error) 26 } 27 28 // KeyUpdaterAPI implements the KeyUpdater interface and is the concrete 29 // implementation of the api end point. 30 type KeyUpdaterAPI struct { 31 state *state.State 32 resources facade.Resources 33 authorizer facade.Authorizer 34 getCanRead common.GetAuthFunc 35 } 36 37 var _ KeyUpdater = (*KeyUpdaterAPI)(nil) 38 39 // NewKeyUpdaterAPI creates a new server-side keyupdater API end point. 40 func NewKeyUpdaterAPI( 41 st *state.State, 42 resources facade.Resources, 43 authorizer facade.Authorizer, 44 ) (*KeyUpdaterAPI, error) { 45 // Only machine agents have access to the keyupdater service. 46 if !authorizer.AuthMachineAgent() { 47 return nil, common.ErrPerm 48 } 49 // No-one else except the machine itself can only read a machine's own credentials. 50 getCanRead := func() (common.AuthFunc, error) { 51 return authorizer.AuthOwner, nil 52 } 53 return &KeyUpdaterAPI{state: st, resources: resources, authorizer: authorizer, getCanRead: getCanRead}, nil 54 } 55 56 // WatchAuthorisedKeys starts a watcher to track changes to the authorised ssh keys 57 // for the specified machines. 58 // The current implementation relies on global authorised keys being stored in the environment config. 59 // This will change as new user management and authorisation functionality is added. 60 func (api *KeyUpdaterAPI) WatchAuthorisedKeys(arg params.Entities) (params.NotifyWatchResults, error) { 61 results := make([]params.NotifyWatchResult, len(arg.Entities)) 62 63 canRead, err := api.getCanRead() 64 if err != nil { 65 return params.NotifyWatchResults{}, err 66 } 67 for i, entity := range arg.Entities { 68 tag, err := names.ParseTag(entity.Tag) 69 if err != nil { 70 results[i].Error = common.ServerError(err) 71 continue 72 } 73 // 1. Check permissions 74 if !canRead(tag) { 75 results[i].Error = common.ServerError(common.ErrPerm) 76 continue 77 } 78 // 2. Check entity exists 79 if _, err := api.state.FindEntity(tag); err != nil { 80 if errors.IsNotFound(err) { 81 results[i].Error = common.ServerError(common.ErrPerm) 82 } else { 83 results[i].Error = common.ServerError(err) 84 } 85 continue 86 } 87 // 3. Watch for changes 88 watch := api.state.WatchForModelConfigChanges() 89 // Consume the initial event. 90 if _, ok := <-watch.Changes(); ok { 91 results[i].NotifyWatcherId = api.resources.Register(watch) 92 } else { 93 err = watcher.EnsureErr(watch) 94 } 95 results[i].Error = common.ServerError(err) 96 } 97 return params.NotifyWatchResults{Results: results}, nil 98 } 99 100 // AuthorisedKeys reports the authorised ssh keys for the specified machines. 101 // The current implementation relies on global authorised keys being stored in the environment config. 102 // This will change as new user management and authorisation functionality is added. 103 func (api *KeyUpdaterAPI) AuthorisedKeys(arg params.Entities) (params.StringsResults, error) { 104 if len(arg.Entities) == 0 { 105 return params.StringsResults{}, nil 106 } 107 results := make([]params.StringsResult, len(arg.Entities)) 108 109 // For now, authorised keys are global, common to all machines. 110 var keys []string 111 config, configErr := api.state.ModelConfig() 112 if configErr == nil { 113 keys = ssh.SplitAuthorisedKeys(config.AuthorizedKeys()) 114 } 115 116 canRead, err := api.getCanRead() 117 if err != nil { 118 return params.StringsResults{}, err 119 } 120 for i, entity := range arg.Entities { 121 tag, err := names.ParseTag(entity.Tag) 122 if err != nil { 123 results[i].Error = common.ServerError(err) 124 continue 125 } 126 // 1. Check permissions 127 if !canRead(tag) { 128 results[i].Error = common.ServerError(common.ErrPerm) 129 continue 130 } 131 // 2. Check entity exists 132 if _, err := api.state.FindEntity(tag); err != nil { 133 if errors.IsNotFound(err) { 134 results[i].Error = common.ServerError(common.ErrPerm) 135 } else { 136 results[i].Error = common.ServerError(err) 137 } 138 continue 139 } 140 // 3. Get keys 141 if configErr == nil { 142 results[i].Result = keys 143 } else { 144 err = configErr 145 } 146 results[i].Error = common.ServerError(err) 147 } 148 return params.StringsResults{Results: results}, nil 149 }