Skip to content

Commit 1db4267

Browse files
committed
Add CRIOCredentialProviderConfig API and related functionality
- Add feature gate for CRIOCredentialProviderConfig in various feature gate manifests. Signed-off-by: Qi Wang <[email protected]>
1 parent 1b67472 commit 1db4267

19 files changed

+1317
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this
2+
name: "CRIOCredentialProviderConfig"
3+
crdName: "criocredentialproviderconfigs.config.openshift.io"
4+
featureGates:
5+
- CRIOCredentialProviderConfig
6+
tests:
7+
onCreate:
8+
- name: Should create a valid CRIOCredentialProviderConfig
9+
initial: |
10+
apiVersion: config.openshift.io/v1alpha1
11+
kind: CRIOCredentialProviderConfig
12+
spec:
13+
matchImages:
14+
- 123456789.dkr.ecr.us-east-1.amazonaws.com
15+
- "*.azurecr.io"
16+
- gcr.io
17+
- "*.*.registry.io"
18+
- registry.io:8080/path
19+
expected: |
20+
apiVersion: config.openshift.io/v1alpha1
21+
kind: CRIOCredentialProviderConfig
22+
spec:
23+
matchImages:
24+
- 123456789.dkr.ecr.us-east-1.amazonaws.com
25+
- "*.azurecr.io"
26+
- gcr.io
27+
- "*.*.registry.io"
28+
- registry.io:8080/path
29+
- name: Should reject matchImages with invalid characters
30+
initial: |
31+
apiVersion: config.openshift.io/v1alpha1
32+
kind: CRIOCredentialProviderConfig
33+
spec:
34+
matchImages:
35+
- "reg!stry.io"
36+
expectedError: "spec.matchImages[0]: Invalid value: \"string\": invalid matchImages value, must be a valid fully qualified domain name with optional wildcard, port, and path"
37+
- name: Should reject empty matchImages
38+
initial: |
39+
apiVersion: config.openshift.io/v1alpha1
40+
kind: CRIOCredentialProviderConfig
41+
spec:
42+
matchImages:
43+
expectedError: "spec.matchImages: Invalid value: []string{}: must contain at least 1 items"
44+
- name: Should reject matchImages wildcard in the path
45+
initial: |
46+
apiVersion: config.openshift.io/v1alpha1
47+
kind: CRIOCredentialProviderConfig
48+
spec:
49+
matchImages:
50+
- "registry.io:8080/pa*th"
51+
expectedError: "spec.matchImages[0]: Invalid value: \"string\": invalid matchImages value, must be a valid fully qualified domain name with optional wildcard, port, and path"
52+
- name: Should reject wildcard for partial subdomains
53+
initial: |
54+
apiVersion: config.openshift.io/v1alpha1
55+
kind: CRIOCredentialProviderConfig
56+
spec:
57+
matchImages:
58+
- "example.app*.com"
59+
expectedError: "spec.matchImages[0]: Invalid value: \"string\": invalid matchImages value, must be a valid fully qualified domain name with optional wildcard, port, and path"
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package v1alpha1
2+
3+
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4+
5+
// +genclient
6+
// +genclient:nonNamespaced
7+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
8+
9+
// CRIOCredentialProviderConfig holds cluster-wide configurations for CRI-O credential provider. CRI-O credential provider is a binary shipped with CRI-O that provides a way to obtain container image pull credentials from external sources.
10+
// For example, it can be used to fetch mirror registry credentials from secrets resources in the cluster within the same namespace the pod will be running in.
11+
// CRIOCredentialProviderConfig configuration specifies the pod image sources registries that should trigger the CRI-O credential provider execution, which will resolve the CRI-O mirror configurations and obtain the necessary credentials for pod creation.
12+
//
13+
// Compatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.
14+
// +kubebuilder:object:root=true
15+
// +kubebuilder:resource:path=criocredentialproviderconfigs,scope=Cluster
16+
// +kubebuilder:subresource:status
17+
// +openshift:api-approved.openshift.io=https://github.com/openshift/api/pull/1929
18+
// +openshift:file-pattern=cvoRunLevel=0000_10,operatorName=config-operator,operatorOrdering=01
19+
// +openshift:enable:FeatureGate=CRIOCredentialProviderConfig
20+
// +openshift:compatibility-gen:level=4
21+
type CRIOCredentialProviderConfig struct {
22+
metav1.TypeMeta `json:",inline"`
23+
24+
// metadata is the standard object's metadata.
25+
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
26+
// +optional
27+
metav1.ObjectMeta `json:"metadata"`
28+
29+
// spec defines the desired configuration of the CRIO Credential Provider.
30+
// +required
31+
Spec CRIOCredentialProviderConfigSpec `json:"spec,omitzero"`
32+
33+
// status represents the current state of the CRIOCredentialProviderConfig.
34+
// +optional
35+
Status *CRIOCredentialProviderConfigStatus `json:"status,omitempty"`
36+
}
37+
38+
// CRIOCredentialProviderConfigSpec defines the desired configuration of the CRI-O Credential Provider.
39+
type CRIOCredentialProviderConfigSpec struct {
40+
// matchImages is a required list of string patterns used to determine whether
41+
// the CRI-O credential provider should be invoked for a given image. This list is
42+
// passed to the kubelet CredentialProviderConfig, and if any pattern matches
43+
// the requested image, CRI-O credential provider will be invoked to obtain credentials for pulling
44+
// that image or its mirrors.
45+
//
46+
// For more details, see:
47+
// - https://kubernetes.io/docs/tasks/administer-cluster/kubelet-credential-provider/
48+
// - https://github.com/cri-o/crio-credential-provider#architecture
49+
//
50+
// Each entry in matchImages is a pattern which can optionally contain a port and a path.
51+
// Wildcards ('*') are supported for full subdomain labels, such as '*.k8s.io' or 'k8s.*.io',
52+
// and for top-level domains, such as 'k8s.*' (which matches 'k8s.io' or 'k8s.net').
53+
// Wildcards are not allowed in the port or path, nor may they appear in the middle of a hostname label.
54+
// For example, '*.example.com' is valid, but 'example*.*.com' is not.
55+
// Each wildcard matches only a single domain label,
56+
// so '*.io' does **not** match '*.k8s.io'.
57+
//
58+
// A match exists between an image and a matchImage when all of the below are true:
59+
// - Both contain the same number of domain parts and each part matches.
60+
// - The URL path of an matchImages must be a prefix of the target image URL path.
61+
// - If the matchImages contains a port, then the port must match in the image as well.
62+
//
63+
// Example values of matchImages:
64+
// - 123456789.dkr.ecr.us-east-1.amazonaws.com
65+
// - *.azurecr.io
66+
// - gcr.io
67+
// - *.*.registry.io
68+
// - registry.io:8080/path
69+
//
70+
// +kubebuilder:validation:MaxItems=50
71+
// +kubebuilder:validation:MinItems=1
72+
// +listType=set
73+
// +required
74+
MatchImages []MatchImage `json:"matchImages,omitempty"`
75+
}
76+
77+
// +kubebuilder:validation:MaxLength=512
78+
// +kubebuilder:validation:XValidation:rule=`self.matches('^((\\*|[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)(\\.(\\*|[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?))*)(:[0-9]+)?(/[-a-zA-Z0-9_/]*)?$')`,message="invalid matchImages value, must be a valid fully qualified domain name with optional wildcard, port, and path"
79+
type MatchImage string
80+
81+
// +k8s:deepcopy-gen=true
82+
// CRIOCredentialProviderConfigStatus defines the observed state of CRIOCredentialProviderConfig
83+
type CRIOCredentialProviderConfigStatus struct {
84+
// conditions represent the latest available observations of the configuration state
85+
// +optional
86+
// +kubebuilder:validation:MaxItems=4
87+
// +listType=map
88+
// +listMapKey=type
89+
Conditions []metav1.Condition `json:"conditions,omitempty"`
90+
}
91+
92+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
93+
94+
// CRIOCredentialProviderConfigList contains a list of CRIOCredentialProviderConfig resources
95+
//
96+
// Compatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.
97+
// +openshift:compatibility-gen:level=4
98+
type CRIOCredentialProviderConfigList struct {
99+
metav1.TypeMeta `json:",inline"`
100+
101+
// metadata is the standard list's metadata.
102+
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
103+
metav1.ListMeta `json:"metadata"`
104+
105+
Items []CRIOCredentialProviderConfig `json:"items"`
106+
}
107+
108+
const (
109+
// ConditionTypeValidated indicates whether the configuration is failed, or partially valid
110+
ConditionTypeValidated = "Validated"
111+
112+
// ReasonValidationFailed indicates the MatchImages configuration contains invalid patterns
113+
ReasonValidationFailed = "ValidationFailed"
114+
115+
// ReasonConfigurationPartiallyApplied indicates some matchImage entries were ignored due to conflicts
116+
ReasonConfigurationPartiallyApplied = "ConfigurationPartiallyApplied"
117+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
apiVersion: apiextensions.k8s.io/v1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
annotations:
5+
api-approved.openshift.io: https://github.com/openshift/api/pull/1929
6+
api.openshift.io/merged-by-featuregates: "true"
7+
include.release.openshift.io/ibm-cloud-managed: "true"
8+
include.release.openshift.io/self-managed-high-availability: "true"
9+
release.openshift.io/feature-set: CustomNoUpgrade
10+
name: criocredentialproviderconfigs.config.openshift.io
11+
spec:
12+
group: config.openshift.io
13+
names:
14+
kind: CRIOCredentialProviderConfig
15+
listKind: CRIOCredentialProviderConfigList
16+
plural: criocredentialproviderconfigs
17+
singular: criocredentialproviderconfig
18+
scope: Cluster
19+
versions:
20+
- name: v1alpha1
21+
schema:
22+
openAPIV3Schema:
23+
description: |-
24+
CRIOCredentialProviderConfig holds cluster-wide configurations for CRI-O credential provider. CRI-O credential provider is a binary shipped with CRI-O that provides a way to obtain container image pull credentials from external sources.
25+
For example, it can be used to fetch mirror registry credentials from secrets resources in the cluster within the same namespace the pod will be running in.
26+
CRIOCredentialProviderConfig configuration specifies the pod image sources registries that should trigger the CRI-O credential provider execution, which will resolve the CRI-O mirror configurations and obtain the necessary credentials for pod creation.
27+
28+
Compatibility level 4: No compatibility is provided, the API can change at any point for any reason. These capabilities should not be used by applications needing long term support.
29+
properties:
30+
apiVersion:
31+
description: |-
32+
APIVersion defines the versioned schema of this representation of an object.
33+
Servers should convert recognized schemas to the latest internal value, and
34+
may reject unrecognized values.
35+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
36+
type: string
37+
kind:
38+
description: |-
39+
Kind is a string value representing the REST resource this object represents.
40+
Servers may infer this from the endpoint the client submits requests to.
41+
Cannot be updated.
42+
In CamelCase.
43+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
44+
type: string
45+
metadata:
46+
type: object
47+
spec:
48+
description: spec defines the desired configuration of the CRIO Credential
49+
Provider.
50+
properties:
51+
matchImages:
52+
description: |-
53+
matchImages is a required list of string patterns used to determine whether
54+
the CRI-O credential provider should be invoked for a given image. This list is
55+
passed to the kubelet CredentialProviderConfig, and if any pattern matches
56+
the requested image, CRI-O credential provider will be invoked to obtain credentials for pulling
57+
that image or its mirrors.
58+
59+
For more details, see:
60+
- https://kubernetes.io/docs/tasks/administer-cluster/kubelet-credential-provider/
61+
- https://github.com/cri-o/crio-credential-provider#architecture
62+
63+
Each entry in matchImages is a pattern which can optionally contain a port and a path.
64+
Wildcards ('*') are supported for full subdomain labels, such as '*.k8s.io' or 'k8s.*.io',
65+
and for top-level domains, such as 'k8s.*' (which matches 'k8s.io' or 'k8s.net').
66+
Wildcards are not allowed in the port or path, nor may they appear in the middle of a hostname label.
67+
For example, '*.example.com' is valid, but 'example*.*.com' is not.
68+
Each wildcard matches only a single domain label,
69+
so '*.io' does **not** match '*.k8s.io'.
70+
71+
A match exists between an image and a matchImage when all of the below are true:
72+
- Both contain the same number of domain parts and each part matches.
73+
- The URL path of an matchImages must be a prefix of the target image URL path.
74+
- If the matchImages contains a port, then the port must match in the image as well.
75+
76+
Example values of matchImages:
77+
- 123456789.dkr.ecr.us-east-1.amazonaws.com
78+
- *.azurecr.io
79+
- gcr.io
80+
- *.*.registry.io
81+
- registry.io:8080/path
82+
items:
83+
maxLength: 512
84+
type: string
85+
x-kubernetes-validations:
86+
- message: invalid matchImages value, must be a valid fully qualified
87+
domain name with optional wildcard, port, and path
88+
rule: self.matches('^((\\*|[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)(\\.(\\*|[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?))*)(:[0-9]+)?(/[-a-zA-Z0-9_/]*)?$')
89+
maxItems: 50
90+
minItems: 1
91+
type: array
92+
x-kubernetes-list-type: set
93+
required:
94+
- matchImages
95+
type: object
96+
status:
97+
description: status represents the current state of the CRIOCredentialProviderConfig.
98+
properties:
99+
conditions:
100+
description: conditions represent the latest available observations
101+
of the configuration state
102+
items:
103+
description: Condition contains details for one aspect of the current
104+
state of this API Resource.
105+
properties:
106+
lastTransitionTime:
107+
description: |-
108+
lastTransitionTime is the last time the condition transitioned from one status to another.
109+
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
110+
format: date-time
111+
type: string
112+
message:
113+
description: |-
114+
message is a human readable message indicating details about the transition.
115+
This may be an empty string.
116+
maxLength: 32768
117+
type: string
118+
observedGeneration:
119+
description: |-
120+
observedGeneration represents the .metadata.generation that the condition was set based upon.
121+
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
122+
with respect to the current state of the instance.
123+
format: int64
124+
minimum: 0
125+
type: integer
126+
reason:
127+
description: |-
128+
reason contains a programmatic identifier indicating the reason for the condition's last transition.
129+
Producers of specific condition types may define expected values and meanings for this field,
130+
and whether the values are considered a guaranteed API.
131+
The value should be a CamelCase string.
132+
This field may not be empty.
133+
maxLength: 1024
134+
minLength: 1
135+
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
136+
type: string
137+
status:
138+
description: status of the condition, one of True, False, Unknown.
139+
enum:
140+
- "True"
141+
- "False"
142+
- Unknown
143+
type: string
144+
type:
145+
description: type of condition in CamelCase or in foo.example.com/CamelCase.
146+
maxLength: 316
147+
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])$
148+
type: string
149+
required:
150+
- lastTransitionTime
151+
- message
152+
- reason
153+
- status
154+
- type
155+
type: object
156+
maxItems: 4
157+
type: array
158+
x-kubernetes-list-map-keys:
159+
- type
160+
x-kubernetes-list-type: map
161+
type: object
162+
required:
163+
- spec
164+
type: object
165+
served: true
166+
storage: true
167+
subresources:
168+
status: {}

0 commit comments

Comments
 (0)