Skip to content

Commit

Permalink
Dynamically Create Permission Relationships From Config (#347)
Browse files Browse the repository at this point in the history
* dynamically create permission relationships from config

Signed-off-by: Stephen Hwang <[email protected]>

* minor fixes

Signed-off-by: Stephen Hwang <[email protected]>

---------

Signed-off-by: Stephen Hwang <[email protected]>
  • Loading branch information
sthwang-metal authored May 9, 2024
1 parent 98c6340 commit cd4b125
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ coverage.txt
.vscode

# binary
load-balancer-api
/load-balancer-api
8 changes: 8 additions & 0 deletions chart/load-balancer-api/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ spec:
imagePullPolicy: {{ .Values.image.pullPolicy }}
args:
- serve
- "--config=/config/loadbalancerapi.yaml"
ports:
- name: http
containerPort: {{ .Values.api.listenPort | default "8080" }}
Expand All @@ -113,6 +114,9 @@ spec:
mountPath: "/dbcerts"
readOnly: true
{{- end }}
- name: config-volume
mountPath: "/config"
readOnly: true
resources:
{{- toYaml .Values.api.resources | nindent 12 }}
{{- with .Values.api.nodeSelector }}
Expand All @@ -138,3 +142,7 @@ spec:
secret:
secretName: "{{ .Values.api.db.certSecret }}"
{{- end }}
- name: config-volume
configMap:
name: {{ include "common.names.fullname" . }}-extra-config

12 changes: 12 additions & 0 deletions chart/load-balancer-api/templates/extra-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "common.names.fullname" . }}-extra-config
labels:
{{- include "common.labels.standard" . | nindent 4 }}
data:
loadbalancerapi.yaml: |
{{- with .Values.api.extraRelations }}
extraRelations:
{{- toYaml . | nindent 6 }}
{{- end }}
4 changes: 4 additions & 0 deletions chart/load-balancer-api/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ api:
extraAnnotations: {}
extraEnvFrom: {}
extraEnvVars: []
extraRelations: {}
# loadbalancer:
# - relation: relationship
# subjectID: subjct-1234567
#- value: "postgresql://user@my-db-server:26257/load_balancer_api"
# name: LOADBALANCERAPI_CRDB_URI
resources: {}
Expand Down
3 changes: 3 additions & 0 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ func serve(ctx context.Context) error {
var resolverOpts []graphapi.Option

config.AppConfig.LoadBalancerLimit = viper.GetInt("load-balancer-limit")
if err := viper.UnmarshalKey("extraRelations", &config.AppConfig.ExtraPermissionRelations); err != nil {
logger.Fatalw("error unmarshaling extraRelations from config", "error", err)
}

if serveDevMode {
enablePlayground = true
Expand Down
31 changes: 19 additions & 12 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@ import (

// AppConfig stores all the config values for our application
var AppConfig struct {
OIDC echojwtx.AuthConfig `mapstructure:"oidc"`
OIDCClient OIDCClientConfig `mapstructure:"oidc"`
CRDB crdbx.Config
Logging loggingx.Config
Server echox.Config
Tracing otelx.Config
Events events.Config
Permissions permissions.Config
LoadBalancerLimit int
Metadata MetadataConfig
RestrictedPorts []int
Supergraph SupergraphConfig
OIDC echojwtx.AuthConfig `mapstructure:"oidc"`
OIDCClient OIDCClientConfig `mapstructure:"oidc"`
CRDB crdbx.Config
Logging loggingx.Config
Server echox.Config
Tracing otelx.Config
Events events.Config
Permissions permissions.Config
LoadBalancerLimit int
Metadata MetadataConfig
RestrictedPorts []int
Supergraph SupergraphConfig
ExtraPermissionRelations map[string][]PermissionRelation
}

// MetadataConfig stores the configuration for metadata
Expand All @@ -46,3 +47,9 @@ type SupergraphConfig struct {
type OIDCClientConfig struct {
Config oauth2x.Config `mapstructure:"client"`
}

// PermissionRelation stores the permission relation metadata needed to create AuthRelationshipRelation
type PermissionRelation struct {
Relation string
SubjectID string
}
11 changes: 11 additions & 0 deletions internal/manualhooks/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"go.infratographer.com/x/gidx"
"golang.org/x/exp/slices"

"go.infratographer.com/load-balancer-api/internal/config"
"go.infratographer.com/load-balancer-api/internal/ent/generated"
"go.infratographer.com/load-balancer-api/internal/ent/generated/hook"
"go.infratographer.com/load-balancer-api/internal/ent/generated/loadbalancer"
Expand Down Expand Up @@ -121,6 +122,16 @@ func LoadBalancerHooks() []ent.Hook {
SubjectID: owner_id,
})

// Add extra relationships based on config
if permissions, ok := config.AppConfig.ExtraPermissionRelations["loadbalancer"]; ok {
for _, p := range permissions {
relationships = append(relationships, events.AuthRelationshipRelation{
Relation: p.Relation,
SubjectID: gidx.PrefixedID(p.SubjectID),
})
}
}

if ok {
cv_owner_id = fmt.Sprintf("%s", fmt.Sprint(owner_id))
pv_owner_id := ""
Expand Down
54 changes: 54 additions & 0 deletions internal/manualhooks/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import (
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"go.infratographer.com/permissions-api/pkg/permissions/mockpermissions"
"go.infratographer.com/x/events"
"go.infratographer.com/x/gidx"

"go.infratographer.com/load-balancer-api/internal/config"
"go.infratographer.com/load-balancer-api/internal/manualhooks"
"go.infratographer.com/load-balancer-api/internal/testutils"
)
Expand Down Expand Up @@ -64,6 +67,57 @@ func Test_LoadbalancerCreateHook(t *testing.T) {
assert.Equal(t, createEventType, msg.Message().EventType)
}

func Test_LoadbalancerCreateHook_Permissions(t *testing.T) {
// Arrange
const ownerString = "owner"
const parentString = "parent"
const subj1 = "subjct-1234567"
const subj2 = "subjct-7654321"

// Mock Permissions
perms := new(mockpermissions.MockPermissions)
perms.On("CreateAuthRelationships", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
perms.On("DeleteAuthRelationships", mock.Anything, mock.Anything, mock.Anything).Return(nil)

ctx := perms.ContextWithHandler(context.Background())

// Populate actual config
config.AppConfig.ExtraPermissionRelations = map[string][]config.PermissionRelation{
"loadbalancer": {
config.PermissionRelation{
Relation: parentString, SubjectID: subj1,
},
config.PermissionRelation{
Relation: ownerString, SubjectID: subj2,
},
},
}

// Mock Events
testutils.EntClient.LoadBalancer.Use(manualhooks.LoadBalancerHooks()...)

// Act
lb := (&testutils.LoadBalancerBuilder{}).MustNew(ctx)

expectedRelation1 := events.AuthRelationshipRelation{
Relation: ownerString, SubjectID: lb.OwnerID,
}

expectedRelation2 := events.AuthRelationshipRelation{
Relation: parentString, SubjectID: subj1,
}

expectedRelation3 := events.AuthRelationshipRelation{
Relation: ownerString, SubjectID: subj2,
}

// Assert
perms.AssertCalled(t, "CreateAuthRelationships", mock.Anything, lb.ID, expectedRelation1, expectedRelation2, expectedRelation3)

// Cleanup
config.AppConfig.ExtraPermissionRelations = map[string][]config.PermissionRelation{}
}

func Test_LoadbalancerUpdateHook(t *testing.T) {
// Arrange
ctx := testutils.MockPermissions(context.Background())
Expand Down

0 comments on commit cd4b125

Please sign in to comment.