refactor(apigateway): configure api & dashboard listeneres individually
This commit is contained in:
parent
0014927ca9
commit
c0cbd22bb0
7 changed files with 143 additions and 44 deletions
|
@ -48,12 +48,23 @@ type EnvoySpec struct {
|
|||
WorkloadTemplate *WorkloadTemplate `json:"workloadTemplate,omitempty"`
|
||||
}
|
||||
|
||||
type ApiEndpointSpec struct {
|
||||
// JWKSSelector - selector where the JWKS can be retrieved from to enable the API gateway to validate JWTs
|
||||
JWKSSelector *corev1.SecretKeySelector `json:"jwks"`
|
||||
}
|
||||
|
||||
type DashboardEndpointSpec struct{}
|
||||
|
||||
// APIGatewaySpec defines the desired state of APIGateway.
|
||||
type APIGatewaySpec struct {
|
||||
// Envoy - configure the envoy instance and most importantly the control-plane
|
||||
Envoy *EnvoySpec `json:"envoy"`
|
||||
// JWKSSelector - selector where the JWKS can be retrieved from to enable the API gateway to validate JWTs
|
||||
JWKSSelector *corev1.SecretKeySelector `json:"jwks"`
|
||||
// ApiEndpoint - Configure the endpoint for all API routes
|
||||
// this includes the JWT configuration
|
||||
ApiEndpoint *ApiEndpointSpec `json:"apiEndpoint,omitempty"`
|
||||
// DashboardEndpoint - Configure the endpoint for the Supabase dashboard (studio)
|
||||
// this includes optional authentication (basic or Oauth2) for the dashboard
|
||||
DashboardEndpoint *DashboardEndpointSpec `json:"dashboardEndpoint,omitempty"`
|
||||
// ServiceSelector - selector to match all Supabase services (or in fact EndpointSlices) that should be considered for this APIGateway
|
||||
// +kubebuilder:default={"matchExpressions":{{"key": "app.kubernetes.io/part-of", "operator":"In", "values":{"supabase"}},{"key":"supabase.k8s.icb4dc0.de/api-gateway-target","operator":"Exists"}}}
|
||||
ServiceSelector *metav1.LabelSelector `json:"serviceSelector"`
|
||||
|
@ -88,7 +99,7 @@ type APIGateway struct {
|
|||
|
||||
func (g APIGateway) JwksSecretMeta() metav1.ObjectMeta {
|
||||
return metav1.ObjectMeta{
|
||||
Name: g.Spec.JWKSSelector.Name,
|
||||
Name: g.Spec.ApiEndpoint.JWKSSelector.Name,
|
||||
Namespace: g.Namespace,
|
||||
Labels: maps.Clone(g.Labels),
|
||||
}
|
||||
|
|
|
@ -93,11 +93,16 @@ func (in *APIGatewaySpec) DeepCopyInto(out *APIGatewaySpec) {
|
|||
*out = new(EnvoySpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.JWKSSelector != nil {
|
||||
in, out := &in.JWKSSelector, &out.JWKSSelector
|
||||
*out = new(v1.SecretKeySelector)
|
||||
if in.ApiEndpoint != nil {
|
||||
in, out := &in.ApiEndpoint, &out.ApiEndpoint
|
||||
*out = new(ApiEndpointSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.DashboardEndpoint != nil {
|
||||
in, out := &in.DashboardEndpoint, &out.DashboardEndpoint
|
||||
*out = new(DashboardEndpointSpec)
|
||||
**out = **in
|
||||
}
|
||||
if in.ServiceSelector != nil {
|
||||
in, out := &in.ServiceSelector, &out.ServiceSelector
|
||||
*out = new(metav1.LabelSelector)
|
||||
|
@ -147,6 +152,26 @@ func (in *APIGatewayStatus) DeepCopy() *APIGatewayStatus {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ApiEndpointSpec) DeepCopyInto(out *ApiEndpointSpec) {
|
||||
*out = *in
|
||||
if in.JWKSSelector != nil {
|
||||
in, out := &in.JWKSSelector, &out.JWKSSelector
|
||||
*out = new(v1.SecretKeySelector)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApiEndpointSpec.
|
||||
func (in *ApiEndpointSpec) DeepCopy() *ApiEndpointSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ApiEndpointSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AuthProviderMeta) DeepCopyInto(out *AuthProviderMeta) {
|
||||
*out = *in
|
||||
|
@ -485,6 +510,21 @@ func (in *DashboardDbSpec) DeepCopy() *DashboardDbSpec {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DashboardEndpointSpec) DeepCopyInto(out *DashboardEndpointSpec) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardEndpointSpec.
|
||||
func (in *DashboardEndpointSpec) DeepCopy() *DashboardEndpointSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DashboardEndpointSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DashboardList) DeepCopyInto(out *DashboardList) {
|
||||
*out = *in
|
||||
|
|
|
@ -43,11 +43,49 @@ spec:
|
|||
spec:
|
||||
description: APIGatewaySpec defines the desired state of APIGateway.
|
||||
properties:
|
||||
apiEndpoint:
|
||||
description: |-
|
||||
ApiEndpoint - Configure the endpoint for all API routes
|
||||
this includes the JWT configuration
|
||||
properties:
|
||||
jwks:
|
||||
description: JWKSSelector - selector where the JWKS can be retrieved
|
||||
from to enable the API gateway to validate JWTs
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must be
|
||||
a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be
|
||||
defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
required:
|
||||
- jwks
|
||||
type: object
|
||||
componentTypeLabel:
|
||||
default: app.kubernetes.io/name
|
||||
description: ComponentTypeLabel - Label to identify which Supabase
|
||||
component a Service represents (e.g. auth, postgrest, ...)
|
||||
type: string
|
||||
dashboardEndpoint:
|
||||
description: |-
|
||||
DashboardEndpoint - Configure the endpoint for the Supabase dashboard (studio)
|
||||
this includes optional authentication (basic or Oauth2) for the dashboard
|
||||
type: object
|
||||
envoy:
|
||||
description: Envoy - configure the envoy instance and most importantly
|
||||
the control-plane
|
||||
|
@ -2593,30 +2631,6 @@ spec:
|
|||
required:
|
||||
- controlPlane
|
||||
type: object
|
||||
jwks:
|
||||
description: JWKSSelector - selector where the JWKS can be retrieved
|
||||
from to enable the API gateway to validate JWTs
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must be a
|
||||
valid secret key.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
serviceSelector:
|
||||
default:
|
||||
matchExpressions:
|
||||
|
@ -2674,7 +2688,6 @@ spec:
|
|||
x-kubernetes-map-type: atomic
|
||||
required:
|
||||
- envoy
|
||||
- jwks
|
||||
- serviceSelector
|
||||
type: object
|
||||
status:
|
||||
|
|
|
@ -6,6 +6,7 @@ metadata:
|
|||
app.kubernetes.io/managed-by: kustomize
|
||||
name: gateway-sample
|
||||
spec:
|
||||
apiEndpoint:
|
||||
jwks:
|
||||
# will be created by Core resource operator if not present
|
||||
# just make sure the secret name is either based on the name of the core resource or explicitly set
|
||||
|
|
|
@ -71,13 +71,30 @@ _Appears in:_
|
|||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
| `envoy` _[EnvoySpec](#envoyspec)_ | Envoy - configure the envoy instance and most importantly the control-plane | | |
|
||||
| `jwks` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#secretkeyselector-v1-core)_ | JWKSSelector - selector where the JWKS can be retrieved from to enable the API gateway to validate JWTs | | |
|
||||
| `apiEndpoint` _[ApiEndpointSpec](#apiendpointspec)_ | ApiEndpoint - Configure the endpoint for all API routes<br />this includes the JWT configuration | | |
|
||||
| `dashboardEndpoint` _[DashboardEndpointSpec](#dashboardendpointspec)_ | DashboardEndpoint - Configure the endpoint for the Supabase dashboard (studio)<br />this includes optional authentication (basic or Oauth2) for the dashboard | | |
|
||||
| `serviceSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#labelselector-v1-meta)_ | ServiceSelector - selector to match all Supabase services (or in fact EndpointSlices) that should be considered for this APIGateway | \{ matchExpressions:[map[key:app.kubernetes.io/part-of operator:In values:[supabase]] map[key:supabase.k8s.icb4dc0.de/api-gateway-target operator:Exists]] \} | |
|
||||
| `componentTypeLabel` _string_ | ComponentTypeLabel - Label to identify which Supabase component a Service represents (e.g. auth, postgrest, ...) | app.kubernetes.io/name | |
|
||||
|
||||
|
||||
|
||||
|
||||
#### ApiEndpointSpec
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_Appears in:_
|
||||
- [APIGatewaySpec](#apigatewayspec)
|
||||
|
||||
| Field | Description | Default | Validation |
|
||||
| --- | --- | --- | --- |
|
||||
| `jwks` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#secretkeyselector-v1-core)_ | JWKSSelector - selector where the JWKS can be retrieved from to enable the API gateway to validate JWTs | | |
|
||||
|
||||
|
||||
#### AuthProviderMeta
|
||||
|
||||
|
||||
|
@ -319,6 +336,19 @@ _Appears in:_
|
|||
| `dbCredentialsRef` _[DbCredentialsReference](#dbcredentialsreference)_ | DBCredentialsRef - reference to a Secret key where the DB credentials can be retrieved from<br />Credentials need to be stored in basic auth form | | |
|
||||
|
||||
|
||||
#### DashboardEndpointSpec
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_Appears in:_
|
||||
- [APIGatewaySpec](#apigatewayspec)
|
||||
|
||||
|
||||
|
||||
#### DashboardList
|
||||
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
jwksSecretNameField = ".spec.jwks.name"
|
||||
jwksSecretNameField = ".spec.apiEndpoint.jwks.name"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -116,7 +116,7 @@ func (r *APIGatewayReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Ma
|
|||
return nil
|
||||
}
|
||||
|
||||
return []string{gw.Spec.JWKSSelector.Name}
|
||||
return []string{gw.Spec.ApiEndpoint.JWKSSelector.Name}
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting up field index for JWKS secret name: %w", err)
|
||||
|
@ -211,7 +211,7 @@ func (r *APIGatewayReconciler) reconcileJwksSecret(
|
|||
return "", err
|
||||
}
|
||||
|
||||
jwksRaw, ok := jwksSecret.Data[gateway.Spec.JWKSSelector.Key]
|
||||
jwksRaw, ok := jwksSecret.Data[gateway.Spec.ApiEndpoint.JWKSSelector.Key]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("%w in secret %s", ErrNoJwksConfigured, jwksSecret.Name)
|
||||
}
|
||||
|
@ -401,10 +401,10 @@ func (r *APIGatewayReconciler) reconileEnvoyDeployment(
|
|||
{
|
||||
Secret: &corev1.SecretProjection{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: gateway.Spec.JWKSSelector.Name,
|
||||
Name: gateway.Spec.ApiEndpoint.JWKSSelector.Name,
|
||||
},
|
||||
Items: []corev1.KeyToPath{{
|
||||
Key: gateway.Spec.JWKSSelector.Key,
|
||||
Key: gateway.Spec.ApiEndpoint.JWKSSelector.Key,
|
||||
Path: "jwks.json",
|
||||
}},
|
||||
},
|
||||
|
|
|
@ -56,8 +56,12 @@ func (d *APIGatewayCustomDefaulter) Default(ctx context.Context, obj runtime.Obj
|
|||
}
|
||||
apigatewaylog.Info("Defaulting for APIGateway", "name", apiGateway.GetName())
|
||||
|
||||
if apiGateway.Spec.JWKSSelector == nil {
|
||||
apiGateway.Spec.JWKSSelector = &corev1.SecretKeySelector{
|
||||
if apiGateway.Spec.ApiEndpoint == nil {
|
||||
apiGateway.Spec.ApiEndpoint = new(supabasev1alpha1.ApiEndpointSpec)
|
||||
}
|
||||
|
||||
if apiGateway.Spec.ApiEndpoint.JWKSSelector == nil {
|
||||
apiGateway.Spec.ApiEndpoint.JWKSSelector = &corev1.SecretKeySelector{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: supabase.ServiceConfig.JWT.ObjectName(apiGateway),
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue