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: support RBAC bypass by group for OKD resources with requester annotation #413

Merged
merged 28 commits into from
Jul 9, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
203db98
ci: release staging version on every push to this branch
royhadad Jul 6, 2023
5c5422e
test: changing CoreV1 to Discovery
royhadad Jul 6, 2023
d4fb1a0
add kubectl to image, run raw kubectl get command
royhadad Jul 6, 2023
43ae95c
fix permissions to include the api group
royhadad Jul 6, 2023
abff6c1
filter response
royhadad Jul 6, 2023
d0c0e6d
fix build
royhadad Jul 6, 2023
2ff81bc
fix build
royhadad Jul 6, 2023
a34d914
create openshift client
royhadad Jul 6, 2023
d854f32
Merge branch 'main' of github.com:datreeio/admission-webhook-datree i…
royhadad Jul 6, 2023
96c1ed4
feat: finish up openshiftClient
royhadad Jul 6, 2023
ef13f93
fix build
royhadad Jul 6, 2023
d95e092
first draft
royhadad Jul 6, 2023
3d1a51c
cleanup
royhadad Jul 6, 2023
c8979fb
go mod tidy
royhadad Jul 6, 2023
8069566
cleanup
royhadad Jul 6, 2023
aa328a8
fix: only overide if succussfull
royhadad Jul 6, 2023
3bb7a00
fix one lint failure
royhadad Jul 6, 2023
0b2b4e3
revert this later
royhadad Jul 9, 2023
02c9097
add logs
royhadad Jul 9, 2023
c34b574
refactor & test: extract openshift service and client, test the service
royhadad Jul 9, 2023
61393c6
make the client private, only the service is public
royhadad Jul 9, 2023
098ffcc
cleanup
royhadad Jul 9, 2023
324cc7c
handle errors
royhadad Jul 9, 2023
fbb251b
cleanup
royhadad Jul 9, 2023
9c6ae8e
remove deployment on every push to the dev branch
royhadad Jul 9, 2023
8600534
add okd installation command to makefile
royhadad Jul 9, 2023
f6b961e
makefile
royhadad Jul 9, 2023
2a64ffb
makefile
royhadad Jul 9, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,4 @@ spec:
else
echo "Error: Failed to send cluster uninstallation request"; \
fi
{{- end }}
{{- end }}
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ require (
github.com/ghodss/yaml v1.0.0
github.com/google/go-cmp v0.5.9
github.com/lithammer/shortuuid v3.0.0+incompatible
github.com/openshift/client-go v0.0.0-20230705133330-7f808ad59404
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/stretchr/testify v1.8.1
go.uber.org/zap v1.10.0
k8s.io/api v0.27.1
k8s.io/apimachinery v0.27.1
k8s.io/api v0.27.2
k8s.io/apimachinery v0.27.2
k8s.io/client-go v0.27.1
k8s.io/utils v0.0.0-20230505201702-9f6742963106
)
Expand All @@ -31,6 +33,7 @@ require (
github.com/jinzhu/copier v0.3.5 // indirect
github.com/mikefarah/yq/v4 v4.27.3 // indirect
github.com/open-policy-agent/opa v0.49.2 // indirect
github.com/openshift/api v0.0.0-20230705144233-e28cd4dd28a8 // indirect
github.com/owenrumney/go-sarif/v2 v2.1.2 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
Expand Down
14 changes: 10 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,15 @@ github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk=
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
github.com/open-policy-agent/opa v0.49.2 h1:n8ntRq/yDWy+cmYaqSLrHXmrT3tX8WlK28vjFQdC6W8=
github.com/open-policy-agent/opa v0.49.2/go.mod h1:7L3lN5qe8xboRmEHxC5lGjo5KsRMdK+CCLiFoOCP7rU=
github.com/openshift/api v0.0.0-20230705144233-e28cd4dd28a8 h1:ZLMYbvXXYPgytju27PdVQPSMU55oAySGGIWhaDU7LX8=
github.com/openshift/api v0.0.0-20230705144233-e28cd4dd28a8/go.mod h1:yimSGmjsI+XF1mr+AKBs2//fSXIOhhetHGbMlBEfXbs=
github.com/openshift/client-go v0.0.0-20230705133330-7f808ad59404 h1:7Q/RkeK4UHpB25nu7z03tSFlWgWjcnAUbjwI1Ud22H4=
github.com/openshift/client-go v0.0.0-20230705133330-7f808ad59404/go.mod h1:8Hq3t7Ba02Z0sjDGtTCARPXylxbOyzFrbwiqb1ViWMA=
github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U=
github.com/owenrumney/go-sarif/v2 v2.1.2 h1:PMDK7tXShJ9zsB7bfvlpADH5NEw1dfA9xwU8Xtdj73U=
github.com/owenrumney/go-sarif/v2 v2.1.2/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
Expand Down Expand Up @@ -402,10 +408,10 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.27.1 h1:Z6zUGQ1Vd10tJ+gHcNNNgkV5emCyW+v2XTmn+CLjSd0=
k8s.io/api v0.27.1/go.mod h1:z5g/BpAiD+f6AArpqNjkY+cji8ueZDU/WV1jcj5Jk4E=
k8s.io/apimachinery v0.27.1 h1:EGuZiLI95UQQcClhanryclaQE6xjg1Bts6/L3cD7zyc=
k8s.io/apimachinery v0.27.1/go.mod h1:5ikh59fK3AJ287GUvpUsryoMFtH9zj/ARfWCo3AyXTM=
k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo=
k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4=
k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg=
k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
k8s.io/client-go v0.27.1 h1:oXsfhW/qncM1wDmWBIuDzRHNS2tLhK3BZv512Nc59W8=
k8s.io/client-go v0.27.1/go.mod h1:f8LHMUkVb3b9N8bWturc+EDtVVVwZ7ueTVquFAJb2vA=
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
Expand Down
4 changes: 3 additions & 1 deletion internal/startup/startup.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import (
"errors"
"fmt"
"github.com/datreeio/admission-webhook-datree/pkg/openshiftClient"

"net/http"
"os"
Expand Down Expand Up @@ -43,6 +44,7 @@
basicCliClient := clients.NewCliServiceClient(deploymentConfig.URL, basicNetworkValidator, state)
errorReporter := errorReporter.NewErrorReporter(basicCliClient, state)
internalLogger := logger.New("", errorReporter)
openshiftClientInstance, err := openshiftClient.NewOpenshiftClient()

Check failure on line 47 in internal/startup/startup.go

View workflow job for this annotation

GitHub Actions / go linter

ineffectual assignment to err (ineffassign)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO handle this error somehow


defer func() {
if panicErr := recover(); panicErr != nil {
Expand Down Expand Up @@ -87,7 +89,7 @@
panic(err)
}

validationController := controllers.NewValidationController(basicCliClient, state, errorReporter, k8sMetadataUtilInstance)
validationController := controllers.NewValidationController(basicCliClient, state, errorReporter, k8sMetadataUtilInstance, &internalLogger, openshiftClientInstance)
healthController := controllers.NewHealthController()
// set routes
http.HandleFunc("/validate", validationController.Validate)
Expand Down
5 changes: 4 additions & 1 deletion pkg/controllers/validationController.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controllers
import (
"encoding/json"
"fmt"
"github.com/datreeio/admission-webhook-datree/pkg/openshiftClient"
"io"
"net/http"

Expand All @@ -27,12 +28,14 @@ type ValidationController struct {
ErrorReporter *errorReporter.ErrorReporter
}

func NewValidationController(cliServiceClient *clients.CliClient, state *servicestate.ServiceState, errorReporter *errorReporter.ErrorReporter, k8sMetadataUtilInstance *k8sMetadataUtil.K8sMetadataUtil) *ValidationController {
func NewValidationController(cliServiceClient *clients.CliClient, state *servicestate.ServiceState, errorReporter *errorReporter.ErrorReporter, k8sMetadataUtilInstance *k8sMetadataUtil.K8sMetadataUtil, logger *logger.Logger, openshiftClient *openshiftClient.OpenshiftClient) *ValidationController {
validationService := &services.ValidationService{
CliServiceClient: cliServiceClient,
State: state,
K8sMetadataUtil: k8sMetadataUtilInstance,
ErrorReporter: errorReporter,
OpenshiftClient: openshiftClient,
Logger: logger,
}

return &ValidationController{
Expand Down
8 changes: 7 additions & 1 deletion pkg/controllers/validationController_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
_ "embed"
"encoding/json"
"fmt"
"github.com/datreeio/admission-webhook-datree/pkg/logger"
"github.com/datreeio/admission-webhook-datree/pkg/openshiftClient"
"net/http"
"net/http/httptest"
"strings"
Expand Down Expand Up @@ -310,7 +312,11 @@ func mockValidationController(mockedResponse httpClient.Response) *ValidationCon
mockErrorReporterClient.On("ReportError", mock.Anything, mock.Anything).Return(200, nil)
mockErrorReporter := errorReporter.NewErrorReporter(mockErrorReporterClient, mockState)

return NewValidationController(mockedCliServiceClient, mockState, mockErrorReporter, mockK8sMetadataUtil)
mockLogger := &logger.Logger{}

mockOpenshiftClient := &openshiftClient.OpenshiftClient{}

return NewValidationController(mockedCliServiceClient, mockState, mockErrorReporter, mockK8sMetadataUtil, mockLogger, mockOpenshiftClient)
}

func convertPrerunResponseJsonToStruct(prerunResponse []byte) *clients.ClusterEvaluationPrerunDataResponse {
Expand Down
2 changes: 2 additions & 0 deletions pkg/k8sMetadataUtil/k8sMetadataUtil.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import (
"context"
"fmt"
"github.com/datreeio/admission-webhook-datree/pkg/errorReporter"
"os"
"strings"
"time"
Expand All @@ -29,6 +30,7 @@
CreateClientSetError error
leaderElection *leaderElection.LeaderElection
internalLogger logger.Logger
errorReporter *errorReporter.ErrorReporter

Check failure on line 33 in pkg/k8sMetadataUtil/k8sMetadataUtil.go

View workflow job for this annotation

GitHub Actions / go linter

field `errorReporter` is unused (unused)
}

type K8sMetadata struct {
Expand Down
74 changes: 74 additions & 0 deletions pkg/openshiftClient/openshiftClient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package openshiftClient

import (
"context"
userClientV1 "github.com/openshift/client-go/user/clientset/versioned/typed/user/v1"
"github.com/patrickmn/go-cache"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
"time"
)

type OpenshiftClient struct {
userClientV1 userClientV1.UserV1Interface
cache *cache.Cache
}

func NewOpenshiftClient() (*OpenshiftClient, error) {
config, err := rest.InClusterConfig()
if err != nil {
return nil, err
}

userClientV1Instance, err := userClientV1.NewForConfig(config)
if err != nil {
return nil, err
}

return &OpenshiftClient{
userClientV1: userClientV1Instance,
cache: cache.New(1*time.Minute, 10*time.Minute),
}, nil
}

type GroupsByUsers = map[string][]string

const groupsByUsersCacheKey = "groupsByUsers"

func (oc *OpenshiftClient) getGroupsByUsers() (GroupsByUsers, error) {
// try to get from cache
valueFromCache, found := oc.cache.Get(groupsByUsersCacheKey)
if found {
return valueFromCache.(GroupsByUsers), nil
}

// get from API
groups, err := oc.userClientV1.Groups().List(context.TODO(), metav1.ListOptions{})
if err != nil {
return nil, err
}

// convert from array of groups to map of users to groups
groupsByUsers := make(GroupsByUsers)
for _, group := range groups.Items {
for _, user := range group.Users {
groupsByUsers[user] = append(groupsByUsers[user], group.Name)
}
}

// set to cache
oc.cache.Set(groupsByUsersCacheKey, groupsByUsers, 1*time.Minute)
return groupsByUsers, nil
}
func (oc *OpenshiftClient) GetGroupsUserBelongsTo(username string) ([]string, error) {
groupsByUsers, err := oc.getGroupsByUsers()
if err != nil {
return nil, err
}

groups, found := groupsByUsers[username]
if !found {
return []string{}, nil
}
return groups, nil
}
15 changes: 14 additions & 1 deletion pkg/services/validationService.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/datreeio/admission-webhook-datree/pkg/openshiftClient"
"net/http"
"os"
"regexp"
Expand Down Expand Up @@ -59,6 +60,8 @@ type ValidationService struct {
K8sMetadataUtil *k8sMetadataUtil.K8sMetadataUtil
ErrorReporter *errorReporter.ErrorReporter
State *servicestate.ServiceState
OpenshiftClient *openshiftClient.OpenshiftClient
Logger *logger.Logger
}

func (vs *ValidationService) Validate(admissionReviewReq *admission.AdmissionReview, warningMessages *[]string, internalLogger logger.Logger) (admissionReview *admission.AdmissionReview, isSkipped bool) {
Expand Down Expand Up @@ -402,8 +405,18 @@ func (vs *ValidationService) shouldBypassByPermissions(userInfo authenticationv1
}

userName := userInfo.Username
groups := userInfo.Groups
if openShiftRequester != "" {
// override username
userName = openShiftRequester

// override groups
groupsFromOpenshiftClient, err := vs.OpenshiftClient.GetGroupsUserBelongsTo(openShiftRequester)
if err != nil {
vs.Logger.LogError(fmt.Sprintf("Failed to get groups for user %s from openshift client: %s", openShiftRequester, err.Error()))
} else {
groups = groupsFromOpenshiftClient
}
}

for _, userAccount := range bypassPermissions.UserAccounts {
Expand All @@ -419,7 +432,7 @@ func (vs *ValidationService) shouldBypassByPermissions(userInfo authenticationv1
}

for _, bypassGroup := range bypassPermissions.Groups {
for _, userInfoGroup := range userInfo.Groups {
for _, userInfoGroup := range groups {
if match, _ := regexp.MatchString(bypassGroup, userInfoGroup); match {
return true
}
Expand Down
Loading