Skip to content

Commit 956d2f5

Browse files
authored
feat(access-control): Add support for Kubernetes Label (#627)
* feat(access-control): Add support for Kubernetes Label * feat(access-control): Defaults to Docker * feat(access-control): Remove kubeconfig fallback * feat(watcher): Watcher for kubernetes service * feat(watcher): Merge with main + remove nightly fix redirect * fix(go): Go mod + Go sum after sync with main * fix(config): Ser default value for LabelProvider to Docker * feat(go): go mod tidy * feat(k8s_service): Remove logic for deprecated Ingress k8s v1.22 * feat(k8s_service): (Watcher) -> Wait 5s before breaking to outer loop again * feat(k8s_service): Remove logic for deprecated Ingress k8s v1.22 * feat(k8s_service): Remove logic for deprecated Ingress k8s v1.22 * feat(k8s_service): Remove logic for deprecated Ingress k8s v1.22 * feat(k8s_service): Remove var _ = unstructured.Unstructured{} + comments + msg edits * feat(bootstrap): Remove dockerService from bootstrap svc * feat(auth_svc): Remove dockerService from authservice * feat(test): Add tests for kubernetes_services * feat(test): Remove docker serivce form proxy/user test * fix(refactor): Remove update logic from watcher and resync * fix(refactor): Split watchGVR to make it more readable * fix(refactor): Remove discovery + drop K 1.22 completely * fix(refactor): Move interface to acess_controls_service * feat: Autodetect labelprovider if TINYAUTH_LABELPROVIDER not set * fix(test): Match testing scheme to the controllers * fix: service bootstrap import after merge * fix: service bootstrap import after merge
1 parent 5e822d9 commit 956d2f5

10 files changed

Lines changed: 644 additions & 38 deletions

File tree

go.mod

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ require (
2121
golang.org/x/crypto v0.50.0
2222
golang.org/x/oauth2 v0.36.0
2323
gotest.tools/v3 v3.5.2
24+
k8s.io/apimachinery v0.32.2
25+
k8s.io/client-go v0.32.2
2426
modernc.org/sqlite v1.49.1
2527
)
2628

@@ -62,6 +64,7 @@ require (
6264
github.com/docker/go-units v0.5.0 // indirect
6365
github.com/dustin/go-humanize v1.0.1 // indirect
6466
github.com/felixge/httpsnoop v1.0.4 // indirect
67+
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
6568
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
6669
github.com/gin-contrib/sse v1.1.0 // indirect
6770
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
@@ -72,7 +75,9 @@ require (
7275
github.com/go-playground/validator/v10 v10.30.1 // indirect
7376
github.com/goccy/go-json v0.10.5 // indirect
7477
github.com/goccy/go-yaml v1.19.2 // indirect
78+
github.com/gogo/protobuf v1.3.2 // indirect
7579
github.com/google/go-cmp v0.7.0 // indirect
80+
github.com/google/gofuzz v1.2.0 // indirect
7681
github.com/huandu/xstrings v1.5.0 // indirect
7782
github.com/json-iterator/go v1.1.12 // indirect
7883
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
@@ -91,6 +96,7 @@ require (
9196
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
9297
github.com/modern-go/reflect2 v1.0.2 // indirect
9398
github.com/muesli/cancelreader v0.2.2 // indirect
99+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
94100
github.com/ncruces/go-strftime v1.0.0 // indirect
95101
github.com/opencontainers/go-digest v1.0.0 // indirect
96102
github.com/opencontainers/image-spec v1.1.0 // indirect
@@ -105,6 +111,7 @@ require (
105111
github.com/spf13/cast v1.10.0 // indirect
106112
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
107113
github.com/ugorji/go/codec v1.3.1 // indirect
114+
github.com/x448/float16 v0.8.4 // indirect
108115
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
109116
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
110117
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
@@ -122,10 +129,17 @@ require (
122129
golang.org/x/sys v0.43.0 // indirect
123130
golang.org/x/term v0.42.0 // indirect
124131
golang.org/x/text v0.36.0 // indirect
132+
golang.org/x/time v0.12.0 // indirect
125133
google.golang.org/protobuf v1.36.11 // indirect
134+
gopkg.in/inf.v0 v0.9.1 // indirect
126135
gopkg.in/yaml.v3 v3.0.1 // indirect
136+
k8s.io/klog/v2 v2.130.1 // indirect
137+
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
127138
modernc.org/libc v1.72.0 // indirect
128139
modernc.org/mathutil v1.7.1 // indirect
129140
modernc.org/memory v1.11.0 // indirect
130141
rsc.io/qr v0.2.0 // indirect
142+
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
143+
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
144+
sigs.k8s.io/yaml v1.4.0 // indirect
131145
)

go.sum

Lines changed: 80 additions & 0 deletions
Large diffs are not rendered by default.

internal/bootstrap/service_bootstrap.go

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package bootstrap
22

33
import (
4+
"os"
5+
46
"github.com/tinyauthapp/tinyauth/internal/repository"
57
"github.com/tinyauthapp/tinyauth/internal/service"
68
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
@@ -10,6 +12,7 @@ type Services struct {
1012
accessControlService *service.AccessControlsService
1113
authService *service.AuthService
1214
dockerService *service.DockerService
15+
kubernetesService *service.KubernetesService
1316
ldapService *service.LdapService
1417
oauthBrokerService *service.OAuthBrokerService
1518
oidcService *service.OIDCService
@@ -38,17 +41,34 @@ func (app *BootstrapApp) initServices(queries *repository.Queries) (Services, er
3841

3942
services.ldapService = ldapService
4043

41-
dockerService := service.NewDockerService()
42-
43-
err = dockerService.Init()
44-
45-
if err != nil {
46-
return Services{}, err
44+
var labelProvider service.LabelProvider
45+
var dockerService *service.DockerService
46+
var kubernetesService *service.KubernetesService
47+
48+
useKubernetes := app.config.LabelProvider == "kubernetes" ||
49+
(app.config.LabelProvider == "auto" && os.Getenv("KUBERNETES_SERVICE_HOST") != "")
50+
51+
if useKubernetes {
52+
tlog.App.Debug().Msg("Using Kubernetes label provider")
53+
kubernetesService = service.NewKubernetesService()
54+
err = kubernetesService.Init()
55+
if err != nil {
56+
return Services{}, err
57+
}
58+
services.kubernetesService = kubernetesService
59+
labelProvider = kubernetesService
60+
} else {
61+
tlog.App.Debug().Msg("Using Docker label provider")
62+
dockerService = service.NewDockerService()
63+
err = dockerService.Init()
64+
if err != nil {
65+
return Services{}, err
66+
}
67+
services.dockerService = dockerService
68+
labelProvider = dockerService
4769
}
4870

49-
services.dockerService = dockerService
50-
51-
accessControlsService := service.NewAccessControlsService(dockerService, app.config.Apps)
71+
accessControlsService := service.NewAccessControlsService(labelProvider, app.config.Apps)
5272

5373
err = accessControlsService.Init()
5474

@@ -80,7 +100,7 @@ func (app *BootstrapApp) initServices(queries *repository.Queries) (Services, er
80100
SessionCookieName: app.context.sessionCookieName,
81101
IP: app.config.Auth.IP,
82102
LDAPGroupsCacheTTL: app.config.Ldap.GroupCacheTTL,
83-
}, dockerService, services.ldapService, queries, services.oauthBrokerService)
103+
}, services.ldapService, queries, services.oauthBrokerService)
84104

85105
err = authService.Init()
86106

internal/config/config.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func NewDefaultConfiguration() *Config {
5959
Experimental: ExperimentalConfig{
6060
ConfigFile: "",
6161
},
62+
LabelProvider: "auto",
6263
}
6364
}
6465

@@ -76,21 +77,21 @@ var RedirectCookieName = "tinyauth-redirect"
7677
var OAuthSessionCookieName = "tinyauth-oauth"
7778

7879
// Main app config
79-
8080
type Config struct {
81-
AppURL string `description:"The base URL where the app is hosted." yaml:"appUrl"`
82-
Database DatabaseConfig `description:"Database configuration." yaml:"database"`
83-
Analytics AnalyticsConfig `description:"Analytics configuration." yaml:"analytics"`
84-
Resources ResourcesConfig `description:"Resources configuration." yaml:"resources"`
85-
Server ServerConfig `description:"Server configuration." yaml:"server"`
86-
Auth AuthConfig `description:"Authentication configuration." yaml:"auth"`
87-
Apps map[string]App `description:"Application ACLs configuration." yaml:"apps"`
88-
OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"`
89-
OIDC OIDCConfig `description:"OIDC configuration." yaml:"oidc"`
90-
UI UIConfig `description:"UI customization." yaml:"ui"`
91-
Ldap LdapConfig `description:"LDAP configuration." yaml:"ldap"`
92-
Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"`
93-
Log LogConfig `description:"Logging configuration." yaml:"log"`
81+
AppURL string `description:"The base URL where the app is hosted." yaml:"appUrl"`
82+
Database DatabaseConfig `description:"Database configuration." yaml:"database"`
83+
Analytics AnalyticsConfig `description:"Analytics configuration." yaml:"analytics"`
84+
Resources ResourcesConfig `description:"Resources configuration." yaml:"resources"`
85+
Server ServerConfig `description:"Server configuration." yaml:"server"`
86+
Auth AuthConfig `description:"Authentication configuration." yaml:"auth"`
87+
Apps map[string]App `description:"Application ACLs configuration." yaml:"apps"`
88+
OAuth OAuthConfig `description:"OAuth configuration." yaml:"oauth"`
89+
OIDC OIDCConfig `description:"OIDC configuration." yaml:"oidc"`
90+
UI UIConfig `description:"UI customization." yaml:"ui"`
91+
Ldap LdapConfig `description:"LDAP configuration." yaml:"ldap"`
92+
Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"`
93+
LabelProvider string `description:"Label provider to use for ACLs (auto, docker, or kubernetes). auto detects the environment." yaml:"labelProvider"`
94+
Log LogConfig `description:"Logging configuration." yaml:"log"`
9495
}
9596

9697
type DatabaseConfig struct {

internal/controller/proxy_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ func TestProxyController(t *testing.T) {
412412
err = broker.Init()
413413
require.NoError(t, err)
414414

415-
authService := service.NewAuthService(authServiceCfg, docker, ldap, queries, broker)
415+
authService := service.NewAuthService(authServiceCfg, ldap, queries, broker)
416416
err = authService.Init()
417417
require.NoError(t, err)
418418

internal/controller/user_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ func TestUserController(t *testing.T) {
370370
err = broker.Init()
371371
require.NoError(t, err)
372372

373-
authService := service.NewAuthService(authServiceCfg, docker, ldap, queries, broker)
373+
authService := service.NewAuthService(authServiceCfg, ldap, queries, broker)
374374
err = authService.Init()
375375
require.NoError(t, err)
376376

internal/service/access_controls_service.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,19 @@ import (
88
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
99
)
1010

11+
type LabelProvider interface {
12+
GetLabels(appDomain string) (config.App, error)
13+
}
14+
1115
type AccessControlsService struct {
12-
docker *DockerService
13-
static map[string]config.App
16+
labelProvider LabelProvider
17+
static map[string]config.App
1418
}
1519

16-
func NewAccessControlsService(docker *DockerService, static map[string]config.App) *AccessControlsService {
20+
func NewAccessControlsService(labelProvider LabelProvider, static map[string]config.App) *AccessControlsService {
1721
return &AccessControlsService{
18-
docker: docker,
19-
static: static,
22+
labelProvider: labelProvider,
23+
static: static,
2024
}
2125
}
2226

@@ -48,7 +52,7 @@ func (acls *AccessControlsService) GetAccessControls(domain string) (config.App,
4852
return app, nil
4953
}
5054

51-
// Fallback to Docker labels
52-
tlog.App.Debug().Msg("Falling back to Docker labels for ACLs")
53-
return acls.docker.GetLabels(domain)
55+
// Fallback to label provider
56+
tlog.App.Debug().Msg("Falling back to label provider for ACLs")
57+
return acls.labelProvider.GetLabels(domain)
5458
}

internal/service/auth_service.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ type AuthServiceConfig struct {
8383

8484
type AuthService struct {
8585
config AuthServiceConfig
86-
docker *DockerService
8786
loginAttempts map[string]*LoginAttempt
8887
ldapGroupsCache map[string]*LdapGroupsCache
8988
oauthPendingSessions map[string]*OAuthPendingSession
@@ -98,17 +97,16 @@ type AuthService struct {
9897
lockdownCancelFunc context.CancelFunc
9998
}
10099

101-
func NewAuthService(config AuthServiceConfig, docker *DockerService, ldap *LdapService, queries *repository.Queries, oauthBroker *OAuthBrokerService) *AuthService {
100+
func NewAuthService(config AuthServiceConfig, ldap *LdapService, queries *repository.Queries, oauthBroker *OAuthBrokerService) *AuthService {
102101
return &AuthService{
103102
config: config,
104-
docker: docker,
105103
loginAttempts: make(map[string]*LoginAttempt),
106104
ldapGroupsCache: make(map[string]*LdapGroupsCache),
107105
oauthPendingSessions: make(map[string]*OAuthPendingSession),
108106
ldap: ldap,
109107
queries: queries,
110108
oauthBroker: oauthBroker,
111-
}
109+
}
112110
}
113111

114112
func (auth *AuthService) Init() error {

0 commit comments

Comments
 (0)