Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 37 additions & 27 deletions internal/bootstrap/service_bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,13 @@ func (app *BootstrapApp) setupServices() error {

app.services.ldapService = ldapService

useKubernetes := app.config.LabelProvider == "kubernetes" ||
(app.config.LabelProvider == "auto" && os.Getenv("KUBERNETES_SERVICE_HOST") != "")

var labelProvider service.LabelProvider

if useKubernetes {
app.log.App.Debug().Msg("Using Kubernetes label provider")

kubernetesService, err := service.NewKubernetesService(app.log, app.ctx, &app.wg)

if err != nil {
return fmt.Errorf("failed to initialize kubernetes service: %w", err)
}
labelProvider, err := app.getLabelProvider()

app.services.kubernetesService = kubernetesService
labelProvider = kubernetesService
} else {
app.log.App.Debug().Msg("Using Docker label provider")

dockerService, err := service.NewDockerService(app.log, app.ctx, &app.wg)

if err != nil {
return fmt.Errorf("failed to initialize docker service: %w", err)
}

app.services.dockerService = dockerService
labelProvider = dockerService
if err != nil {
return fmt.Errorf("failed to initialize label provider: %w", err)
}

accessControlsService := service.NewAccessControlsService(app.log, &labelProvider, app.config.Apps)
accessControlsService := service.NewAccessControlsService(app.log, app.config, &labelProvider)
app.services.accessControlService = accessControlsService

oauthBrokerService := service.NewOAuthBrokerService(app.log, app.runtime.OAuthProviders, app.ctx)
Expand All @@ -64,3 +41,36 @@ func (app *BootstrapApp) setupServices() error {

return nil
}

func (app *BootstrapApp) getLabelProvider() (service.LabelProvider, error) {
if app.config.LabelProvider == "none" {
return nil, nil
}

useKubernetes := app.config.LabelProvider == "kubernetes" ||
(app.config.LabelProvider == "auto" && os.Getenv("KUBERNETES_SERVICE_HOST") != "")

if useKubernetes {
app.log.App.Debug().Msg("Using Kubernetes label provider")

kubernetesService, err := service.NewKubernetesService(app.log, app.ctx, &app.wg)

if err != nil {
return nil, fmt.Errorf("failed to initialize kubernetes service: %w", err)
}

app.services.kubernetesService = kubernetesService
return kubernetesService, nil
}

app.log.App.Debug().Msg("Using Docker label provider")

dockerService, err := service.NewDockerService(app.log, app.ctx, &app.wg)

if err != nil {
return nil, fmt.Errorf("failed to initialize docker service: %w", err)
}

app.services.dockerService = dockerService
return dockerService, nil
}
18 changes: 6 additions & 12 deletions internal/controller/proxy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {

clientIP := c.ClientIP()

if controller.auth.IsBypassedIP(clientIP, acls) {
if controller.acls.IsIPBypassed(clientIP, acls) {
controller.setHeaders(c, acls)
c.JSON(200, gin.H{
"status": 200,
Expand All @@ -110,13 +110,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
return
}

authEnabled, err := controller.auth.IsAuthEnabled(proxyCtx.Path, acls)

if err != nil {
controller.log.App.Error().Err(err).Msg("Failed to determine if authentication is enabled for resource")
controller.handleError(c, proxyCtx)
return
}
authEnabled := controller.acls.IsAuthEnabled(proxyCtx.Path, acls)

if !authEnabled {
controller.log.App.Debug().Msg("Authentication is disabled for this resource, allowing access without authentication")
Expand All @@ -128,7 +122,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
return
}

if !controller.auth.CheckIP(clientIP, acls) {
if !controller.acls.IsIPAllowed(clientIP, acls) {
queries, err := query.Values(UnauthorizedQuery{
Resource: strings.Split(proxyCtx.Host, ".")[0],
IP: clientIP,
Expand Down Expand Up @@ -165,7 +159,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
}

if userContext.Authenticated {
userAllowed := controller.auth.IsUserAllowed(c, *userContext, acls)
userAllowed := controller.acls.IsUserAllowed(*userContext, acls)

if !userAllowed {
controller.log.App.Warn().Str("user", userContext.GetUsername()).Str("resource", strings.Split(proxyCtx.Host, ".")[0]).Msg("User is not allowed to access resource")
Expand Down Expand Up @@ -205,9 +199,9 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
var groupOK bool

if userContext.IsOAuth() {
groupOK = controller.auth.IsInOAuthGroup(c, *userContext, acls)
groupOK = controller.acls.IsInOAuthGroup(*userContext, acls)
} else {
groupOK = controller.auth.IsInLDAPGroup(c, *userContext, acls)
groupOK = controller.acls.IsInLDAPGroup(*userContext, acls)
}

if !groupOK {
Expand Down
29 changes: 1 addition & 28 deletions internal/controller/proxy_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,33 +24,6 @@ func TestProxyController(t *testing.T) {

cfg, runtime := test.CreateTestConfigs(t)

acls := map[string]model.App{
"app_path_allow": {
Config: model.AppConfig{
Domain: "path-allow.example.com",
},
Path: model.AppPath{
Allow: "/allowed",
},
},
"app_user_allow": {
Config: model.AppConfig{
Domain: "user-allow.example.com",
},
Users: model.AppUsers{
Allow: "testuser",
},
},
"ip_bypass": {
Config: model.AppConfig{
Domain: "ip-bypass.example.com",
},
IP: model.AppIP{
Bypass: []string{"10.10.10.10"},
},
},
}

const browserUserAgent = `
Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Mobile Safari/537.36`

Expand Down Expand Up @@ -391,7 +364,7 @@ func TestProxyController(t *testing.T) {

broker := service.NewOAuthBrokerService(log, map[string]model.OAuthServiceConfig{}, ctx)
authService := service.NewAuthService(log, cfg, runtime, ctx, wg, nil, queries, broker)
aclsService := service.NewAccessControlsService(log, nil, acls)
aclsService := service.NewAccessControlsService(log, cfg, nil)

for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
Expand Down
10 changes: 9 additions & 1 deletion internal/model/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ func NewDefaultConfiguration() *Config {
SessionMaxLifetime: 0, // disabled
LoginTimeout: 300, // 5 minutes
LoginMaxRetries: 3,
ACLs: ACLsConfig{
Policy: "allow",
},
},
UI: UIConfig{
Title: "Tinyauth",
Expand Down Expand Up @@ -78,7 +81,7 @@ type Config struct {
UI UIConfig `description:"UI customization." yaml:"ui"`
LDAP LDAPConfig `description:"LDAP configuration." yaml:"ldap"`
Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"`
LabelProvider string `description:"Label provider to use for ACLs (auto, docker, or kubernetes). auto detects the environment." yaml:"labelProvider"`
LabelProvider string `description:"Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment." yaml:"labelProvider"`
Log LogConfig `description:"Logging configuration." yaml:"log"`
}

Expand Down Expand Up @@ -114,6 +117,7 @@ type AuthConfig struct {
LoginTimeout int `description:"Login timeout in seconds." yaml:"loginTimeout"`
LoginMaxRetries int `description:"Maximum login retries." yaml:"loginMaxRetries"`
TrustedProxies []string `description:"Comma-separated list of trusted proxy addresses." yaml:"trustedProxies"`
ACLs ACLsConfig `description:"ACLs configuration." yaml:"acls"`
}

type UserAttributes struct {
Expand Down Expand Up @@ -223,6 +227,10 @@ type OIDCClientConfig struct {
Name string `description:"Client name in UI." yaml:"name"`
}

type ACLsConfig struct {
Policy string `description:"ACL policy for allow-by-default or deny-by-default, available options are allow and deny, default is allow." yaml:"policy"`
}

// ACLs

type Apps struct {
Expand Down
Loading