Skip to content

Commit 9c9c878

Browse files
feat: implement landjail (#119)
1 parent 3e2e411 commit 9c9c878

File tree

23 files changed

+1092
-326
lines changed

23 files changed

+1092
-326
lines changed

cli/cli.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
"github.com/coder/boundary/config"
1010
"github.com/coder/boundary/log"
11-
"github.com/coder/boundary/nsjail_manager"
11+
"github.com/coder/boundary/run"
1212
"github.com/coder/serpent"
1313
)
1414

@@ -119,9 +119,25 @@ func BaseCommand() *serpent.Command {
119119
Value: &cliConfig.ConfigureDNSForLocalStubResolver,
120120
YAML: "configure_dns_for_local_stub_resolver",
121121
},
122+
{
123+
Flag: "jail-type",
124+
Env: "BOUNDARY_JAIL_TYPE",
125+
Description: "Jail type to use for network isolation. Options: nsjail (default), landjail.",
126+
Default: "nsjail",
127+
Value: &cliConfig.JailType,
128+
YAML: "jail_type",
129+
},
122130
},
123131
Handler: func(inv *serpent.Invocation) error {
124-
appConfig := config.NewAppConfigFromCliConfig(cliConfig)
132+
appConfig, err := config.NewAppConfigFromCliConfig(cliConfig, inv.Args)
133+
if err != nil {
134+
return fmt.Errorf("failed to parse cli config file: %v", err)
135+
}
136+
137+
// Get command arguments
138+
if len(appConfig.TargetCMD) == 0 {
139+
return fmt.Errorf("no command specified")
140+
}
125141

126142
logger, err := log.SetupLogging(appConfig)
127143
if err != nil {
@@ -134,7 +150,7 @@ func BaseCommand() *serpent.Command {
134150
}
135151
logger.Debug("Application config", "config", appConfigInJSON)
136152

137-
return nsjail_manager.Run(inv.Context(), logger, appConfig, inv.Args)
153+
return run.Run(inv.Context(), logger, appConfig)
138154
},
139155
}
140156
}

config/config.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
11
package config
22

33
import (
4+
"fmt"
5+
46
"github.com/coder/serpent"
57
)
68

9+
// JailType represents the type of jail to use for network isolation
10+
type JailType string
11+
12+
const (
13+
NSJailType JailType = "nsjail"
14+
LandjailType JailType = "landjail"
15+
)
16+
17+
func NewJailTypeFromString(str string) (JailType, error) {
18+
switch str {
19+
case "nsjail":
20+
return NSJailType, nil
21+
case "landjail":
22+
return LandjailType, nil
23+
default:
24+
return NSJailType, fmt.Errorf("invalid JailType: %s", str)
25+
}
26+
}
27+
728
type CliConfig struct {
829
Config serpent.YAMLConfigPath `yaml:"-"`
930
AllowListStrings serpent.StringArray `yaml:"allowlist"` // From config file
@@ -14,6 +35,7 @@ type CliConfig struct {
1435
PprofEnabled serpent.Bool `yaml:"pprof_enabled"`
1536
PprofPort serpent.Int64 `yaml:"pprof_port"`
1637
ConfigureDNSForLocalStubResolver serpent.Bool `yaml:"configure_dns_for_local_stub_resolver"`
38+
JailType serpent.String `yaml:"jail_type"`
1739
}
1840

1941
type AppConfig struct {
@@ -24,16 +46,26 @@ type AppConfig struct {
2446
PprofEnabled bool
2547
PprofPort int64
2648
ConfigureDNSForLocalStubResolver bool
49+
JailType JailType
50+
TargetCMD []string
51+
UserInfo *UserInfo
2752
}
2853

29-
func NewAppConfigFromCliConfig(cfg CliConfig) AppConfig {
54+
func NewAppConfigFromCliConfig(cfg CliConfig, targetCMD []string) (AppConfig, error) {
3055
// Merge allowlist from config file with allow from CLI flags
3156
allowListStrings := cfg.AllowListStrings.Value()
3257
allowStrings := cfg.AllowStrings.Value()
3358

3459
// Combine allowlist (config file) with allow (CLI flags)
3560
allAllowStrings := append(allowListStrings, allowStrings...)
3661

62+
jailType, err := NewJailTypeFromString(cfg.JailType.Value())
63+
if err != nil {
64+
return AppConfig{}, err
65+
}
66+
67+
userInfo := GetUserInfo()
68+
3769
return AppConfig{
3870
AllowRules: allAllowStrings,
3971
LogLevel: cfg.LogLevel.Value(),
@@ -42,5 +74,8 @@ func NewAppConfigFromCliConfig(cfg CliConfig) AppConfig {
4274
PprofEnabled: cfg.PprofEnabled.Value(),
4375
PprofPort: cfg.PprofPort.Value(),
4476
ConfigureDNSForLocalStubResolver: cfg.ConfigureDNSForLocalStubResolver.Value(),
45-
}
77+
JailType: jailType,
78+
TargetCMD: targetCMD,
79+
UserInfo: userInfo,
80+
}, nil
4681
}

util/user.go renamed to config/user_info.go

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package util
1+
package config
22

33
import (
44
"os"
@@ -7,8 +7,21 @@ import (
77
"strconv"
88
)
99

10+
const (
11+
CAKeyName = "ca-key.pem"
12+
CACertName = "ca-cert.pem"
13+
)
14+
15+
type UserInfo struct {
16+
SudoUser string
17+
Uid int
18+
Gid int
19+
HomeDir string
20+
ConfigDir string
21+
}
22+
1023
// GetUserInfo returns information about the current user, handling sudo scenarios
11-
func GetUserInfo() (string, int, int, string, string) {
24+
func GetUserInfo() *UserInfo {
1225
// Only consider SUDO_USER if we're actually running with elevated privileges
1326
// In environments like Coder workspaces, SUDO_USER may be set to 'root'
1427
// but we're not actually running under sudo
@@ -36,27 +49,39 @@ func GetUserInfo() (string, int, int, string, string) {
3649

3750
configDir := getConfigDir(user.HomeDir)
3851

39-
return sudoUser, uid, gid, user.HomeDir, configDir
52+
return &UserInfo{
53+
SudoUser: sudoUser,
54+
Uid: uid,
55+
Gid: gid,
56+
HomeDir: user.HomeDir,
57+
ConfigDir: configDir,
58+
}
4059
}
4160

4261
// Not actually running under sudo, use current user
4362
return getCurrentUserInfo()
4463
}
4564

4665
// getCurrentUserInfo gets information for the current user
47-
func getCurrentUserInfo() (string, int, int, string, string) {
66+
func getCurrentUserInfo() *UserInfo {
4867
currentUser, err := user.Current()
4968
if err != nil {
5069
// Fallback with empty values if we can't get user info
51-
return "", 0, 0, "", ""
70+
return &UserInfo{}
5271
}
5372

5473
uid, _ := strconv.Atoi(currentUser.Uid)
5574
gid, _ := strconv.Atoi(currentUser.Gid)
5675

5776
configDir := getConfigDir(currentUser.HomeDir)
5877

59-
return currentUser.Username, uid, gid, currentUser.HomeDir, configDir
78+
return &UserInfo{
79+
SudoUser: currentUser.Username,
80+
Uid: uid,
81+
Gid: gid,
82+
HomeDir: currentUser.HomeDir,
83+
ConfigDir: configDir,
84+
}
6085
}
6186

6287
// getConfigDir determines the config directory based on XDG_CONFIG_HOME or fallback
@@ -67,3 +92,11 @@ func getConfigDir(homeDir string) string {
6792
}
6893
return filepath.Join(homeDir, ".config", "coder_boundary")
6994
}
95+
96+
func (u *UserInfo) CAKeyPath() string {
97+
return filepath.Join(u.ConfigDir, CAKeyName)
98+
}
99+
100+
func (u *UserInfo) CACertPath() string {
101+
return filepath.Join(u.ConfigDir, CACertName)
102+
}

0 commit comments

Comments
 (0)