Repository: kubernetes
Issue: Consider allowing CEL validation of metadata.namespace field of embedded resource
Labels: sig/api-machinery,kind/feature,triage/accepted

### What would you like to be added?

Some context for the issue below: I'm writing operator and generating CRD yaml using `controller-gen`

I have a CRD which has a `runtime.RawExtension` field, its spec looks more or less like this:
```go
type ObjectSpec struct {
	// Raw YAML representation of the kubernetes object to be created.
	// +kubebuilder:validation:EmbeddedResource
	// +kubebuilder:pruning:PreserveUnknownFields
	Manifest runtime.RawExtension `json:"manifest"`
}
```
I'd like to restrict users of that CRD to be able to set the name/namespace/gvk of this embedded resource only during creation, much like with a real resource. I want it to have stable identity, which is not possible if any of those 4 fields are possible to be edited. To do this I can either write and maintain a webhook or add CEL validation to this field. I've actually managed to do this succesfully for **metadata.name**, **apiVersion** and **kind** fields, like here:
```go
// +kubebuilder:validation:XValidation:rule="self.kind == oldSelf.kind",message="Kind is immutable"
// +kubebuilder:validation:XValidation:rule="self.apiVersion == oldSelf.apiVersion",message="APIVersion is immutable"
// +kubebuilder:validation:XValidation:rule="self.metadata.name == oldSelf.metadata.name",message="metadata.name is immutable"
```

Generating CRD yaml using controller-gen resulted in:
```yaml
...
          spec:
            properties:
              manifest:
                description: Raw YAML representation of the kubernetes object to be
                  created.
                type: object
                x-kubernetes-embedded-resource: true
                x-kubernetes-preserve-unknown-fields: true
                x-kubernetes-validations:
                - message: Kind is immutable
                  rule: self.kind == oldSelf.kind
                - message: APIVersion is immutable
                  rule: self.apiVersion == oldSelf.apiVersion
                - message: metadata.name is immutable
                  rule: self.metadata.name == oldSelf.metadata.name
...                  
```
<details>
  <summary>Full CRD</summary>

  ```yaml
  ---
  apiVersion: apiextensions.k8s.io/v1
  kind: CustomResourceDefinition
  metadata:
    annotations:
      controller-gen.kubebuilder.io/version: v0.13.0
    name: objects.embedded.aerf.io
  spec:
    group: embedded.aerf.io
    names:
      kind: Object
      listKind: ObjectList
      plural: objects
      singular: object
    scope: Cluster
    versions:
    - name: v1alpha1
      schema:
        openAPIV3Schema:
          properties:
            apiVersion:
              description: 'APIVersion defines the versioned schema of this representation
                of an object. Servers should convert recognized schemas to the latest
                internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
              type: string
            kind:
              description: 'Kind is a string value representing the REST resource this
                object represents. Servers may infer this from the endpoint the client
                submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
              type: string
            metadata:
              type: object
            spec:
              properties:
                manifest:
                  type: object
                  x-kubernetes-embedded-resource: true
                  x-kubernetes-preserve-unknown-fields: true
                  x-kubernetes-validations:
                  - message: Kind is immutable
                    rule: self.kind == oldSelf.kind
                  - message: APIVersion is immutable
                    rule: self.apiVersion == oldSelf.apiVersion
                  - message: metadata.name is immutable
                    rule: self.metadata.name == oldSelf.metadata.name
              required:
              - manifest
              type: object
          required:
          - spec
          type: object
      served: true
      storage: true
  ```
</details>

And such a CRD is successfully accepted by the APIServer. Unfortunately, as documented in [here](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation-rules), once I add any validation rule to the metadata.namespace field I get an error 
```
compilation failed: ERROR: <input>:1:14: undefined field 'namespace'
```

All of that behaviour is currently matching both [the docs](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation-rules) and the implementation found in https://github.com/kubernetes/kubernetes/blob/55f2bc10435160619d1ece8de49a1c0f8fcdf276/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/model/schemas.go#L39-L73

My suggestion would be to also allow users to include custom CEL validation rules for **namespace** field **for embedded resources**, which is the only one left that currently prevents me from disallowing users of that CR from updating the identity of that embedded resource. 

Initially I've thought that the `x-kubernetes-embedded-resource: true` would take care of this, as stated in [this document](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#rawextension), where it says 
> With x-kubernetes-embedded-resource: true, the apiVersion, kind and metadata are implicitly specified and validated.

BUT it's not said what is validated. I've actually created a very simple CRD with only 1 embedded field to test it (repo [here](https://github.com/aerfio/embedded-resource/blob/main/crds/embedded.aerf.io_objects.yaml)), and it seems like I'm able to edit any subfield I want:
![image](https://github.com/kubernetes/kubernetes/assets/17271979/247c0536-3e02-4d29-841e-405eed92333a)
(`kaf` == `kubectl apply -f`)


Slack discussion I started for this situation: https://kubernetes.slack.com/archives/C0EG7JC6T/p1698949573455489

### Why is this needed?

Adding ability to validate **metadata.namespace** would allow me to create CRD which would embed other k8s resources with the guarantee that the identity of those resources stays stable for particular CR instance. 

Following fields are already open to CEL validation:
- name
- generateName
- apiVersion
- kind
Source: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation-rules