access.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. package localapi
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. )
  7. // Access is who may reach a socket beyond the account nebula runs as: the node's mode,
  8. // and the group that shares the socket when the config names one.
  9. //
  10. // It is the dockerd model (-G): the operator names a group, nebula hands the socket to
  11. // it, and who is in the group is managed outside nebula. On unix the mode is the
  12. // socket node's and the group becomes its owning group; on windows the group is an
  13. // entry in the pipe's security descriptor and the mode means nothing to a pipe.
  14. type Access struct {
  15. Mode os.FileMode
  16. Group *Group
  17. }
  18. // Group is a group named in the config, resolved to what the platform checks.
  19. type Group struct {
  20. // Name is what the config said.
  21. Name string
  22. // ID is the platform's identifier for it: a gid on unix, a SID on windows.
  23. ID string
  24. }
  25. // groupSocketMode is the mode a socket takes when a group shares it and the config
  26. // names no other: the account nebula runs as and the group, and nobody else.
  27. const groupSocketMode os.FileMode = 0660
  28. // errReopenForAccess is returned by applyAccess on a platform whose access control is
  29. // fixed when the endpoint is created, so a change means creating it again.
  30. var errReopenForAccess = errors.New("access is fixed at listen time")
  31. // ownerOnly is the control socket's access when no group is configured: the account
  32. // nebula runs as, and nobody else.
  33. func ownerOnly() Access { return Access{Mode: ctlSocketMode} }
  34. // String renders the access for a log line.
  35. func (a Access) String() string {
  36. if a.Group == nil {
  37. return modeString(a.Mode)
  38. }
  39. return fmt.Sprintf("%s group %s (%s)", modeString(a.Mode), a.Group.Name, a.Group.ID)
  40. }
  41. func (a Access) equal(b Access) bool {
  42. if a.Mode != b.Mode || (a.Group == nil) != (b.Group == nil) {
  43. return false
  44. }
  45. return a.Group == nil || a.Group.ID == b.Group.ID
  46. }
  47. // groupFromConfig reads the group a key names, or nil when it names none. The name is
  48. // resolved here, when the config is read, so a group that does not exist is a config
  49. // error reported with the key rather than a bind that fails later.
  50. func groupFromConfig(c interface{ GetString(string, string) string }, key string) (*Group, error) {
  51. name := c.GetString(key, "")
  52. if name == "" {
  53. return nil, nil
  54. }
  55. id, err := lookupGroupID(name)
  56. if err != nil {
  57. return nil, fmt.Errorf("%s: %w", key, err)
  58. }
  59. return &Group{Name: name, ID: id}, nil
  60. }
  61. func modeString(m os.FileMode) string {
  62. return fmt.Sprintf("%04o", m)
  63. }