Fix docker user and write configuration to disk when setting user

This commit is contained in:
Dane Everitt 2019-04-06 16:03:02 -07:00
parent 6e2a442846
commit 94223bafec
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
3 changed files with 60 additions and 12 deletions

View File

@ -66,7 +66,14 @@ type SystemConfiguration struct {
Data string Data string
// The user that should own all of the server files, and be used for containers. // The user that should own all of the server files, and be used for containers.
User string Username string
// Definitions for the user that gets created to ensure that we can quickly access
// this information without constantly having to do a system lookup.
User struct {
Uid int
Gid int
}
// The path to the system's timezone file that will be mounted into running Docker containers. // The path to the system's timezone file that will be mounted into running Docker containers.
TimezonePath string `yaml:"timezone_path"` TimezonePath string `yaml:"timezone_path"`
@ -133,6 +140,7 @@ type ApiConfiguration struct {
// a tedious thing to have to do. // a tedious thing to have to do.
func (c *Configuration) SetDefaults() { func (c *Configuration) SetDefaults() {
c.System = &SystemConfiguration{ c.System = &SystemConfiguration{
Username: "pterodactyl",
Data: "/srv/daemon-data", Data: "/srv/daemon-data",
TimezonePath:"/etc/timezone", TimezonePath:"/etc/timezone",
} }
@ -198,12 +206,12 @@ func ReadConfiguration(path string) (*Configuration, error) {
// If files are not owned by this user there will be issues with permissions on Docker // If files are not owned by this user there will be issues with permissions on Docker
// mount points. // mount points.
func (c *Configuration) EnsurePterodactylUser() (*user.User, error) { func (c *Configuration) EnsurePterodactylUser() (*user.User, error) {
u, err := user.Lookup(c.System.User) u, err := user.Lookup(c.System.Username)
// If an error is returned but it isn't the unknown user error just abort // If an error is returned but it isn't the unknown user error just abort
// the process entirely. If we did find a user, return it immediately. // the process entirely. If we did find a user, return it immediately.
if err == nil { if err == nil {
return u, nil return u, c.setSystemUser(u)
} else if _, ok := err.(user.UnknownUserError); !ok { } else if _, ok := err.(user.UnknownUserError); !ok {
return nil, err return nil, err
} }
@ -213,16 +221,16 @@ func (c *Configuration) EnsurePterodactylUser() (*user.User, error) {
return nil, err return nil, err
} }
var command = fmt.Sprintf("useradd --system --no-create-home --shell /bin/false %s", c.System.User) var command = fmt.Sprintf("useradd --system --no-create-home --shell /bin/false %s", c.System.Username)
// Alpine Linux is the only OS we currently support that doesn't work with the useradd command, so // Alpine Linux is the only OS we currently support that doesn't work with the useradd command, so
// in those cases we just modify the command a bit to work as expected. // in those cases we just modify the command a bit to work as expected.
if strings.HasPrefix(sysName, "Alpine") { if strings.HasPrefix(sysName, "Alpine") {
command = fmt.Sprintf("adduser -S -D -H -G %[1]s -s /bin/false %[1]s", c.System.User) command = fmt.Sprintf("adduser -S -D -H -G %[1]s -s /bin/false %[1]s", c.System.Username)
// We have to create the group first on Alpine, so do that here before continuing on // We have to create the group first on Alpine, so do that here before continuing on
// to the user creation process. // to the user creation process.
if _, err := exec.Command("addgroup", "-s", c.System.User).Output(); err != nil { if _, err := exec.Command("addgroup", "-s", c.System.Username).Output(); err != nil {
return nil, err return nil, err
} }
} }
@ -232,7 +240,24 @@ func (c *Configuration) EnsurePterodactylUser() (*user.User, error) {
return nil, err return nil, err
} }
return user.Lookup(c.System.User) if u, err := user.Lookup(c.System.Username); err != nil {
return nil, err
} else {
return u, c.setSystemUser(u)
}
}
// Set the system user into the configuration and then write it to the disk so that
// it is persisted on boot.
func (c *Configuration) setSystemUser(u *user.User) error {
uid, _ := strconv.Atoi(u.Uid)
gid, _ := strconv.Atoi(u.Gid)
c.System.Username = u.Username
c.System.User.Uid = uid
c.System.User.Gid = gid
return c.WriteToDisk()
} }
// Ensures that the configured data directory has the correct permissions assigned to // Ensures that the configured data directory has the correct permissions assigned to
@ -251,7 +276,7 @@ func (c *Configuration) EnsureFilePermissions() error {
return err return err
} }
su, err := user.Lookup(c.System.User) su, err := user.Lookup(c.System.Username)
if err != nil { if err != nil {
return err return err
} }
@ -287,6 +312,28 @@ func (c *Configuration) EnsureFilePermissions() error {
return nil return nil
} }
// Writes the configuration to the disk as a blocking operation by obtaining an exclusive
// lock on the file. This prevents something else from writing at the exact same time and
// leading to bad data conditions.
func (c *Configuration) WriteToDisk() error {
f, err := os.OpenFile("config.yml", os.O_WRONLY, os.ModeExclusive)
if err != nil {
return err
}
defer f.Close()
b, err := yaml.Marshal(&c)
if err != nil {
return err
}
if _, err := f.Write(b); err != nil {
return err
}
return nil
}
// Gets the system release name. // Gets the system release name.
func getSystemName() (string, error) { func getSystemName() (string, error) {
cmd := exec.Command("lsb_release", "-is") cmd := exec.Command("lsb_release", "-is")

View File

@ -24,8 +24,8 @@ import (
type DockerEnvironment struct { type DockerEnvironment struct {
Server *Server Server *Server
// The user that containers should be running as. // The user ID that containers should be running as.
User string User int
// Defines the configuration for the Docker instance that will allow us to connect // Defines the configuration for the Docker instance that will allow us to connect
// and create and modify containers. // and create and modify containers.
@ -43,6 +43,7 @@ func NewDockerEnvironment(opts ...func(*DockerEnvironment)) (*DockerEnvironment,
} }
env := &DockerEnvironment{ env := &DockerEnvironment{
User: 1000,
Client: cli, Client: cli,
} }
@ -157,7 +158,7 @@ func (d *DockerEnvironment) Create() error {
conf := &container.Config{ conf := &container.Config{
Hostname: "container", Hostname: "container",
User: d.User, User: strconv.Itoa(d.User),
AttachStdin: true, AttachStdin: true,
AttachStdout: true, AttachStdout: true,
AttachStderr: true, AttachStderr: true,

View File

@ -171,7 +171,7 @@ func FromConfiguration(data []byte, cfg *config.SystemConfiguration) (*Server, e
} }
withConfiguration := func (e *DockerEnvironment) { withConfiguration := func (e *DockerEnvironment) {
e.User = cfg.User e.User = cfg.User.Uid
e.TimezonePath = cfg.TimezonePath e.TimezonePath = cfg.TimezonePath
e.Server = s e.Server = s
} }