mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-05-06 08:15:48 -04:00
constellation-access-manager: Persistent SSH as ConfigMap (#184)
This commit is contained in:
parent
1e19e64fbc
commit
f0b8412ef8
31 changed files with 1162 additions and 78 deletions
|
@ -13,20 +13,24 @@ import (
|
|||
// ErrUserDoesNotExist is returned by GetLinuxUser if a linux user does not exist yet.
|
||||
var ErrUserDoesNotExist = errors.New("user does not exist")
|
||||
|
||||
// ErrUserOrGroupAlreadyExists is the Go error converted from the result of useradd or groupadd when an user or group already exists.
|
||||
var ErrUserOrGroupAlreadyExists = errors.New("user or group already exists")
|
||||
|
||||
type passwdParser interface {
|
||||
Parse(fs afero.Fs) (Entries, error)
|
||||
}
|
||||
|
||||
type userCreator interface {
|
||||
CreateUser(ctx context.Context, username string) error
|
||||
CreateUserWithSpecificUIDAndGID(ctx context.Context, username string, uid int, gid int) error
|
||||
}
|
||||
|
||||
// LinuxUser holds relevant information about a linux user (subset of /etc/passwd).
|
||||
type LinuxUser struct {
|
||||
Username string
|
||||
Home string
|
||||
Uid int
|
||||
Gid int
|
||||
UID int
|
||||
GID int
|
||||
}
|
||||
|
||||
// LinuxUserManager can retrieve information on linux users and create new users.
|
||||
|
@ -58,13 +62,16 @@ func NewLinuxUserManagerFake(fs afero.Fs) LinuxUserManager {
|
|||
type StubUserCreator struct {
|
||||
fs afero.Fs
|
||||
usernames []string
|
||||
uids []int
|
||||
createUserErr error
|
||||
currentUID int
|
||||
}
|
||||
|
||||
// CreateUser for StubUserCreator creates an user for an unit test environment.
|
||||
func (s *StubUserCreator) CreateUser(ctx context.Context, username string) error {
|
||||
if stringInSlice(username, s.usernames) {
|
||||
return errors.New("username already exists")
|
||||
// do not fail if user already exists
|
||||
return nil
|
||||
}
|
||||
|
||||
// We want created users to start at UID 1000
|
||||
|
@ -78,7 +85,7 @@ func (s *StubUserCreator) CreateUser(ctx context.Context, username string) error
|
|||
|
||||
// If no predefined error is supposed to happen, increase the UID (unless the file system code fails)
|
||||
if s.fs != nil {
|
||||
lineToWrite := fmt.Sprintf("%s:x:%d:%d:%s:/home/%s:/bin/bash\n", username, s.currentUID, s.currentUID, username, username)
|
||||
lineToWrite := fmt.Sprintf("%s:x:%d:%d:%s:/var/home/%s:/bin/bash\n", username, s.currentUID, s.currentUID, username, username)
|
||||
file, err := s.fs.OpenFile("/etc/passwd", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -94,14 +101,59 @@ func (s *StubUserCreator) CreateUser(ctx context.Context, username string) error
|
|||
}
|
||||
}
|
||||
|
||||
s.currentUID += 1
|
||||
s.currentUID++
|
||||
s.usernames = append(s.usernames, username)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getLinuxUser tries to find an existing linux user in /etc/passwd.
|
||||
func (l *LinuxUserManager) getLinuxUser(username string) (LinuxUser, error) {
|
||||
// CreateUserWithSpecificUIDAndGID for StubUserCreator creates an user with a specific UID and GID for an unit test environment.
|
||||
func (s *StubUserCreator) CreateUserWithSpecificUIDAndGID(ctx context.Context, username string, uid int, gid int) error {
|
||||
if stringInSlice(username, s.usernames) {
|
||||
// do not fail if user already exists
|
||||
return nil
|
||||
}
|
||||
if intInSlice(uid, s.uids) {
|
||||
return errors.New("uid is already used by another user")
|
||||
}
|
||||
|
||||
if s.createUserErr != nil {
|
||||
return s.createUserErr
|
||||
}
|
||||
|
||||
// If no predefined error is supposed to happen, increase the UID (unless the file system code fails)
|
||||
if s.fs != nil {
|
||||
lineToWrite := fmt.Sprintf("%s:x:%d:%d:%s:/var/home/%s:/bin/bash\n", username, uid, gid, username, username)
|
||||
file, err := s.fs.OpenFile("/etc/passwd", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
n, err := file.WriteString(lineToWrite)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if n != len(lineToWrite) {
|
||||
return errors.New("written text too short")
|
||||
}
|
||||
}
|
||||
|
||||
// Mark UID as used (we don't track GIDs though, as multiple users can belong to one GID)
|
||||
s.uids = append(s.uids, uid)
|
||||
|
||||
// Avoid potential collisions
|
||||
if s.currentUID == uid {
|
||||
s.currentUID++
|
||||
}
|
||||
|
||||
s.usernames = append(s.usernames, username)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLinuxUser tries to find an existing linux user in /etc/passwd.
|
||||
func (l *LinuxUserManager) GetLinuxUser(username string) (LinuxUser, error) {
|
||||
entries, err := l.Passwd.Parse(l.Fs)
|
||||
if err != nil {
|
||||
return LinuxUser{}, err
|
||||
|
@ -121,19 +173,19 @@ func (l *LinuxUserManager) getLinuxUser(username string) (LinuxUser, error) {
|
|||
return LinuxUser{
|
||||
Username: username,
|
||||
Home: entry.Home,
|
||||
Uid: uid,
|
||||
Gid: gid,
|
||||
UID: uid,
|
||||
GID: gid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// EnsureLinuxUserExists will try to create the user specified by username and call GetLinuxUser to retrieve user information.
|
||||
func (l *LinuxUserManager) EnsureLinuxUserExists(ctx context.Context, username string) (LinuxUser, error) {
|
||||
// try to create user (even if it already exists)
|
||||
if err := l.Creator.CreateUser(ctx, username); err != nil {
|
||||
if err := l.Creator.CreateUser(ctx, username); err != nil && !errors.Is(err, ErrUserOrGroupAlreadyExists) {
|
||||
return LinuxUser{}, err
|
||||
}
|
||||
|
||||
return l.getLinuxUser(username)
|
||||
return l.GetLinuxUser(username)
|
||||
}
|
||||
|
||||
// stringInSlice checks if a given string exists in a slice of strings.
|
||||
|
@ -145,3 +197,13 @@ func stringInSlice(a string, list []string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// intInSlice checks if a given string exists in a slice of strings.
|
||||
func intInSlice(a int, list []int) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue