Skip to content

Commit 33388a2

Browse files
authored
feat: Add authz caching config (#344)
* Add authz caching config * Update MLP dependency * Fix lint errors
1 parent 8ad8d74 commit 33388a2

File tree

8 files changed

+98
-8
lines changed

8 files changed

+98
-8
lines changed

api/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/GoogleCloudPlatform/spark-on-k8s-operator v0.0.0-20220214044918-55732a6a392c
99
github.com/antihax/optional v1.0.0
1010
github.com/caraml-dev/merlin v0.0.0
11-
github.com/caraml-dev/mlp v1.7.7-0.20230519042541-3415407aa27b
11+
github.com/caraml-dev/mlp v1.8.1-0.20230613010931-dd63f4364a18
1212
github.com/caraml-dev/turing/engines/experiment v0.0.0
1313
github.com/caraml-dev/turing/engines/router v0.0.0
1414
github.com/caraml-dev/universal-prediction-interface v0.3.4

api/go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,8 @@ github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c/go.
254254
github.com/caraml-dev/merlin/api v0.0.0-20230403075012-795947162429 h1:utxGPa/erqKIUhgBFMgnbORjKUIqVKLs7VXa0ZB0jNY=
255255
github.com/caraml-dev/merlin/api v0.0.0-20230403075012-795947162429/go.mod h1:BRGKVbv3zEu9rE6pE2RNlj/IZfqy/3HEqBQGLK5rHMc=
256256
github.com/caraml-dev/merlin/python/batch-predictor v0.0.0-20230403075012-795947162429/go.mod h1:jYSIcxx7FDccKSva3mo12YhQ0rYuP4MOEbgSveY82HE=
257-
github.com/caraml-dev/mlp v1.7.7-0.20230519042541-3415407aa27b h1:gnHGvCi48tbpWyvIIN9T51OjjBPN87CSjlNezq74H9s=
258-
github.com/caraml-dev/mlp v1.7.7-0.20230519042541-3415407aa27b/go.mod h1:KwanmpEzX11cIczhSs7e55M0EvgTuiZWC+uHQYppG5U=
257+
github.com/caraml-dev/mlp v1.8.1-0.20230613010931-dd63f4364a18 h1:/Rjw7+qVMo+rBaBqzJZrtQ1lKXb3KXeTXP1lJOTT7xI=
258+
github.com/caraml-dev/mlp v1.8.1-0.20230613010931-dd63f4364a18/go.mod h1:dNqC/QnXYpkxWDaV6XU8y1UJTjmKJC3Z6CpW1n9Hjd0=
259259
github.com/caraml-dev/universal-prediction-interface v0.3.4 h1:cPytzpjXE/8RhSw3iS0JFZzNdM3tJ/l8UcHTPrxQWEo=
260260
github.com/caraml-dev/universal-prediction-interface v0.3.4/go.mod h1:e0qmFOXQxx8HFg5ObYyQO3WVnrqsr5v5JApFmeF7eJo=
261261
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=

api/turing/config/config.go

+9
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,13 @@ type UPIConfig struct {
353353
type AuthorizationConfig struct {
354354
Enabled bool
355355
URL string
356+
Caching *InMemoryCacheConfig `validate:"required_if=Enabled True"`
357+
}
358+
359+
type InMemoryCacheConfig struct {
360+
Enabled bool
361+
KeyExpirySeconds int `validate:"required_if=Enabled True"`
362+
CacheCleanUpIntervalSeconds int `validate:"required_if=Enabled True"`
356363
}
357364

358365
// ClusterConfig contains the cluster controller information.
@@ -556,6 +563,8 @@ func setDefaultValues(v *viper.Viper) {
556563

557564
v.SetDefault("AuthConfig::Enabled", "false")
558565
v.SetDefault("AuthConfig::URL", "")
566+
v.SetDefault("AuthConfig::Caching::KeyExpirySeconds", "600")
567+
v.SetDefault("AuthConfig::Caching::CacheCleanUpIntervalSeconds", "900")
559568

560569
v.SetDefault("DbConfig::Host", "localhost")
561570
v.SetDefault("DbConfig::Port", "5432")

api/turing/config/config_test.go

+59-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package config_test
33
import (
44
"os"
55
"reflect"
6+
"strings"
67
"testing"
78
"time"
89

@@ -68,8 +69,9 @@ func TestGetters(t *testing.T) {
6869

6970
func TestAuthConfigValidation(t *testing.T) {
7071
tests := map[string]struct {
71-
cfg config.AuthorizationConfig
72-
success bool
72+
cfg config.AuthorizationConfig
73+
success bool
74+
expectedErr string
7375
}{
7476
"success auth disabled": {
7577
cfg: config.AuthorizationConfig{
@@ -81,6 +83,21 @@ func TestAuthConfigValidation(t *testing.T) {
8183
cfg: config.AuthorizationConfig{
8284
Enabled: true,
8385
URL: "url",
86+
Caching: &config.InMemoryCacheConfig{
87+
Enabled: false,
88+
},
89+
},
90+
success: true,
91+
},
92+
"success caching enabled": {
93+
cfg: config.AuthorizationConfig{
94+
Enabled: true,
95+
URL: "url",
96+
Caching: &config.InMemoryCacheConfig{
97+
Enabled: true,
98+
KeyExpirySeconds: 100,
99+
CacheCleanUpIntervalSeconds: 200,
100+
},
84101
},
85102
success: true,
86103
},
@@ -89,6 +106,26 @@ func TestAuthConfigValidation(t *testing.T) {
89106
Enabled: true,
90107
},
91108
success: false,
109+
expectedErr: strings.Join([]string{
110+
"Key: 'AuthorizationConfig.Caching' ",
111+
"Error:Field validation for 'Caching' failed on the 'required_if' tag",
112+
}, ""),
113+
},
114+
"failure caching enabled no duration config": {
115+
cfg: config.AuthorizationConfig{
116+
Enabled: true,
117+
URL: "url",
118+
Caching: &config.InMemoryCacheConfig{
119+
Enabled: true,
120+
},
121+
},
122+
success: false,
123+
expectedErr: strings.Join([]string{
124+
"Key: 'AuthorizationConfig.Caching.KeyExpirySeconds' ",
125+
"Error:Field validation for 'KeyExpirySeconds' failed on the 'required_if' tag\n",
126+
"Key: 'AuthorizationConfig.Caching.CacheCleanUpIntervalSeconds' ",
127+
"Error:Field validation for 'CacheCleanUpIntervalSeconds' failed on the 'required_if' tag",
128+
}, ""),
92129
},
93130
}
94131

@@ -133,7 +170,12 @@ func TestLoad(t *testing.T) {
133170
want: &config.Config{
134171
Port: 8080,
135172
AllowedOrigins: []string{"*"},
136-
AuthConfig: &config.AuthorizationConfig{},
173+
AuthConfig: &config.AuthorizationConfig{
174+
Caching: &config.InMemoryCacheConfig{
175+
KeyExpirySeconds: 600,
176+
CacheCleanUpIntervalSeconds: 900,
177+
},
178+
},
137179
DbConfig: &config.DatabaseConfig{
138180
Host: "localhost",
139181
Port: 5432,
@@ -201,6 +243,10 @@ func TestLoad(t *testing.T) {
201243
AuthConfig: &config.AuthorizationConfig{
202244
Enabled: true,
203245
URL: "http://example.com",
246+
Caching: &config.InMemoryCacheConfig{
247+
KeyExpirySeconds: 600,
248+
CacheCleanUpIntervalSeconds: 900,
249+
},
204250
},
205251
DbConfig: &config.DatabaseConfig{
206252
Host: "127.0.0.1",
@@ -338,6 +384,10 @@ func TestLoad(t *testing.T) {
338384
AuthConfig: &config.AuthorizationConfig{
339385
Enabled: false,
340386
URL: "http://example.com",
387+
Caching: &config.InMemoryCacheConfig{
388+
KeyExpirySeconds: 600,
389+
CacheCleanUpIntervalSeconds: 900,
390+
},
341391
},
342392
DbConfig: &config.DatabaseConfig{
343393
Host: "127.0.0.1",
@@ -489,6 +539,7 @@ func TestLoad(t *testing.T) {
489539
"ALLOWEDORIGINS": "http://baz.com,http://qux.com",
490540
"AUTHCONFIG_ENABLED": "true",
491541
"AUTHCONFIG_URL": "http://env.example.com",
542+
"AUTHCONFIG_CACHING_ENABLED": "true",
492543
"DBCONFIG_USER": "dbuser-env",
493544
"DBCONFIG_PASSWORD": "dbpassword-env",
494545
"DEPLOYCONFIG_TIMEOUT": "10m",
@@ -510,6 +561,11 @@ func TestLoad(t *testing.T) {
510561
AuthConfig: &config.AuthorizationConfig{
511562
Enabled: true,
512563
URL: "http://env.example.com",
564+
Caching: &config.InMemoryCacheConfig{
565+
Enabled: true,
566+
KeyExpirySeconds: 600,
567+
CacheCleanUpIntervalSeconds: 900,
568+
},
513569
},
514570
DbConfig: &config.DatabaseConfig{
515571
Host: "127.0.0.1",

api/turing/config/example.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ AuthConfig:
1313
Enabled: false
1414
# ORY Keto auth server URL: https://github.com/ory/keto
1515
URL: http://example.com/auth
16+
# Whether or not local caching of authz responses should be enabled
17+
Caching:
18+
Enabled: false
1619

1720
# Batch ensembler job configurations
1821
BatchEnsemblingConfig:

api/turing/config/testdata/config-1.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ AllowedOrigins:
55
AuthConfig:
66
Enabled: true
77
URL: http://example.com
8+
Caching:
9+
Enabled: false
810
DbConfig:
911
Host: "127.0.0.1"
1012
User: dbuser

api/turing/middleware/authorization.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,19 @@ func (a *Authorizer) FilterAuthorizedProjects(
9696
}
9797

9898
func getResourceFromPath(path string, prefix string) string {
99-
return strings.Replace(strings.TrimPrefix(strings.TrimPrefix(path, prefix), "/"), "/", ":", -1)
99+
// Current paths registered in Turing are of the following formats:
100+
// - /experiment-engines/**
101+
// - /projects/{project_id}/**
102+
//
103+
// Given this, we only care about the permissions up-to 2 levels deep. The rationale is that
104+
// if a user has READ/WRITE permissions on /projects/{project_id}, they would also have the same
105+
// permissions on all its sub-resources. Thus, trimming the resource identifier to aid quicker
106+
// authz matching and to efficiently make use of the in-memory authz cache, if enabled.
107+
parts := strings.Split(strings.TrimPrefix(path, "/"), "/")
108+
if len(parts) > 1 {
109+
parts = parts[:2]
110+
}
111+
return strings.Join(parts, ":")
100112
}
101113

102114
func getActionFromMethod(method string) string {

api/turing/server/application.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,15 @@ func Run() {
8181
apiPathPrefix := "/v1"
8282
if cfg.AuthConfig.Enabled {
8383
// Use product mlp as the policies are shared across the mlp products.
84-
authEnforcer, err := enforcer.NewEnforcerBuilder().Product("mlp").URL(cfg.AuthConfig.URL).Build()
84+
enforcerCfg := enforcer.NewEnforcerBuilder().URL(cfg.AuthConfig.URL).Product("mlp")
85+
if cfg.AuthConfig.Caching.Enabled {
86+
enforcerCfg = enforcerCfg.WithCaching(
87+
cfg.AuthConfig.Caching.KeyExpirySeconds,
88+
cfg.AuthConfig.Caching.CacheCleanUpIntervalSeconds,
89+
)
90+
}
91+
authEnforcer, err := enforcerCfg.Build()
92+
8593
if err != nil {
8694
log.Panicf("Failed initializing authorization enforcer %v", err)
8795
}

0 commit comments

Comments
 (0)