k8s-operator,cmd/k8s-operator: define ProxyGroupPolicy CRD (#18614)
This commit adds a new custom resource definition to the kubernetes operator named `ProxyGroupPolicy`. This resource is namespace scoped and is used as an allow list for which `ProxyGroup` resources can be used within its namespace. The `spec` contains two fields, `ingress` and `egress`. These should contain the names of `ProxyGroup` resources to denote which can be used as values in the `tailscale.com/proxy-group` annotation within `Service` and `Ingress` resources. The intention is for these policies to be merged within a namespace and produce a `ValidatingAdmissionPolicy` and `ValidatingAdmissionPolicyBinding` for both ingress and egress that prevents users from using names of `ProxyGroup` resources in those annotations. Closes: https://github.com/tailscale/corp/issues/36829 Signed-off-by: David Bond <davidsbond93@gmail.com>main
parent
d468870310
commit
a341eea00b
@ -0,0 +1,139 @@ |
|||||||
|
apiVersion: apiextensions.k8s.io/v1 |
||||||
|
kind: CustomResourceDefinition |
||||||
|
metadata: |
||||||
|
annotations: |
||||||
|
controller-gen.kubebuilder.io/version: v0.17.0 |
||||||
|
name: proxygrouppolicies.tailscale.com |
||||||
|
spec: |
||||||
|
group: tailscale.com |
||||||
|
names: |
||||||
|
kind: ProxyGroupPolicy |
||||||
|
listKind: ProxyGroupPolicyList |
||||||
|
plural: proxygrouppolicies |
||||||
|
shortNames: |
||||||
|
- pgp |
||||||
|
singular: proxygrouppolicy |
||||||
|
scope: Namespaced |
||||||
|
versions: |
||||||
|
- additionalPrinterColumns: |
||||||
|
- jsonPath: .metadata.creationTimestamp |
||||||
|
name: Age |
||||||
|
type: date |
||||||
|
- description: Status of the deployed ProxyGroupPolicy resources. |
||||||
|
jsonPath: .status.conditions[?(@.type == "ProxyGroupPolicyReady")].reason |
||||||
|
name: Status |
||||||
|
type: string |
||||||
|
name: v1alpha1 |
||||||
|
schema: |
||||||
|
openAPIV3Schema: |
||||||
|
type: object |
||||||
|
required: |
||||||
|
- metadata |
||||||
|
- spec |
||||||
|
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: |
||||||
|
description: |- |
||||||
|
Spec describes the desired state of the ProxyGroupPolicy. |
||||||
|
More info: |
||||||
|
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status |
||||||
|
type: object |
||||||
|
properties: |
||||||
|
egress: |
||||||
|
description: |- |
||||||
|
Names of ProxyGroup resources that can be used by Service resources within this namespace. An empty list |
||||||
|
denotes that no egress via ProxyGroups is allowed within this namespace. |
||||||
|
type: array |
||||||
|
items: |
||||||
|
type: string |
||||||
|
ingress: |
||||||
|
description: |- |
||||||
|
Names of ProxyGroup resources that can be used by Ingress resources within this namespace. An empty list |
||||||
|
denotes that no ingress via ProxyGroups is allowed within this namespace. |
||||||
|
type: array |
||||||
|
items: |
||||||
|
type: string |
||||||
|
status: |
||||||
|
description: |- |
||||||
|
Status describes the status of the ProxyGroupPolicy. This is set |
||||||
|
and managed by the Tailscale operator. |
||||||
|
type: object |
||||||
|
properties: |
||||||
|
conditions: |
||||||
|
type: array |
||||||
|
items: |
||||||
|
description: Condition contains details for one aspect of the current state of this API Resource. |
||||||
|
type: object |
||||||
|
required: |
||||||
|
- lastTransitionTime |
||||||
|
- message |
||||||
|
- reason |
||||||
|
- status |
||||||
|
- type |
||||||
|
properties: |
||||||
|
lastTransitionTime: |
||||||
|
description: |- |
||||||
|
lastTransitionTime is the last time the condition transitioned from one status to another. |
||||||
|
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. |
||||||
|
type: string |
||||||
|
format: date-time |
||||||
|
message: |
||||||
|
description: |- |
||||||
|
message is a human readable message indicating details about the transition. |
||||||
|
This may be an empty string. |
||||||
|
type: string |
||||||
|
maxLength: 32768 |
||||||
|
observedGeneration: |
||||||
|
description: |- |
||||||
|
observedGeneration represents the .metadata.generation that the condition was set based upon. |
||||||
|
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date |
||||||
|
with respect to the current state of the instance. |
||||||
|
type: integer |
||||||
|
format: int64 |
||||||
|
minimum: 0 |
||||||
|
reason: |
||||||
|
description: |- |
||||||
|
reason contains a programmatic identifier indicating the reason for the condition's last transition. |
||||||
|
Producers of specific condition types may define expected values and meanings for this field, |
||||||
|
and whether the values are considered a guaranteed API. |
||||||
|
The value should be a CamelCase string. |
||||||
|
This field may not be empty. |
||||||
|
type: string |
||||||
|
maxLength: 1024 |
||||||
|
minLength: 1 |
||||||
|
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ |
||||||
|
status: |
||||||
|
description: status of the condition, one of True, False, Unknown. |
||||||
|
type: string |
||||||
|
enum: |
||||||
|
- "True" |
||||||
|
- "False" |
||||||
|
- Unknown |
||||||
|
type: |
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase. |
||||||
|
type: string |
||||||
|
maxLength: 316 |
||||||
|
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ |
||||||
|
x-kubernetes-list-map-keys: |
||||||
|
- type |
||||||
|
x-kubernetes-list-type: map |
||||||
|
served: true |
||||||
|
storage: true |
||||||
|
subresources: |
||||||
|
status: {} |
||||||
@ -0,0 +1,67 @@ |
|||||||
|
// Copyright (c) Tailscale Inc & contributors
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
//go:build !plan9
|
||||||
|
|
||||||
|
package v1alpha1 |
||||||
|
|
||||||
|
import ( |
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||||
|
) |
||||||
|
|
||||||
|
// Code comments on these types should be treated as user facing documentation-
|
||||||
|
// they will appear on the ProxyGroupPolicy CRD i.e. if someone runs kubectl explain tailnet.
|
||||||
|
|
||||||
|
var ProxyGroupPolicyKind = "ProxyGroupPolicy" |
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:subresource:status
|
||||||
|
// +kubebuilder:resource:scope=Namespaced,shortName=pgp
|
||||||
|
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
|
||||||
|
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=`.status.conditions[?(@.type == "ProxyGroupPolicyReady")].reason`,description="Status of the deployed ProxyGroupPolicy resources."
|
||||||
|
|
||||||
|
type ProxyGroupPolicy struct { |
||||||
|
metav1.TypeMeta `json:",inline"` |
||||||
|
metav1.ObjectMeta `json:"metadata,omitzero"` |
||||||
|
|
||||||
|
// Spec describes the desired state of the ProxyGroupPolicy.
|
||||||
|
// More info:
|
||||||
|
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
|
||||||
|
Spec ProxyGroupPolicySpec `json:"spec"` |
||||||
|
|
||||||
|
// Status describes the status of the ProxyGroupPolicy. This is set
|
||||||
|
// and managed by the Tailscale operator.
|
||||||
|
// +optional
|
||||||
|
Status ProxyGroupPolicyStatus `json:"status"` |
||||||
|
} |
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
type ProxyGroupPolicyList struct { |
||||||
|
metav1.TypeMeta `json:",inline"` |
||||||
|
metav1.ListMeta `json:"metadata"` |
||||||
|
|
||||||
|
Items []ProxyGroupPolicy `json:"items"` |
||||||
|
} |
||||||
|
|
||||||
|
type ProxyGroupPolicySpec struct { |
||||||
|
// Names of ProxyGroup resources that can be used by Ingress resources within this namespace. An empty list
|
||||||
|
// denotes that no ingress via ProxyGroups is allowed within this namespace.
|
||||||
|
// +optional
|
||||||
|
Ingress []string `json:"ingress,omitempty"` |
||||||
|
|
||||||
|
// Names of ProxyGroup resources that can be used by Service resources within this namespace. An empty list
|
||||||
|
// denotes that no egress via ProxyGroups is allowed within this namespace.
|
||||||
|
// +optional
|
||||||
|
Egress []string `json:"egress,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
type ProxyGroupPolicyStatus struct { |
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
|
// +optional
|
||||||
|
Conditions []metav1.Condition `json:"conditions"` |
||||||
|
} |
||||||
|
|
||||||
|
// ProxyGroupPolicyReady is set to True if the ProxyGroupPolicy is available for use by operator workloads.
|
||||||
|
const ProxyGroupPolicyReady ConditionType = "ProxyGroupPolicyReady" |
||||||
Loading…
Reference in new issue