feat(server): activate projected authentication safely

This commit is contained in:
User
2026-08-22 01:01:36 +02:00
parent 903c0b4de5
commit 3d9a9f0675
32 changed files with 1837 additions and 38 deletions
+30 -2
View File
@@ -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")),