diff --git a/apis/concierge/config/v1alpha1/types_credentialissuer.go.tmpl b/apis/concierge/config/v1alpha1/types_credentialissuer.go.tmpl index f3e2895507..bcb69227e4 100644 --- a/apis/concierge/config/v1alpha1/types_credentialissuer.go.tmpl +++ b/apis/concierge/config/v1alpha1/types_credentialissuer.go.tmpl @@ -155,6 +155,11 @@ type ImpersonationProxyServiceSpec struct { // // +optional Annotations map[string]string `json:"annotations,omitempty"` + + // Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + // + // +optional + Labels map[string]string `json:"labels,omitempty"` } // CredentialIssuerStatus describes the status of the Concierge. diff --git a/deploy/concierge/config.concierge.pinniped.dev_credentialissuers.yaml b/deploy/concierge/config.concierge.pinniped.dev_credentialissuers.yaml index 5e74f080fe..0287401b49 100644 --- a/deploy/concierge/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/deploy/concierge/config.concierge.pinniped.dev_credentialissuers.yaml @@ -86,6 +86,12 @@ spec: description: Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. type: object + labels: + additionalProperties: + type: string + description: Labels specifies zero or more key/value pairs + to set as labels on the provisioned Service. + type: object loadBalancerIP: description: |- LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. diff --git a/generated/1.31/README.adoc b/generated/1.31/README.adoc index 09eda657fd..16b67234a1 100644 --- a/generated/1.31/README.adoc +++ b/generated/1.31/README.adoc @@ -754,6 +754,7 @@ value so that the Concierge can properly advertise the endpoint in the Credentia | *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. + This is not supported on all cloud providers. + | *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. + +| *`labels`* __object (keys:string, values:string)__ | Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + |=== diff --git a/generated/1.31/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.31/apis/concierge/config/v1alpha1/types_credentialissuer.go index f3e2895507..bcb69227e4 100644 --- a/generated/1.31/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.31/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -155,6 +155,11 @@ type ImpersonationProxyServiceSpec struct { // // +optional Annotations map[string]string `json:"annotations,omitempty"` + + // Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + // + // +optional + Labels map[string]string `json:"labels,omitempty"` } // CredentialIssuerStatus describes the status of the Concierge. diff --git a/generated/1.31/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.31/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index a29874df81..14f958625b 100644 --- a/generated/1.31/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.31/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -191,6 +191,13 @@ func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxySer (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/generated/1.31/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.31/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 5e74f080fe..0287401b49 100644 --- a/generated/1.31/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.31/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -86,6 +86,12 @@ spec: description: Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. type: object + labels: + additionalProperties: + type: string + description: Labels specifies zero or more key/value pairs + to set as labels on the provisioned Service. + type: object loadBalancerIP: description: |- LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. diff --git a/generated/1.32/README.adoc b/generated/1.32/README.adoc index d545aeb410..6b9e4532ae 100644 --- a/generated/1.32/README.adoc +++ b/generated/1.32/README.adoc @@ -754,6 +754,7 @@ value so that the Concierge can properly advertise the endpoint in the Credentia | *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. + This is not supported on all cloud providers. + | *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. + +| *`labels`* __object (keys:string, values:string)__ | Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + |=== diff --git a/generated/1.32/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.32/apis/concierge/config/v1alpha1/types_credentialissuer.go index f3e2895507..bcb69227e4 100644 --- a/generated/1.32/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.32/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -155,6 +155,11 @@ type ImpersonationProxyServiceSpec struct { // // +optional Annotations map[string]string `json:"annotations,omitempty"` + + // Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + // + // +optional + Labels map[string]string `json:"labels,omitempty"` } // CredentialIssuerStatus describes the status of the Concierge. diff --git a/generated/1.32/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.32/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index a29874df81..14f958625b 100644 --- a/generated/1.32/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.32/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -191,6 +191,13 @@ func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxySer (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/generated/1.32/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.32/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 5e74f080fe..0287401b49 100644 --- a/generated/1.32/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.32/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -86,6 +86,12 @@ spec: description: Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. type: object + labels: + additionalProperties: + type: string + description: Labels specifies zero or more key/value pairs + to set as labels on the provisioned Service. + type: object loadBalancerIP: description: |- LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. diff --git a/generated/1.33/README.adoc b/generated/1.33/README.adoc index f8805ee9cc..c1682950f1 100644 --- a/generated/1.33/README.adoc +++ b/generated/1.33/README.adoc @@ -754,6 +754,7 @@ value so that the Concierge can properly advertise the endpoint in the Credentia | *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. + This is not supported on all cloud providers. + | *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. + +| *`labels`* __object (keys:string, values:string)__ | Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + |=== diff --git a/generated/1.33/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.33/apis/concierge/config/v1alpha1/types_credentialissuer.go index f3e2895507..bcb69227e4 100644 --- a/generated/1.33/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.33/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -155,6 +155,11 @@ type ImpersonationProxyServiceSpec struct { // // +optional Annotations map[string]string `json:"annotations,omitempty"` + + // Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + // + // +optional + Labels map[string]string `json:"labels,omitempty"` } // CredentialIssuerStatus describes the status of the Concierge. diff --git a/generated/1.33/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.33/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index a29874df81..14f958625b 100644 --- a/generated/1.33/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.33/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -191,6 +191,13 @@ func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxySer (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/generated/1.33/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.33/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 5e74f080fe..0287401b49 100644 --- a/generated/1.33/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.33/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -86,6 +86,12 @@ spec: description: Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. type: object + labels: + additionalProperties: + type: string + description: Labels specifies zero or more key/value pairs + to set as labels on the provisioned Service. + type: object loadBalancerIP: description: |- LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. diff --git a/generated/1.34/README.adoc b/generated/1.34/README.adoc index c901546925..6a0c8e969e 100644 --- a/generated/1.34/README.adoc +++ b/generated/1.34/README.adoc @@ -754,6 +754,7 @@ value so that the Concierge can properly advertise the endpoint in the Credentia | *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. + This is not supported on all cloud providers. + | *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. + +| *`labels`* __object (keys:string, values:string)__ | Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + |=== diff --git a/generated/1.34/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.34/apis/concierge/config/v1alpha1/types_credentialissuer.go index f3e2895507..bcb69227e4 100644 --- a/generated/1.34/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.34/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -155,6 +155,11 @@ type ImpersonationProxyServiceSpec struct { // // +optional Annotations map[string]string `json:"annotations,omitempty"` + + // Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + // + // +optional + Labels map[string]string `json:"labels,omitempty"` } // CredentialIssuerStatus describes the status of the Concierge. diff --git a/generated/1.34/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.34/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index a29874df81..14f958625b 100644 --- a/generated/1.34/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.34/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -191,6 +191,13 @@ func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxySer (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/generated/1.34/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.34/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 5e74f080fe..0287401b49 100644 --- a/generated/1.34/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.34/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -86,6 +86,12 @@ spec: description: Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. type: object + labels: + additionalProperties: + type: string + description: Labels specifies zero or more key/value pairs + to set as labels on the provisioned Service. + type: object loadBalancerIP: description: |- LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. diff --git a/generated/1.35/README.adoc b/generated/1.35/README.adoc index 4bcefa66b8..75fd3d5d87 100644 --- a/generated/1.35/README.adoc +++ b/generated/1.35/README.adoc @@ -754,6 +754,7 @@ value so that the Concierge can properly advertise the endpoint in the Credentia | *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. + This is not supported on all cloud providers. + | *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. + +| *`labels`* __object (keys:string, values:string)__ | Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + |=== diff --git a/generated/1.35/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.35/apis/concierge/config/v1alpha1/types_credentialissuer.go index f3e2895507..bcb69227e4 100644 --- a/generated/1.35/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.35/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -155,6 +155,11 @@ type ImpersonationProxyServiceSpec struct { // // +optional Annotations map[string]string `json:"annotations,omitempty"` + + // Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + // + // +optional + Labels map[string]string `json:"labels,omitempty"` } // CredentialIssuerStatus describes the status of the Concierge. diff --git a/generated/1.35/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.35/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index a29874df81..14f958625b 100644 --- a/generated/1.35/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.35/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -191,6 +191,13 @@ func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxySer (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/generated/1.35/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.35/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 5e74f080fe..0287401b49 100644 --- a/generated/1.35/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.35/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -86,6 +86,12 @@ spec: description: Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. type: object + labels: + additionalProperties: + type: string + description: Labels specifies zero or more key/value pairs + to set as labels on the provisioned Service. + type: object loadBalancerIP: description: |- LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. diff --git a/generated/1.36/README.adoc b/generated/1.36/README.adoc index 56bb46ecc0..2c7a1cdcd3 100644 --- a/generated/1.36/README.adoc +++ b/generated/1.36/README.adoc @@ -754,6 +754,7 @@ value so that the Concierge can properly advertise the endpoint in the Credentia | *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. + This is not supported on all cloud providers. + | *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. + +| *`labels`* __object (keys:string, values:string)__ | Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + |=== diff --git a/generated/1.36/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.36/apis/concierge/config/v1alpha1/types_credentialissuer.go index f3e2895507..bcb69227e4 100644 --- a/generated/1.36/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.36/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -155,6 +155,11 @@ type ImpersonationProxyServiceSpec struct { // // +optional Annotations map[string]string `json:"annotations,omitempty"` + + // Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + // + // +optional + Labels map[string]string `json:"labels,omitempty"` } // CredentialIssuerStatus describes the status of the Concierge. diff --git a/generated/1.36/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.36/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index a29874df81..14f958625b 100644 --- a/generated/1.36/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.36/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -191,6 +191,13 @@ func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxySer (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/generated/1.36/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.36/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 5e74f080fe..0287401b49 100644 --- a/generated/1.36/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.36/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -86,6 +86,12 @@ spec: description: Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. type: object + labels: + additionalProperties: + type: string + description: Labels specifies zero or more key/value pairs + to set as labels on the provisioned Service. + type: object loadBalancerIP: description: |- LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. diff --git a/generated/latest/README.adoc b/generated/latest/README.adoc index 56bb46ecc0..2c7a1cdcd3 100644 --- a/generated/latest/README.adoc +++ b/generated/latest/README.adoc @@ -754,6 +754,7 @@ value so that the Concierge can properly advertise the endpoint in the Credentia | *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. + This is not supported on all cloud providers. + | *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service. + +| *`labels`* __object (keys:string, values:string)__ | Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + |=== diff --git a/generated/latest/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/latest/apis/concierge/config/v1alpha1/types_credentialissuer.go index f3e2895507..bcb69227e4 100644 --- a/generated/latest/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/latest/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -155,6 +155,11 @@ type ImpersonationProxyServiceSpec struct { // // +optional Annotations map[string]string `json:"annotations,omitempty"` + + // Labels specifies zero or more key/value pairs to set as labels on the provisioned Service. + // + // +optional + Labels map[string]string `json:"labels,omitempty"` } // CredentialIssuerStatus describes the status of the Concierge. diff --git a/generated/latest/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/latest/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index a29874df81..14f958625b 100644 --- a/generated/latest/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/latest/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -191,6 +191,13 @@ func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxySer (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/internal/controller/impersonatorconfig/impersonator_config.go b/internal/controller/impersonatorconfig/impersonator_config.go index e0edffeb98..884739704e 100644 --- a/internal/controller/impersonatorconfig/impersonator_config.go +++ b/internal/controller/impersonatorconfig/impersonator_config.go @@ -555,13 +555,26 @@ func (c *impersonatorConfigController) ensureLoadBalancerIsStarted(ctx context.C ObjectMeta: metav1.ObjectMeta{ Name: c.generatedLoadBalancerServiceName, Namespace: c.namespace, - Labels: c.labels, + Labels: c.serviceLabels(config.Service.Labels), Annotations: config.Service.Annotations, }, } return c.createOrUpdateService(ctx, &loadBalancer) } +func (c *impersonatorConfigController) serviceLabels(labelsFromCredentialIssuer map[string]string) map[string]string { + serviceLabels := maps.Clone(c.labels) + if len(labelsFromCredentialIssuer) > 0 { + if serviceLabels == nil { + serviceLabels = map[string]string{} + } + for k, v := range labelsFromCredentialIssuer { + serviceLabels[k] = v + } + } + return serviceLabels +} + func (c *impersonatorConfigController) ensureLoadBalancerIsStopped(ctx context.Context) error { running, service, err := c.serviceExists(c.generatedLoadBalancerServiceName) if err != nil { @@ -600,7 +613,7 @@ func (c *impersonatorConfigController) ensureClusterIPServiceIsStarted(ctx conte ObjectMeta: metav1.ObjectMeta{ Name: c.generatedClusterIPServiceName, Namespace: c.namespace, - Labels: c.labels, + Labels: c.serviceLabels(config.Service.Labels), Annotations: config.Service.Annotations, }, } @@ -1249,6 +1262,10 @@ func validateCredentialIssuerSpec(spec *conciergeconfigv1alpha1.ImpersonationPro return fmt.Errorf("invalid LoadBalancerIP %q", spec.Service.LoadBalancerIP) } + if err := validateServiceLabels(spec.Service.Labels); err != nil { + return err + } + // If service is type "None", a non-empty external endpoint must be specified. if spec.ExternalEndpoint == "" && spec.Service.Type == conciergeconfigv1alpha1.ImpersonationProxyServiceTypeNone { return fmt.Errorf("externalEndpoint must be set when service.type is None") @@ -1263,6 +1280,19 @@ func validateCredentialIssuerSpec(spec *conciergeconfigv1alpha1.ImpersonationPro return nil } +func validateServiceLabels(serviceLabels map[string]string) error { + for k, v := range serviceLabels { + if errs := validation.IsQualifiedName(k); len(errs) > 0 { + return fmt.Errorf("invalid service label key %q: %s", k, strings.Join(errs, "; ")) + } + + if errs := validation.IsValidLabelValue(v); len(errs) > 0 { + return fmt.Errorf("invalid service label value for key %q: %s", k, strings.Join(errs, "; ")) + } + } + return nil +} + func mapHasExactlyOneKey(m map[string]string, key string) bool { if len(m) != 1 { return false diff --git a/internal/controller/impersonatorconfig/impersonator_config_test.go b/internal/controller/impersonatorconfig/impersonator_config_test.go index 2a9e79d5f0..f1a8a1a79c 100644 --- a/internal/controller/impersonatorconfig/impersonator_config_test.go +++ b/internal/controller/impersonatorconfig/impersonator_config_test.go @@ -1011,7 +1011,6 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { r.Equal(installedInNamespace, createdLoadBalancerService.Namespace) r.Equal(corev1.ServiceTypeLoadBalancer, createdLoadBalancerService.Spec.Type) r.Equal("app-name", createdLoadBalancerService.Spec.Selector["app"]) - r.Equal(labels, createdLoadBalancerService.Labels) return createdLoadBalancerService } @@ -1964,7 +1963,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { }) }) - when("credentialissuer has service type loadbalancer and custom annotations", func() { + when("credentialissuer has service type loadbalancer and custom annotations and labels", func() { it.Before(func() { addCredentialIssuerToTrackers(conciergeconfigv1alpha1.CredentialIssuer{ ObjectMeta: metav1.ObjectMeta{Name: credentialIssuerResourceName}, @@ -1974,6 +1973,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { Service: conciergeconfigv1alpha1.ImpersonationProxyServiceSpec{ Type: conciergeconfigv1alpha1.ImpersonationProxyServiceTypeLoadBalancer, Annotations: map[string]string{"some-annotation-key": "some-annotation-value"}, + Labels: map[string]string{"some-label-key": "some-label-value"}, }, }, }, @@ -1987,11 +1987,14 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { r.Len(kubeAPIClient.Actions(), 3) requireNodesListed(kubeAPIClient.Actions()[0]) lbService := requireLoadBalancerWasCreated(kubeAPIClient.Actions()[1]) + wantLabels := maps.Clone(labels) + wantLabels["some-label-key"] = "some-label-value" + r.Equal(wantLabels, lbService.Labels) //nolint:gosec // no credentials here r.Equal(lbService.Annotations, map[string]string{ "some-annotation-key": "some-annotation-value", "credentialissuer.pinniped.dev/annotation-keys": `["some-annotation-key"]`, - "credentialissuer.pinniped.dev/label-keys": `["app","other-key"]`, + "credentialissuer.pinniped.dev/label-keys": `["app","other-key","some-label-key"]`, }) requireCASecretWasCreated(kubeAPIClient.Actions()[2]) requireTLSServerIsRunningWithoutCerts() @@ -2807,8 +2810,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { r.NoError(runControllerSync()) r.Len(kubeAPIClient.Actions(), 4) // no new actions because the controller decides there is nothing to update on the Service - // Add annotations to the CredentialIssuer spec. + // Add annotations and labels to the CredentialIssuer spec. credentialIssuerAnnotations := map[string]string{"my-annotation-key": "my-annotation-val"} + credentialIssuerLabels := map[string]string{"my-label-key": "my-label-val"} updateCredentialIssuerInInformerAndWait(credentialIssuerResourceName, conciergeconfigv1alpha1.CredentialIssuerSpec{ ImpersonationProxy: &conciergeconfigv1alpha1.ImpersonationProxySpec{ Mode: conciergeconfigv1alpha1.ImpersonationProxyModeEnabled, @@ -2816,6 +2820,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { Service: conciergeconfigv1alpha1.ImpersonationProxyServiceSpec{ Type: conciergeconfigv1alpha1.ImpersonationProxyServiceTypeLoadBalancer, Annotations: credentialIssuerAnnotations, + Labels: credentialIssuerLabels, }, }, }, pinnipedInformers.Config().V1alpha1().CredentialIssuers()) @@ -2824,7 +2829,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { r.Len(kubeAPIClient.Actions(), 5) // one more item to update the loadbalancer lbService = requireLoadBalancerWasUpdated(kubeAPIClient.Actions()[4]) wantLabels := maps.Clone(labels) - wantLabels["my-label-key"] = "my-label-from-unrelated-controller-val" + wantLabels["my-label-key"] = "my-label-val" r.Equal(wantLabels, lbService.Labels) //nolint:gosec // no credentials here r.Equal(map[string]string{ @@ -2834,7 +2839,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { "annotation-from-unrelated-controller-key": "annotation-from-unrelated-controller-val", "my-annotation-key": "my-annotation-val", "credentialissuer.pinniped.dev/annotation-keys": `["my-annotation-key"]`, - "credentialissuer.pinniped.dev/label-keys": `["app","other-key"]`, + "credentialissuer.pinniped.dev/label-keys": `["app","my-label-key","other-key"]`, }, lbService.Annotations) requireTLSServerIsRunning(ca, testServerAddr(), nil) requireCredentialIssuer(newSuccessStrategy(localhostIP, ca)) @@ -2890,8 +2895,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { r.NoError(runControllerSync()) r.Len(kubeAPIClient.Actions(), 4) // no new actions because the controller decides there is nothing to update on the Service - // Add annotations to the CredentialIssuer spec. + // Add annotations and labels to the CredentialIssuer spec. credentialIssuerAnnotations := map[string]string{"my-annotation-key": "my-annotation-val"} + credentialIssuerLabels := map[string]string{"my-label-key": "my-label-val"} updateCredentialIssuerInInformerAndWait(credentialIssuerResourceName, conciergeconfigv1alpha1.CredentialIssuerSpec{ ImpersonationProxy: &conciergeconfigv1alpha1.ImpersonationProxySpec{ Mode: conciergeconfigv1alpha1.ImpersonationProxyModeEnabled, @@ -2899,6 +2905,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { Service: conciergeconfigv1alpha1.ImpersonationProxyServiceSpec{ Type: conciergeconfigv1alpha1.ImpersonationProxyServiceTypeClusterIP, Annotations: credentialIssuerAnnotations, + Labels: credentialIssuerLabels, }, }, }, pinnipedInformers.Config().V1alpha1().CredentialIssuers()) @@ -2907,7 +2914,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { r.Len(kubeAPIClient.Actions(), 5) // one more item to update the loadbalancer clusterIPService = requireClusterIPWasUpdated(kubeAPIClient.Actions()[4]) wantLabels := maps.Clone(labels) - wantLabels["my-label-key"] = "my-label-from-unrelated-controller-val" + wantLabels["my-label-key"] = "my-label-val" r.Equal(wantLabels, clusterIPService.Labels) //nolint:gosec // no credentials here r.Equal(map[string]string{ @@ -2917,7 +2924,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { "annotation-from-unrelated-controller-key": "annotation-from-unrelated-controller-val", "my-annotation-key": "my-annotation-val", "credentialissuer.pinniped.dev/annotation-keys": `["my-annotation-key"]`, - "credentialissuer.pinniped.dev/label-keys": `["app","other-key"]`, + "credentialissuer.pinniped.dev/label-keys": `["app","my-label-key","other-key"]`, }, clusterIPService.Annotations) requireTLSServerIsRunning(ca, testServerAddr(), nil) requireCredentialIssuer(newSuccessStrategy(localhostIP, ca)) @@ -3553,6 +3560,58 @@ func TestImpersonatorConfigControllerSync(t *testing.T) { }) }) + when("the CredentialIssuer has an invalid service label key", func() { + it.Before(func() { + addCredentialIssuerToTrackers(conciergeconfigv1alpha1.CredentialIssuer{ + ObjectMeta: metav1.ObjectMeta{Name: credentialIssuerResourceName}, + Spec: conciergeconfigv1alpha1.CredentialIssuerSpec{ + ImpersonationProxy: &conciergeconfigv1alpha1.ImpersonationProxySpec{ + Mode: conciergeconfigv1alpha1.ImpersonationProxyModeEnabled, + Service: conciergeconfigv1alpha1.ImpersonationProxyServiceSpec{ + Labels: map[string]string{"not a valid key": "valid-value"}, + }, + }, + }, + }, pinnipedInformerClient, pinnipedAPIClient) + }) + + it("returns an error", func() { + startInformersAndController() + err := runControllerSync() + r.Error(err) + r.Contains(err.Error(), `could not load CredentialIssuer spec.impersonationProxy: invalid service label key "not a valid key":`) + requireCredentialIssuer(newErrorStrategy(err.Error())) + requireMTLSClientCertProviderIsEmpty() + requireTLSServerWasNeverStarted() + }) + }) + + when("the CredentialIssuer has an invalid service label value", func() { + it.Before(func() { + addCredentialIssuerToTrackers(conciergeconfigv1alpha1.CredentialIssuer{ + ObjectMeta: metav1.ObjectMeta{Name: credentialIssuerResourceName}, + Spec: conciergeconfigv1alpha1.CredentialIssuerSpec{ + ImpersonationProxy: &conciergeconfigv1alpha1.ImpersonationProxySpec{ + Mode: conciergeconfigv1alpha1.ImpersonationProxyModeEnabled, + Service: conciergeconfigv1alpha1.ImpersonationProxyServiceSpec{ + Labels: map[string]string{"valid-key": "not a valid value!"}, + }, + }, + }, + }, pinnipedInformerClient, pinnipedAPIClient) + }) + + it("returns an error", func() { + startInformersAndController() + err := runControllerSync() + r.Error(err) + r.Contains(err.Error(), `could not load CredentialIssuer spec.impersonationProxy: invalid service label value for key "valid-key":`) + requireCredentialIssuer(newErrorStrategy(err.Error())) + requireMTLSClientCertProviderIsEmpty() + requireTLSServerWasNeverStarted() + }) + }) + when("the CredentialIssuer has invalid ExternalEndpoint", func() { it.Before(func() { addCredentialIssuerToTrackers(conciergeconfigv1alpha1.CredentialIssuer{