Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for Kong Enterprise RBAC resources #276

Merged
merged 8 commits into from
Mar 3, 2021
Merged
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
35 changes: 35 additions & 0 deletions cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"context"
"fmt"
"net/http"
"os"

Expand Down Expand Up @@ -145,6 +146,9 @@ func syncMain(filenames []string, dry bool, parallelism, delay int, workspace st
if err != nil {
return err
}
if err := checkForRBACResources(*rawState, dumpConfig.RBACResourcesOnly); err != nil {
return err
}
targetState, err := state.Get(rawState)
if err != nil {
return err
Expand Down Expand Up @@ -216,3 +220,34 @@ func validateNoArgs(cmd *cobra.Command, args []string) error {
}
return nil
}

func checkForRBACResources(content utils.KongRawState,
rbacResourcesOnly bool) error {
proxyConfig := containsProxyConfiguration(content)
rbacConfig := containsRBACConfiguration(content)
if proxyConfig && rbacConfig {
common := "At a time, state file(s) must entirely consist of either proxy " +
"configuration or RBAC configuration."
if rbacResourcesOnly {
return fmt.Errorf("When --rbac-resources-only is used, state file(s) " +
"cannot contain any resources other than RBAC resources. " + common)
}
return fmt.Errorf("State file(s) contains RBAC resources. " +
"Please use --rbac-resources-only flag to manage these resources. " + common)
}
return nil
}

func containsProxyConfiguration(content utils.KongRawState) bool {
return len(content.Services) != 0 ||
len(content.Routes) != 0 ||
len(content.Plugins) != 0 ||
len(content.Upstreams) != 0 ||
len(content.Certificates) != 0 ||
len(content.CACertificates) != 0 ||
len(content.Consumers) != 0
}

func containsRBACConfiguration(content utils.KongRawState) bool {
return len(content.RBACRoles) != 0
}
2 changes: 2 additions & 0 deletions cmd/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ func init() {
"select-tag", []string{},
"only entities matching tags specified via this flag are diffed.\n"+
"Multiple tags are ANDed together.")
diffCmd.Flags().BoolVar(&dumpConfig.RBACResourcesOnly, "rbac-resources-only",
false, "sync only the RBAC resources (Kong Enterprise only)")
diffCmd.Flags().BoolVar(&diffCmdNonZeroExitCode, "non-zero-exit-code",
false, "return exit code 2 if there is a diff present,\n"+
"exit code 0 if no diff is found,\n"+
Expand Down
3 changes: 2 additions & 1 deletion cmd/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,6 @@ func init() {
"select-tag", []string{},
"only entities matching tags specified via this flag are exported.\n"+
"Multiple tags are ANDed together.")

dumpCmd.Flags().BoolVar(&dumpConfig.RBACResourcesOnly, "rbac-resources-only",
false, "export only the RBAC resources (Kong Enterprise only)")
}
2 changes: 2 additions & 0 deletions cmd/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,6 @@ func init() {
"select-tag", []string{},
"only entities matching tags specified via this flag are deleted.\n"+
"Multiple tags are ANDed together.")
resetCmd.Flags().BoolVar(&dumpConfig.RBACResourcesOnly, "rbac-resources-only",
false, "reset only the RBAC resources (Kong Enterprise only)")
}
2 changes: 2 additions & 0 deletions cmd/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ func init() {
"select-tag", []string{},
"only entities matching tags specified via this flag are synced.\n"+
"Multiple tags are ANDed together.")
syncCmd.Flags().BoolVar(&dumpConfig.RBACResourcesOnly, "rbac-resources-only",
false, "diff only the RBAC resources (Kong Enterprise only)")
syncCmd.Flags().IntVar(&syncCmdDBUpdateDelay, "db-update-propagation-delay",
0, "aritificial delay in seconds that is injected between insert operations \n"+
"for related entities (usually for cassandra deployments).\n"+
Expand Down
8 changes: 7 additions & 1 deletion cmd/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
)

var (
validateCmdKongStateFile []string
validateCmdKongStateFile []string
validateCmdRBACResourcesOnly bool
)

// validateCmd represents the diff command
Expand Down Expand Up @@ -43,6 +44,9 @@ this command.
if err != nil {
return err
}
if err := checkForRBACResources(*rawState, validateCmdRBACResourcesOnly); err != nil {
return err
}
// this catches foreign relation errors
_, err = state.Get(rawState)
if err != nil {
Expand All @@ -62,6 +66,8 @@ this command.

func init() {
rootCmd.AddCommand(validateCmd)
validateCmd.Flags().BoolVar(&validateCmdRBACResourcesOnly, "rbac-resources-only",
false, "indicate that the state file(s) contain RBAC resources only (Kong Enterprise only)")
validateCmd.Flags().StringSliceVarP(&validateCmdKongStateFile,
"state", "s", []string{"kong.yaml"}, "file(s) containing Kong's configuration.\n"+
"This flag can be specified multiple times for multiple files.\n"+
Expand Down
4 changes: 3 additions & 1 deletion crud/registry.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package crud

import "github.com/pkg/errors"
import (
"github.com/pkg/errors"
)

// Kind represents Kind of an entity or object.
type Kind string
Expand Down
30 changes: 30 additions & 0 deletions diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func NewSyncer(current, target *state.KongState) (*Syncer, error) {
s.postProcess.MustRegister("acl-group", &aclGroupPostAction{current})
s.postProcess.MustRegister("oauth2-cred", &oauth2CredPostAction{current})
s.postProcess.MustRegister("mtls-auth", &mtlsAuthPostAction{current})
s.postProcess.MustRegister("rbac-role", &rbacRolePostAction{current})
s.postProcess.MustRegister("rbac-endpointpermission", &rbacEndpointPermissionPostAction{current})
return s, nil
}

Expand Down Expand Up @@ -179,6 +181,20 @@ func (sc *Syncer) delete() error {
return err
}

err = sc.deleteRBACEndpointPermissions()
if err != nil {
return err
}

// barrier for foreign relations
// RBAC endpoint permissions must be deleted before RBAC roles
sc.wait()

err = sc.deleteRBACRoles()
if err != nil {
return err
}

// finish delete before returning
sc.wait()

Expand Down Expand Up @@ -272,6 +288,20 @@ func (sc *Syncer) createUpdate() error {
return err
}

err = sc.createUpdateRBACRoles()
if err != nil {
return err
}

// barrier for foreign relations
// RBAC roles must be created before endpoint permissions
sc.wait()

err = sc.createUpdateRBACEndpointPermissions()
if err != nil {
return err
}

// finish createUpdate before returning
sc.wait()

Expand Down
32 changes: 32 additions & 0 deletions diff/postProcess.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,35 @@ func (crud *mtlsAuthPostAction) Delete(args ...crud.Arg) (crud.Arg, error) {
func (crud *mtlsAuthPostAction) Update(args ...crud.Arg) (crud.Arg, error) {
return nil, crud.currentState.MTLSAuths.Update(*args[0].(*state.MTLSAuth))
}

type rbacRolePostAction struct {
currentState *state.KongState
}

func (crud *rbacRolePostAction) Create(args ...crud.Arg) (crud.Arg, error) {
return nil, crud.currentState.RBACRoles.Add(*args[0].(*state.RBACRole))
}

func (crud *rbacRolePostAction) Delete(args ...crud.Arg) (crud.Arg, error) {
return nil, crud.currentState.RBACRoles.Delete(*((args[0].(*state.RBACRole)).ID))
}

func (crud *rbacRolePostAction) Update(args ...crud.Arg) (crud.Arg, error) {
return nil, crud.currentState.RBACRoles.Update(*args[0].(*state.RBACRole))
}

type rbacEndpointPermissionPostAction struct {
currentState *state.KongState
}

func (crud *rbacEndpointPermissionPostAction) Create(args ...crud.Arg) (crud.Arg, error) {
return nil, crud.currentState.RBACEndpointPermissions.Add(*args[0].(*state.RBACEndpointPermission))
}

func (crud *rbacEndpointPermissionPostAction) Delete(args ...crud.Arg) (crud.Arg, error) {
return nil, crud.currentState.RBACEndpointPermissions.Delete(args[0].(*state.RBACEndpointPermission).Identifier())
}

func (crud *rbacEndpointPermissionPostAction) Update(args ...crud.Arg) (crud.Arg, error) {
return nil, crud.currentState.RBACEndpointPermissions.Update(*args[0].(*state.RBACEndpointPermission))
}
94 changes: 94 additions & 0 deletions diff/rbac_endpoint_permission.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package diff

import (
"github.com/kong/deck/crud"
"github.com/kong/deck/state"
"github.com/pkg/errors"
)

func (sc *Syncer) deleteRBACEndpointPermissions() error {
currentRBACEndpointPermissions, err := sc.currentState.RBACEndpointPermissions.GetAll()
if err != nil {
return errors.Wrap(err, "error fetching eps from state")
}

for _, ep := range currentRBACEndpointPermissions {
n, err := sc.deleteRBACEndpointPermission(ep)
if err != nil {
return err
}
if n != nil {
err = sc.queueEvent(*n)
if err != nil {
return err
}
}

}
return nil
}

func (sc *Syncer) deleteRBACEndpointPermission(ep *state.RBACEndpointPermission) (*Event, error) {
_, err := sc.targetState.RBACEndpointPermissions.Get(ep.Identifier())
if err == state.ErrNotFound {
return &Event{
Op: crud.Delete,
Kind: "rbac-endpointpermission",
Obj: ep,
}, nil
}
if err != nil {
return nil, errors.Wrapf(err, "looking up rbac ep '%v'",
ep.ID)
}
return nil, nil
}

func (sc *Syncer) createUpdateRBACEndpointPermissions() error {
targetRBACEndpointPermissions, err := sc.targetState.RBACEndpointPermissions.GetAll()
if err != nil {
return errors.Wrap(err, "error fetching rbac eps from state")
}

for _, ep := range targetRBACEndpointPermissions {
n, err := sc.createUpdateRBACEndpointPermission(ep)
if err != nil {
return err
}
if n != nil {
err = sc.queueEvent(*n)
if err != nil {
return err
}
}
}
return nil
}

func (sc *Syncer) createUpdateRBACEndpointPermission(ep *state.RBACEndpointPermission) (*Event, error) {
epCopy := &state.RBACEndpointPermission{RBACEndpointPermission: *ep.DeepCopy()}
currentEp, err := sc.currentState.RBACEndpointPermissions.Get(ep.Identifier())

if err == state.ErrNotFound {
return &Event{
Op: crud.Create,
Kind: "rbac-endpointpermission",
Obj: epCopy,
}, nil
}
if err != nil {
return nil, errors.Wrapf(err, "error looking up rbac endpoint permission %v",
ep.Identifier())
}

// found, check if update needed
if !currentEp.EqualWithOpts(epCopy, false, true, false) {
return &Event{
Op: crud.Update,
Kind: "rbac-endpointpermission",
Obj: epCopy,
OldObj: currentEp,
}, nil
}
return nil, nil
}
Loading