Skip to content

Commit

Permalink
feat: add azure.skip-authz-namespace
Browse files Browse the repository at this point in the history
Signed-off-by: Fabian Kramm <[email protected]>
  • Loading branch information
FabianKramm committed Nov 3, 2023
1 parent 2f0a77a commit f71089d
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 10 deletions.
3 changes: 3 additions & 0 deletions authz/providers/azure/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Options struct {
ARMCallLimit int
SkipAuthzCheck []string
SkipAuthzForNonAADUsers bool
SkipAuthzNamespace bool
AllowNonResDiscoveryPathAccess bool
UseNamespaceResourceScopeFormat bool
DiscoverResources bool
Expand All @@ -56,6 +57,7 @@ func NewOptions() Options {
ARMCallLimit: defaultArmCallLimit,
SkipAuthzCheck: []string{""},
SkipAuthzForNonAADUsers: true,
SkipAuthzNamespace: false,
AllowNonResDiscoveryPathAccess: true,
UseNamespaceResourceScopeFormat: false,
DiscoverResources: false,
Expand All @@ -70,6 +72,7 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) {
fs.IntVar(&o.ARMCallLimit, "azure.arm-call-limit", o.ARMCallLimit, "No of calls before which webhook switch to new ARM instance to avoid throttling")
fs.StringSliceVar(&o.SkipAuthzCheck, "azure.skip-authz-check", o.SkipAuthzCheck, "name of usernames/email for which authz check will be skipped")
fs.BoolVar(&o.SkipAuthzForNonAADUsers, "azure.skip-authz-for-non-aad-users", o.SkipAuthzForNonAADUsers, "skip authz for non AAD users")
fs.BoolVar(&o.SkipAuthzNamespace, "azure.skip-authz-namespace", o.SkipAuthzNamespace, "skip authz namespace information")
fs.BoolVar(&o.AllowNonResDiscoveryPathAccess, "azure.allow-nonres-discovery-path-access", o.AllowNonResDiscoveryPathAccess, "allow access on Non Resource paths required for discovery, setting it false will require explicit non resource path role assignment for all users in Azure RBAC")
fs.BoolVar(&o.UseNamespaceResourceScopeFormat, "azure.use-ns-resource-scope-format", o.UseNamespaceResourceScopeFormat, "use namespace as resource scope format for making rbac checkaccess calls at namespace scope")
fs.StringVar(&o.KubeConfigFile, "azure.kubeconfig-file", "", "path to the kubeconfig of cluster.")
Expand Down
8 changes: 6 additions & 2 deletions authz/providers/azure/rbac/checkaccessreqhelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ func getResultCacheKey(subRevReq *authzv1.SubjectAccessReviewSpec) string {
return cacheKey
}

func prepareCheckAccessRequestBody(req *authzv1.SubjectAccessReviewSpec, clusterType string, resourceId string, useNamespaceResourceScopeFormat bool) ([]*CheckAccessRequest, error) {
func prepareCheckAccessRequestBody(req *authzv1.SubjectAccessReviewSpec, clusterType string, resourceId string, skipNamespace, useNamespaceResourceScopeFormat bool) ([]*CheckAccessRequest, error) {
/* This is how sample SubjectAccessReview request will look like
{
"kind": "SubjectAccessReview",
Expand Down Expand Up @@ -522,7 +522,11 @@ func prepareCheckAccessRequestBody(req *authzv1.SubjectAccessReviewSpec, cluster
checkaccessreq.Subject.Attributes.Groups = groups
checkaccessreq.Subject.Attributes.ObjectId = userOid
checkaccessreq.Actions = actions[i:j]
checkaccessreq.Resource.Id = getScope(resourceId, req.ResourceAttributes, useNamespaceResourceScopeFormat)
if skipNamespace {
checkaccessreq.Resource.Id = resourceId
} else {
checkaccessreq.Resource.Id = getScope(resourceId, req.ResourceAttributes, useNamespaceResourceScopeFormat)
}
checkAccessReqs = append(checkAccessReqs, &checkaccessreq)
}

Expand Down
20 changes: 16 additions & 4 deletions authz/providers/azure/rbac/checkaccessreqhelper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ func Test_prepareCheckAccessRequestBody(t *testing.T) {
createOperationsMap(clusterType)
wantErr := errors.New("oid info not sent from authenticatoin module")

got, gotErr := prepareCheckAccessRequestBody(req, clusterType, resourceId, false)
got, gotErr := prepareCheckAccessRequestBody(req, clusterType, resourceId, false, false)

if got != nil && gotErr != wantErr {
t.Errorf("Want:%v WantErr:%v, got:%v, gotErr:%v", nil, wantErr, got, gotErr)
Expand All @@ -584,7 +584,7 @@ func Test_prepareCheckAccessRequestBody(t *testing.T) {
clusterType = "arc"
wantErr = errors.New("oid info sent from authenticatoin module is not valid")

got, gotErr = prepareCheckAccessRequestBody(req, clusterType, resourceId, false)
got, gotErr = prepareCheckAccessRequestBody(req, clusterType, resourceId, false, false)

if got != nil && gotErr != wantErr {
t.Errorf("Want:%v WantErr:%v, got:%v, gotErr:%v", nil, wantErr, got, gotErr)
Expand All @@ -600,7 +600,7 @@ func Test_prepareCheckAccessRequestBodyWithNamespace(t *testing.T) {
// testing with new ns scope format
var want string = "resourceId/providers/Microsoft.KubernetesConfiguration/namespaces/dev"

got, gotErr := prepareCheckAccessRequestBody(req, clusterType, resourceId, true)
got, gotErr := prepareCheckAccessRequestBody(req, clusterType, resourceId, false, true)

if got == nil {
t.Errorf("Want: not nil Got: nil, gotErr:%v", gotErr)
Expand All @@ -613,7 +613,19 @@ func Test_prepareCheckAccessRequestBodyWithNamespace(t *testing.T) {
// testing with the old namespace format
want = "resourceId/namespaces/dev"

got, gotErr = prepareCheckAccessRequestBody(req, clusterType, resourceId, false)
got, gotErr = prepareCheckAccessRequestBody(req, clusterType, resourceId, false, false)
if got == nil {
t.Errorf("Want: not nil Got: nil, gotErr:%v", gotErr)
}

if got != nil && got[0].Resource.Id != want {
t.Errorf("Want:%v, got:%v", want, got)
}

// testing without namespace
want = "resourceId"

got, gotErr = prepareCheckAccessRequestBody(req, clusterType, resourceId, true, false)
if got == nil {
t.Errorf("Want: not nil Got: nil, gotErr:%v", gotErr)
}
Expand Down
12 changes: 8 additions & 4 deletions authz/providers/azure/rbac/rbac.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ type AccessInfo struct {
armCallLimit int
skipCheck map[string]void
skipAuthzForNonAADUsers bool
skipAuthzNamespace bool
allowNonResDiscoveryPathAccess bool
useNamespaceResourceScopeFormat bool
lock sync.RWMutex
Expand Down Expand Up @@ -167,6 +168,7 @@ func newAccessInfo(tokenProvider graph.TokenProvider, rbacURL *url.URL, opts aut
azureResourceId: opts.ResourceId,
armCallLimit: opts.ARMCallLimit,
skipAuthzForNonAADUsers: opts.SkipAuthzForNonAADUsers,
skipAuthzNamespace: opts.SkipAuthzNamespace,
allowNonResDiscoveryPathAccess: opts.AllowNonResDiscoveryPathAccess,
useNamespaceResourceScopeFormat: opts.UseNamespaceResourceScopeFormat,
}
Expand Down Expand Up @@ -293,17 +295,19 @@ func (a *AccessInfo) setReqHeaders(req *http.Request) {
}

func (a *AccessInfo) CheckAccess(request *authzv1.SubjectAccessReviewSpec) (*authzv1.SubjectAccessReviewStatus, error) {
checkAccessBodies, err := prepareCheckAccessRequestBody(request, a.clusterType, a.azureResourceId, a.useNamespaceResourceScopeFormat)
checkAccessBodies, err := prepareCheckAccessRequestBody(request, a.clusterType, a.azureResourceId, a.skipAuthzNamespace, a.useNamespaceResourceScopeFormat)
if err != nil {
return nil, errors.Wrap(err, "error in preparing check access request")
}

checkAccessURL := *a.apiURL
// Append the path for azure cluster resource id
checkAccessURL.Path = path.Join(checkAccessURL.Path, a.azureResourceId)
exist, nameSpaceString := getNameSpaceScope(request, a.useNamespaceResourceScopeFormat)
if exist {
checkAccessURL.Path = path.Join(checkAccessURL.Path, nameSpaceString)
if !a.skipAuthzNamespace {
exist, nameSpaceString := getNameSpaceScope(request, a.useNamespaceResourceScopeFormat)
if exist {
checkAccessURL.Path = path.Join(checkAccessURL.Path, nameSpaceString)
}
}

checkAccessURL.Path = path.Join(checkAccessURL.Path, checkAccessPath)
Expand Down

0 comments on commit f71089d

Please sign in to comment.