Skip to content

Commit d9cca98

Browse files
committed
wire in permission claim to apiServiceExport & binding
1 parent 7cffdae commit d9cca98

12 files changed

Lines changed: 299 additions & 13 deletions

File tree

apiserviceexport.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: kube-bind.io/v1alpha2
2+
kind: APIServiceExportRequest
3+
metadata:
4+
name: sheriffs.wildwest.dev
5+
spec:
6+
resources:
7+
- group: wildwest.dev
8+
resource: sheriffs
9+
versions:
10+
- v1alpha1
11+
status: {}

backend/controllers/serviceexportrequest/serviceexportrequest_reconcile.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ func (r *reconciler) ensureExports(ctx context.Context, cl client.Client, cache
228228
Versions: res.Versions,
229229
})
230230
}
231+
export.Spec.PermissionClaims = req.Spec.PermissionClaims
231232

232233
logger.V(1).Info("Creating APIServiceExport", "name", export.Name, "namespace", export.Namespace)
233234
if err := r.createServiceExport(ctx, cl, export); err != nil {
@@ -288,6 +289,7 @@ func (r *reconciler) validate(ctx context.Context, cl client.Client, req *kubebi
288289
scopes = append(scopes, boundSchema.Spec.Scope)
289290
}
290291

292+
// Check CRD scopes matches.
291293
if len(scopes) > 1 {
292294
first := scopes[0]
293295
for _, scope := range scopes[1:] {
@@ -304,5 +306,30 @@ func (r *reconciler) validate(ctx context.Context, cl client.Client, req *kubebi
304306
}
305307
}
306308

309+
// Add validation if claimable apis are valid here
310+
for _, claim := range req.Spec.PermissionClaims {
311+
if !isClaimableAPI(claim) {
312+
conditions.MarkFalse(
313+
req,
314+
kubebindv1alpha2.APIServiceExportConditionPermissionClaim,
315+
"InvalidPermissionClaim",
316+
conditionsapi.ConditionSeverityError,
317+
"Resource %s is not a valid claimable API",
318+
claim.GroupResource.String(),
319+
)
320+
return fmt.Errorf("resource %s is not a valid claimable API", claim.GroupResource.String())
321+
}
322+
}
323+
307324
return nil
308325
}
326+
327+
// isClaimableAPI checks if a permission claim is for a claimable API.
328+
func isClaimableAPI(claim kubebindv1alpha2.PermissionClaim) bool {
329+
for _, api := range kubebindv1alpha2.ClaimableAPIs {
330+
if claim.Group == api.GroupVersion.Group && claim.Resource == api.Names.Plural {
331+
return true
332+
}
333+
}
334+
return false
335+
}

backend/kubernetes/resources/rbac.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func EnsureBinderClusterRole(ctx context.Context, client client.Client) error {
109109
},
110110
{
111111
APIGroups: []string{"kube-bind.io"},
112-
Resources: []string{"boundaschemas/status"},
112+
Resources: []string{"boundschemas/status"},
113113
Verbs: []string{"get", "list", "patch", "update"},
114114
},
115115
},

cli/pkg/kubectl/bind-apiservice/plugin/servicebindings.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func (b *BindAPIServiceOptions) createAPIServiceBindings(ctx context.Context, co
8989
},
9090
Namespace: "kube-bind",
9191
},
92+
PermissionClaims: request.Spec.PermissionClaims,
9293
},
9394
}, metav1.CreateOptions{})
9495
if err != nil {

deploy/crd/kube-bind.io_apiservicebindings.yaml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,118 @@ spec:
227227
x-kubernetes-validations:
228228
- message: kubeconfigSecretRef is immutable
229229
rule: self == oldSelf
230+
permissionClaims:
231+
description: |-
232+
PermissionClaims records decisions about permission claims requested by the service provider.
233+
Access is granted per GroupResource.
234+
items:
235+
description: |-
236+
permissionClaim selects objects of a GVR that a service provider may
237+
request and that a consumer may accept and allow the service provider access to.
238+
properties:
239+
group:
240+
default: ""
241+
description: |-
242+
group is the name of an API group.
243+
For core groups this is the empty string '""'.
244+
pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$
245+
type: string
246+
resource:
247+
description: |-
248+
resource is the name of the resource.
249+
Note: it is worth noting that you can not ask for permissions for resource provided by a CRD
250+
not provided by an service binding export.
251+
pattern: ^[a-z][-a-z0-9]*[a-z0-9]$
252+
type: string
253+
selector:
254+
description: Selector is a resource selector that selects objects
255+
of a GVR.
256+
properties:
257+
all:
258+
description: |-
259+
all claims all resources for the given group/resource.
260+
This is mutually exclusive with resourceSelector.
261+
type: boolean
262+
labelSelector:
263+
description: LabelSelector is a label selector that selects
264+
objects of a GVR.
265+
properties:
266+
matchExpressions:
267+
description: matchExpressions is a list of label selector
268+
requirements. The requirements are ANDed.
269+
items:
270+
description: |-
271+
A label selector requirement is a selector that contains values, a key, and an operator that
272+
relates the key and values.
273+
properties:
274+
key:
275+
description: key is the label key that the selector
276+
applies to.
277+
type: string
278+
operator:
279+
description: |-
280+
operator represents a key's relationship to a set of values.
281+
Valid operators are In, NotIn, Exists and DoesNotExist.
282+
type: string
283+
values:
284+
description: |-
285+
values is an array of string values. If the operator is In or NotIn,
286+
the values array must be non-empty. If the operator is Exists or DoesNotExist,
287+
the values array must be empty. This array is replaced during a strategic
288+
merge patch.
289+
items:
290+
type: string
291+
type: array
292+
x-kubernetes-list-type: atomic
293+
required:
294+
- key
295+
- operator
296+
type: object
297+
type: array
298+
x-kubernetes-list-type: atomic
299+
matchLabels:
300+
additionalProperties:
301+
type: string
302+
description: |-
303+
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
304+
map is equivalent to an element of matchExpressions, whose key field is "key", the
305+
operator is "In", and the values array contains only "value". The requirements are ANDed.
306+
type: object
307+
type: object
308+
x-kubernetes-map-type: atomic
309+
resourceNames:
310+
description: resourceNames is a list of resource names to
311+
select.
312+
items:
313+
description: |-
314+
SelectorResourceName identifies a specific resource by name.
315+
If backend operates at the namespace level isolation, namespace will be included.
316+
properties:
317+
name:
318+
description: Name is the name of the resource.
319+
type: string
320+
required:
321+
- name
322+
type: object
323+
type: array
324+
type: object
325+
verbs:
326+
description: Verbs is a list of verbs that are required by the
327+
provider to operate.
328+
items:
329+
type: string
330+
type: array
331+
versions:
332+
description: |-
333+
versions is a list of versions that should be exported. If this is empty
334+
a sensible default is chosen by the service provider.
335+
items:
336+
type: string
337+
type: array
338+
required:
339+
- resource
340+
type: object
341+
type: array
230342
required:
231343
- kubeconfigSecretRef
232344
type: object
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
apiVersion: kube-bind.io/v1alpha2
22
kind: APIServiceExportRequest
33
metadata:
4-
name: wildwest.dev
4+
name: cowboys.wildwest.dev
55
spec:
66
resources:
7-
- group: wildwest.dev
8-
resource: sheriffs
9-
versions:
10-
- v1alpha1
117
- group: wildwest.dev
128
resource: cowboys
139
versions:
1410
- v1alpha1
11+
permissionClaims:
12+
- apiGroup: ""
13+
resource: configmaps
14+
verbs:
15+
- get
16+
- list
17+
- watch
18+
- create
19+
selector:
20+
labelSelector:
21+
matchLabels:
22+
app: wildwest
1523
status: {}

kcp/deploy/resources/apiexport-kube-bind.io.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ spec:
4949
crd: {}
5050
- group: kube-bind.io
5151
name: apiservicebindings
52-
schema: v250809-5ed76a1.apiservicebindings.kube-bind.io
52+
schema: v250911-7cffdae.apiservicebindings.kube-bind.io
5353
storage:
5454
crd: {}
5555
- group: kube-bind.io

kcp/deploy/resources/apiresourceschema-apiservicebindings.kube-bind.io.yaml

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ apiVersion: apis.kcp.io/v1alpha1
22
kind: APIResourceSchema
33
metadata:
44
creationTimestamp: null
5-
name: v250809-5ed76a1.apiservicebindings.kube-bind.io
5+
name: v250911-7cffdae.apiservicebindings.kube-bind.io
66
spec:
77
conversion:
88
strategy: None
@@ -222,6 +222,118 @@ spec:
222222
x-kubernetes-validations:
223223
- message: kubeconfigSecretRef is immutable
224224
rule: self == oldSelf
225+
permissionClaims:
226+
description: |-
227+
PermissionClaims records decisions about permission claims requested by the service provider.
228+
Access is granted per GroupResource.
229+
items:
230+
description: |-
231+
permissionClaim selects objects of a GVR that a service provider may
232+
request and that a consumer may accept and allow the service provider access to.
233+
properties:
234+
group:
235+
default: ""
236+
description: |-
237+
group is the name of an API group.
238+
For core groups this is the empty string '""'.
239+
pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$
240+
type: string
241+
resource:
242+
description: |-
243+
resource is the name of the resource.
244+
Note: it is worth noting that you can not ask for permissions for resource provided by a CRD
245+
not provided by an service binding export.
246+
pattern: ^[a-z][-a-z0-9]*[a-z0-9]$
247+
type: string
248+
selector:
249+
description: Selector is a resource selector that selects objects
250+
of a GVR.
251+
properties:
252+
all:
253+
description: |-
254+
all claims all resources for the given group/resource.
255+
This is mutually exclusive with resourceSelector.
256+
type: boolean
257+
labelSelector:
258+
description: LabelSelector is a label selector that selects
259+
objects of a GVR.
260+
properties:
261+
matchExpressions:
262+
description: matchExpressions is a list of label selector
263+
requirements. The requirements are ANDed.
264+
items:
265+
description: |-
266+
A label selector requirement is a selector that contains values, a key, and an operator that
267+
relates the key and values.
268+
properties:
269+
key:
270+
description: key is the label key that the selector
271+
applies to.
272+
type: string
273+
operator:
274+
description: |-
275+
operator represents a key's relationship to a set of values.
276+
Valid operators are In, NotIn, Exists and DoesNotExist.
277+
type: string
278+
values:
279+
description: |-
280+
values is an array of string values. If the operator is In or NotIn,
281+
the values array must be non-empty. If the operator is Exists or DoesNotExist,
282+
the values array must be empty. This array is replaced during a strategic
283+
merge patch.
284+
items:
285+
type: string
286+
type: array
287+
x-kubernetes-list-type: atomic
288+
required:
289+
- key
290+
- operator
291+
type: object
292+
type: array
293+
x-kubernetes-list-type: atomic
294+
matchLabels:
295+
additionalProperties:
296+
type: string
297+
description: |-
298+
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
299+
map is equivalent to an element of matchExpressions, whose key field is "key", the
300+
operator is "In", and the values array contains only "value". The requirements are ANDed.
301+
type: object
302+
type: object
303+
x-kubernetes-map-type: atomic
304+
resourceNames:
305+
description: resourceNames is a list of resource names to
306+
select.
307+
items:
308+
description: |-
309+
SelectorResourceName identifies a specific resource by name.
310+
If backend operates at the namespace level isolation, namespace will be included.
311+
properties:
312+
name:
313+
description: Name is the name of the resource.
314+
type: string
315+
required:
316+
- name
317+
type: object
318+
type: array
319+
type: object
320+
verbs:
321+
description: Verbs is a list of verbs that are required by the
322+
provider to operate.
323+
items:
324+
type: string
325+
type: array
326+
versions:
327+
description: |-
328+
versions is a list of versions that should be exported. If this is empty
329+
a sensible default is chosen by the service provider.
330+
items:
331+
type: string
332+
type: array
333+
required:
334+
- resource
335+
type: object
336+
type: array
225337
required:
226338
- kubeconfigSecretRef
227339
type: object

pkg/konnector/controllers/cluster/serviceexport/serviceexport_reconcile.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,11 +372,11 @@ func (r *reconciler) ensureCRDConditionsCopiedToBoundSchema(ctx context.Context,
372372

373373
if err := r.updateRemoteBoundSchema(ctx, boundSchema); err != nil {
374374
errs = append(errs, err)
375-
allValid = false // at least one BoundAPIResourceSchema is not valid
375+
allValid = false // at least one BoundSchemas is not valid
376376
}
377377
}
378378

379-
// Set APIServiceExport Ready condition based on all BoundAPIResourceSchemas
379+
// Set APIServiceExport Ready condition based on all BoundSchemas
380380
if allValid {
381381
conditions.MarkTrue(
382382
export,
@@ -386,9 +386,9 @@ func (r *reconciler) ensureCRDConditionsCopiedToBoundSchema(ctx context.Context,
386386
conditions.MarkFalse(
387387
export,
388388
kubebindv1alpha2.APIServiceExportConditionConnected,
389-
"BoundAPIResourceSchemasNotValid",
389+
"BoundSchemasNotValid",
390390
conditionsapi.ConditionSeverityWarning,
391-
"One or more BoundAPIResourceSchemas are not valid",
391+
"One or more BoundSchemas are not valid",
392392
)
393393
}
394394

sdk/apis/kubebind/v1alpha2/apiservicebinding_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ type APIServiceBindingSpec struct {
8888
// +kubebuilder:validation:Required
8989
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="kubeconfigSecretRef is immutable"
9090
KubeconfigSecretRef ClusterSecretKeyRef `json:"kubeconfigSecretRef"`
91+
92+
// PermissionClaims records decisions about permission claims requested by the service provider.
93+
// Access is granted per GroupResource.
94+
PermissionClaims []PermissionClaim `json:"permissionClaims,omitempty"`
9195
}
9296

9397
type APIServiceBindingStatus struct {

0 commit comments

Comments
 (0)