feat(server): activate projected authentication safely
This commit is contained in:
@@ -30,6 +30,10 @@ var installationIDPattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]*$`)
|
||||
// file and leaves no final target until all content is synced.
|
||||
var atomicWriteNewFile = writeNewFileAtomically
|
||||
|
||||
// effectiveUID is a package-private seam so projected server setup can prove its root gate
|
||||
// happens before any filesystem mutation.
|
||||
var effectiveUID = currentEffectiveUID
|
||||
|
||||
type answers struct {
|
||||
installationID, profile string
|
||||
workspaceRemote, workspaceBranch string
|
||||
@@ -51,7 +55,12 @@ type generatedDescriptor struct {
|
||||
Access string `yaml:"access"`
|
||||
} `yaml:"workspaceRepository"`
|
||||
Authentication struct {
|
||||
ConfigDirectory string `yaml:"configDirectory"`
|
||||
ConfigDirectory string `yaml:"configDirectory"`
|
||||
RuntimeProjection *struct {
|
||||
Directory string `yaml:"directory"`
|
||||
UID uint32 `yaml:"uid"`
|
||||
GID uint32 `yaml:"gid"`
|
||||
} `yaml:"runtimeProjection,omitempty"`
|
||||
} `yaml:"authentication"`
|
||||
Overrides []string `yaml:"overrides"`
|
||||
}
|
||||
@@ -70,6 +79,9 @@ func EnsureFiles(request Request, input io.Reader, output io.Writer) (FilesResul
|
||||
if err := validateAnswers(values); err != nil {
|
||||
return FilesResult{}, err
|
||||
}
|
||||
if values.profile == "server" && effectiveUID() != 0 {
|
||||
return FilesResult{}, errors.New("projected server setup requires root")
|
||||
}
|
||||
|
||||
directory, err := installationDirectory(root, values.installationID)
|
||||
if err != nil {
|
||||
@@ -77,7 +89,11 @@ func EnsureFiles(request Request, input io.Reader, output io.Writer) (FilesResul
|
||||
}
|
||||
descriptorPath := filepath.Join(directory, descriptorName)
|
||||
environmentPath := filepath.Join(directory, environmentName)
|
||||
if err := safeio.EnsurePrivateDirectory(filepath.Join(directory, "auth")); err != nil {
|
||||
if values.profile == "server" {
|
||||
if err := ensureProjectedAuthDirectories(filepath.Join(directory, "auth"), filepath.Join(directory, "auth-runtime")); err != nil {
|
||||
return FilesResult{}, errors.New("projected authentication directories are unavailable or unsafe")
|
||||
}
|
||||
} else if err := safeio.EnsurePrivateDirectory(filepath.Join(directory, "auth")); err != nil {
|
||||
return FilesResult{}, errors.New("authentication directory is unavailable or unsafe")
|
||||
}
|
||||
result := FilesResult{DescriptorPath: descriptorPath, EnvironmentPath: environmentPath}
|
||||
@@ -305,6 +321,17 @@ func render(root, descriptorPath string, value answers) ([]byte, []byte, error)
|
||||
descriptor := generatedDescriptor{Profile: value.profile, ProjectDirectory: root, EnvFile: filepath.Join(filepath.Dir(descriptorPath), environmentName)}
|
||||
descriptor.Workspace.Remote, descriptor.Workspace.Branch, descriptor.Workspace.Access = value.workspaceRemote, value.workspaceBranch, value.workspaceAccess
|
||||
descriptor.Authentication.ConfigDirectory = filepath.Join(filepath.Dir(descriptorPath), "auth")
|
||||
if value.profile == "server" {
|
||||
descriptor.Authentication.RuntimeProjection = &struct {
|
||||
Directory string `yaml:"directory"`
|
||||
UID uint32 `yaml:"uid"`
|
||||
GID uint32 `yaml:"gid"`
|
||||
}{
|
||||
Directory: filepath.Join(filepath.Dir(descriptorPath), "auth-runtime"),
|
||||
UID: 10001,
|
||||
GID: 10001,
|
||||
}
|
||||
}
|
||||
descriptor.Overrides = []string{filepath.Join(root, "deploy", "compose.git-"+value.workspaceAccess+".yaml")}
|
||||
descriptorBytes, err := yaml.Marshal(descriptor)
|
||||
if err != nil {
|
||||
@@ -334,6 +361,7 @@ func render(root, descriptorPath string, value answers) ([]byte, []byte, error)
|
||||
if value.profile == "server" {
|
||||
installationDirectory := filepath.Dir(descriptorPath)
|
||||
lines = append(lines,
|
||||
"THT_AUTH_RUNTIME_ROOT="+dotenvValue(descriptor.Authentication.RuntimeProjection.Directory),
|
||||
"THT_DATA_ROOT="+dotenvValue(filepath.Join(installationDirectory, "data")),
|
||||
"THT_PI_STATE_ROOT="+dotenvValue(filepath.Join(installationDirectory, "pi-state")),
|
||||
"THT_WORKSPACE_REGISTRY_ROOT="+dotenvValue(filepath.Join(installationDirectory, "workspace-registry")),
|
||||
|
||||
Reference in New Issue
Block a user