// Bootstrap bootstraps the given environment. The supplied constraints are // used to provision the instance, and are also set within the bootstrapped // environment. func Bootstrap(ctx environs.BootstrapContext, environ environs.Environ, args environs.BootstrapParams) error { cfg := environ.Config() if secret := cfg.AdminSecret(); secret == "" { return fmt.Errorf("environment configuration has no admin-secret") } if authKeys := ssh.SplitAuthorisedKeys(cfg.AuthorizedKeys()); len(authKeys) == 0 { // Apparently this can never happen, so it's not tested. But, one day, // Config will act differently (it's pretty crazy that, AFAICT, the // authorized-keys are optional config settings... but it's impossible // to actually *create* a config without them)... and when it does, // we'll be here to catch this problem early. return fmt.Errorf("environment configuration has no authorized-keys") } if _, hasCACert := cfg.CACert(); !hasCACert { return fmt.Errorf("environment configuration has no ca-cert") } if _, hasCAKey := cfg.CAPrivateKey(); !hasCAKey { return fmt.Errorf("environment configuration has no ca-private-key") } // Write out the bootstrap-init file, and confirm storage is writeable. if err := environs.VerifyStorage(environ.Storage()); err != nil { return err } logger.Debugf("environment %q supports service/machine networks: %v", environ.Name(), environ.SupportNetworks()) logger.Infof("bootstrapping environment %q", environ.Name()) return environ.Bootstrap(ctx, args) }
// AddSSHAuthorizedKeys adds a set of keys in // ssh authorized_keys format (see ssh(8) for details) // that will be added to ~/.ssh/authorized_keys for the // configured user (see SetUser). func (cfg *Config) AddSSHAuthorizedKeys(keyData string) { akeys, _ := cfg.attrs["ssh_authorized_keys"].([]string) keys := ssh.SplitAuthorisedKeys(keyData) for _, key := range keys { // Ensure the key has a comment prepended with "Juju:" so we // can distinguish between Juju managed keys and those added // externally. jujuKey := ssh.EnsureJujuComment(key) akeys = append(akeys, jujuKey) } cfg.attrs["ssh_authorized_keys"] = akeys }
func (s *AuthorisedKeysKeysSuite) TestSplitAuthorisedKeys(c *gc.C) { sshKey := sshtesting.ValidKeyOne.Key for _, test := range []struct { keyData string expected []string }{ {"", nil}, {sshKey, []string{sshKey}}, {sshKey + "\n", []string{sshKey}}, {sshKey + "\n\n", []string{sshKey}}, {sshKey + "\n#comment\n", []string{sshKey}}, {sshKey + "\n #comment\n", []string{sshKey}}, {sshKey + "\ninvalid\n", []string{sshKey, "invalid"}}, } { actual := ssh.SplitAuthorisedKeys(test.keyData) c.Assert(actual, gc.DeepEquals, test.expected) } }
// AuthorisedKeys reports the authorised ssh keys for the specified machines. // The current implementation relies on global authorised keys being stored in the environment config. // This will change as new user management and authorisation functionality is added. func (api *KeyUpdaterAPI) AuthorisedKeys(arg params.Entities) (params.StringsResults, error) { if len(arg.Entities) == 0 { return params.StringsResults{}, nil } results := make([]params.StringsResult, len(arg.Entities)) // For now, authorised keys are global, common to all machines. var keys []string config, configErr := api.state.EnvironConfig() if configErr == nil { keys = ssh.SplitAuthorisedKeys(config.AuthorizedKeys()) } canRead, err := api.getCanRead() if err != nil { return params.StringsResults{}, err } for i, entity := range arg.Entities { // 1. Check permissions if !canRead(entity.Tag) { results[i].Error = common.ServerError(common.ErrPerm) continue } // 2. Check entity exists if _, err := api.state.FindEntity(entity.Tag); err != nil { if errors.IsNotFound(err) { results[i].Error = common.ServerError(common.ErrPerm) } else { results[i].Error = common.ServerError(err) } continue } // 3. Get keys var err error if configErr == nil { results[i].Result = keys } else { err = configErr } results[i].Error = common.ServerError(err) } return params.StringsResults{Results: results}, nil }