Replace logging with default logging interface (#233)

* Add test logger

* Refactor access manager logging

* Refactor activation service logging

* Refactor debugd logging

* Refactor kms server logging

* Refactor disk-mapper logging

Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
Daniel Weiße 2022-06-28 16:51:30 +02:00 committed by GitHub
parent e3f78a5bff
commit b10b13b173
42 changed files with 513 additions and 328 deletions

View file

@ -2,8 +2,8 @@ package main
import (
"context"
"errors"
"fmt"
"log"
"os"
"path"
"path/filepath"
@ -12,7 +12,10 @@ import (
"github.com/edgelesssys/constellation/internal/deploy/ssh"
"github.com/edgelesssys/constellation/internal/deploy/user"
"github.com/edgelesssys/constellation/internal/logger"
"github.com/spf13/afero"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
v1 "k8s.io/api/core/v1"
v1Options "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -30,7 +33,7 @@ const (
// evictedHomePath holds the directory to which deleted user directories are moved to.
evictedHomePath = "/var/evicted"
// relativePathToSSHKeys holds the path inside an user's directory to the SSH keys.
// relativePathToSSHKeys holds the path inside a user's directory to the SSH keys.
// Needs to be in sync with internal/deploy/ssh.go.
relativePathToSSHKeys = ".ssh/authorized_keys.d/constellation-ssh-keys"
@ -45,33 +48,35 @@ type uidGIDPair struct {
}
func main() {
log := logger.New(logger.JSONLog, zapcore.InfoLevel)
hostname, err := os.Hostname()
if err != nil {
log.Println("Starting constellation-access-manager as unknown pod.")
log.Warnf("Starting constellation-access-manager as unknown pod")
} else {
log.Println("Starting constellation-access-manager as", hostname)
log.Infof("Starting constellation-access-manager as %q", hostname)
}
// Retrieve configMap from Kubernetes API before we chroot into the host filesystem.
configMap, err := retrieveConfigMap()
configMap, err := retrieveConfigMap(log)
if err != nil {
log.Panicf("Failed to retrieve ConfigMap from Kubernetes API: %v", err)
log.With(zap.Error(err)).Fatalf("Failed to retrieve ConfigMap from Kubernetes API")
}
// Chroot into main system
if err := syscall.Chroot(hostPath); err != nil {
log.Panicf("Failed to chroot into host filesystem: %v", err)
log.With(zap.Error(err)).Fatalf("Failed to chroot into host filesystem")
}
if err := syscall.Chdir("/"); err != nil {
log.Panicf("Failed to chdir into host filesystem: %v", err)
log.With(zap.Error(err)).Fatalf("Failed to chdir into host filesystem")
}
fs := afero.NewOsFs()
linuxUserManager := user.NewLinuxUserManager(fs)
if err := run(fs, linuxUserManager, configMap); err != nil {
if err := run(log, fs, linuxUserManager, configMap); err != nil {
// So far there is only one error path in this code, and this is getting the user directories... So just make the error specific here for now.
log.Panicf("Failed to retrieve existing user directories: %v", err)
log.With(zap.Error(err)).Fatalf("Failed to retrieve existing user directories")
}
}
@ -92,21 +97,28 @@ func loadClientSet() (*kubernetes.Clientset, error) {
}
// deployKeys creates or evicts users based on the ConfigMap and deploy their SSH keys.
func deployKeys(ctx context.Context, configMap *v1.ConfigMap, fs afero.Fs, linuxUserManager user.LinuxUserManager, userMap map[string]uidGIDPair, sshAccess *ssh.Access) {
func deployKeys(
ctx context.Context, log *logger.Logger, configMap *v1.ConfigMap, fs afero.Fs,
linuxUserManager user.LinuxUserManager, userMap map[string]uidGIDPair, sshAccess *ssh.Access,
) {
// If no ConfigMap exists or has been emptied, evict all users and exit.
if configMap == nil || len(configMap.Data) == 0 {
for username, ownership := range userMap {
log := log.With(zap.String("username", username))
if username != "root" {
evictedUserPath := path.Join(evictedHomePath, username)
log.Printf("Evicting '%s' with previous UID '%d' and GID '%d' to %s.\n", username, ownership.UID, ownership.GID, evictedUserPath)
log.With(zap.Uint32("UID", ownership.UID), zap.Uint32("GID", ownership.GID)).
Infof("Evicting user to %q", evictedUserPath)
if err := evictUser(username, fs, linuxUserManager); err != nil {
log.Printf("Did not evict '%s': %v\n", username, err)
log.With(zap.Error(err)).Errorf("Did not evict user")
continue
}
} else {
log.Infof("Removing any old keys for 'root', if existent")
// Remove root's SSH key specifically instead of evicting the whole directory.
if err := evictRootKey(fs, linuxUserManager); err != nil && !os.IsNotExist(err) {
log.Printf("Failed to remove previously existing root key: %v\n", err)
log.With(zap.Error(err)).Errorf("Failed to remove previously existing root key")
continue
}
}
@ -118,25 +130,36 @@ func deployKeys(ctx context.Context, configMap *v1.ConfigMap, fs afero.Fs, linux
// First, recreate users that already existed, if they are defined in the configMap.
// For users which do not exist, we move their user directories to avoid accidental takeovers but also loss of data.
for username, ownership := range userMap {
log := log.With(zap.String("username", username))
if username != "root" {
if _, ok := configMap.Data[username]; ok {
log.Printf("Recreating '%s' with UID %d and GID %d, if not existent.\n", username, ownership.UID, ownership.GID)
if err := linuxUserManager.Creator.CreateUserWithSpecificUIDAndGID(ctx, username, int(ownership.UID), int(ownership.GID)); err != nil {
log.Printf("Did not recreate '%s': %v\n", username, err)
log.With(zap.Uint32("UID", ownership.UID), zap.Uint32("GID", ownership.GID)).
Infof("Recreating user, if not existent")
if err := linuxUserManager.Creator.CreateUserWithSpecificUIDAndGID(
ctx, username, int(ownership.UID), int(ownership.GID),
); err != nil {
if errors.Is(err, user.ErrUserOrGroupAlreadyExists) {
log.Infof("User already exists, skipping")
} else {
log.With(zap.Error(err)).Errorf("Failed to recreate user")
}
continue
}
} else {
evictedUserPath := path.Join(evictedHomePath, username)
log.Printf("Evicting '%s' with previous UID '%d' and GID '%d' to %s.\n", username, ownership.UID, ownership.GID, evictedUserPath)
log.With(zap.Uint32("UID", ownership.UID), zap.Uint32("GID", ownership.GID)).
Infof("Evicting user to %q", evictedUserPath)
if err := evictUser(username, fs, linuxUserManager); err != nil {
log.Printf("Did not to evict '%s': %v\n", username, err)
log.With(zap.Error(err)).Errorf("Did not evict user")
continue
}
}
} else {
log.Infof("Removing any old keys for 'root', if existent")
// Always remove the root key first, even if it is about to be redeployed.
if err := evictRootKey(fs, linuxUserManager); err != nil && !os.IsNotExist(err) {
log.Printf("Failed to remove previously existing root key: %v\n", err)
log.With(zap.Error(err)).Errorf("Failed to remove previously existing root key")
continue
}
}
@ -144,25 +167,30 @@ func deployKeys(ctx context.Context, configMap *v1.ConfigMap, fs afero.Fs, linux
// Then, create the remaining users from the configMap (if remaining) and deploy SSH keys for all users.
for username, publicKey := range configMap.Data {
log := log.With(zap.String("username", username))
if _, ok := userMap[username]; !ok {
log.Printf("Creating user '%s'\n", username)
log.Infof("Creating user")
if err := linuxUserManager.Creator.CreateUser(ctx, username); err != nil {
log.Printf("Failed to create '%s': %v\n", username, err)
if errors.Is(err, user.ErrUserOrGroupAlreadyExists) {
log.Infof("User already exists, skipping")
} else {
log.With(zap.Error(err)).Errorf("Failed to create user")
}
continue
}
}
// If we created an user, let's actually get the home directory instead of assuming it's the same as the normal home directory.
// If we created a user, let's actually get the home directory instead of assuming it's the same as the normal home directory.
user, err := linuxUserManager.GetLinuxUser(username)
if err != nil {
log.Printf("Failed to retrieve information about user '%s': %v\n", username, err)
log.With(zap.Error(err)).Errorf("Failed to retrieve information about user")
continue
}
// Delete already deployed keys
pathToSSHKeys := filepath.Join(user.Home, relativePathToSSHKeys)
if err := fs.Remove(pathToSSHKeys); err != nil && !os.IsNotExist(err) {
log.Printf("Failed to delete remaining managed SSH keys for '%s': %v\n", username, err)
log.With(zap.Error(err)).Errorf("Failed to delete remaining managed SSH keys for user")
continue
}
@ -172,15 +200,15 @@ func deployKeys(ctx context.Context, configMap *v1.ConfigMap, fs afero.Fs, linux
PublicKey: publicKey,
}
log.Printf("Deploying new SSH key for '%s'.\n", username)
log.Infof("Deploying new SSH key for user")
if err := sshAccess.DeployAuthorizedKey(context.Background(), newKey); err != nil {
log.Printf("Failed to deploy SSH keys for '%s': %v\n", username, err)
log.With(zap.Error(err)).Errorf("Failed to deploy SSH keys for user")
continue
}
}
}
// evictUser moves an user directory to evictedPath and changes their owner recursive to root.
// evictUser moves a user directory to evictedPath and changes their owner recursive to root.
func evictUser(username string, fs afero.Fs, linuxUserManager user.LinuxUserManager) error {
if _, err := linuxUserManager.GetLinuxUser(username); err == nil {
return fmt.Errorf("user '%s' still seems to exist", username)
@ -219,7 +247,6 @@ func evictUser(username string, fs afero.Fs, linuxUserManager user.LinuxUserMana
// evictRootKey removes the root key from the filesystem, instead of evicting the whole user directory.
func evictRootKey(fs afero.Fs, linuxUserManager user.LinuxUserManager) error {
log.Println("Removing any old keys for 'root', if existent.")
user, err := linuxUserManager.GetLinuxUser("root")
if err != nil {
return err
@ -235,9 +262,9 @@ func evictRootKey(fs afero.Fs, linuxUserManager user.LinuxUserManager) error {
}
// retrieveConfigMap contacts the Kubernetes API server and retrieves the ssh-users ConfigMap.
func retrieveConfigMap() (*v1.ConfigMap, error) {
func retrieveConfigMap(log *logger.Logger) (*v1.ConfigMap, error) {
// Authenticate with the Kubernetes API and get the information from the ssh-users ConfigMap to recreate the users we need.
log.Println("Authenticating with Kubernetes...")
log.Infof("Authenticating with Kubernetes...")
clientset, err := loadClientSet()
if err != nil {
return nil, err
@ -246,7 +273,7 @@ func retrieveConfigMap() (*v1.ConfigMap, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
log.Println("Requesting 'ssh-users' ConfigMap...")
log.Infof("Requesting 'ssh-users' ConfigMap...")
configmap, err := clientset.CoreV1().ConfigMaps("kube-system").Get(ctx, "ssh-users", v1Options.GetOptions{})
if err != nil {
return nil, err
@ -256,7 +283,7 @@ func retrieveConfigMap() (*v1.ConfigMap, error) {
}
// generateUserMap iterates the list of existing home directories to create a map of previously existing usernames to their previous respective UID and GID.
func generateUserMap(fs afero.Fs) (map[string]uidGIDPair, error) {
func generateUserMap(log *logger.Logger, fs afero.Fs) (map[string]uidGIDPair, error) {
// Go through the normalHomePath directory, and create a mapping of existing user names in combination with their owner's UID & GID.
// We use this information later to create missing users under the same UID and GID to avoid breakage.
fileInfo, err := afero.ReadDir(fs, normalHomePath)
@ -268,12 +295,14 @@ func generateUserMap(fs afero.Fs) (map[string]uidGIDPair, error) {
userMap["root"] = uidGIDPair{UID: 0, GID: 0}
// This will fail under MemMapFS, since it's not UNIX-compatible.
for _, singleInfo := range fileInfo {
log := log.With("username", singleInfo.Name())
// Fail gracefully instead of hard.
if stat, ok := singleInfo.Sys().(*syscall.Stat_t); ok {
userMap[singleInfo.Name()] = uidGIDPair{UID: stat.Uid, GID: stat.Gid}
log.Printf("Found home directory for '%s' (%d:%d).\n", singleInfo.Name(), stat.Uid, stat.Gid)
log.With(zap.Uint32("UID", stat.Uid), zap.Uint32("GID", stat.Gid)).
Infof("Found home directory for user")
} else {
log.Printf("WARNING: Failed to retrieve UNIX stat for %s. User will not be evicted, or if this directory belongs to an user that is to be created later, it might be created under a different UID/GID than before.\n", singleInfo.Name())
log.Warnf("Failed to retrieve UNIX stat for user. User will not be evicted, or if this directory belongs to a user that is to be created later, it might be created under a different UID/GID than before")
continue
}
}
@ -281,17 +310,17 @@ func generateUserMap(fs afero.Fs) (map[string]uidGIDPair, error) {
return userMap, nil
}
func run(fs afero.Fs, linuxUserManager user.LinuxUserManager, configMap *v1.ConfigMap) error {
sshAccess := ssh.NewAccess(linuxUserManager)
func run(log *logger.Logger, fs afero.Fs, linuxUserManager user.LinuxUserManager, configMap *v1.ConfigMap) error {
sshAccess := ssh.NewAccess(log, linuxUserManager)
// Generate userMap containing existing user directories and their ownership
userMap, err := generateUserMap(fs)
userMap, err := generateUserMap(log, fs)
if err != nil {
return err
}
// Try to deploy keys based on configmap.
deployKeys(context.Background(), configMap, fs, linuxUserManager, userMap, sshAccess)
deployKeys(context.Background(), log, configMap, fs, linuxUserManager, userMap, sshAccess)
return nil
}