Skip to content

Commit 55cb650

Browse files
committed
feat: add imageRegistryCredentials handler
1 parent 4899941 commit 55cb650

29 files changed

+1680
-3
lines changed

api/v1alpha1/clusterconfig_types.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ type GenericClusterConfig struct {
2828
// +optional
2929
ExtraAPIServerCertSANs ExtraAPIServerCertSANs `json:"extraAPIServerCertSANs,omitempty"`
3030

31+
// TODO: Add support for multiple registries.
32+
// +optional
33+
ImageRegistryCredentials ImageRegistryCredentials `json:"imageRegistryCredentials,omitempty"`
34+
3135
// +optional
3236
Addons *Addons `json:"addons,omitempty"`
3337
}
@@ -46,6 +50,7 @@ func (GenericClusterConfig) VariableSchema() clusterv1.VariableSchema {
4650
"",
4751
).VariableSchema().
4852
OpenAPIV3Schema,
53+
"imageRegistryCredentials": ImageRegistryCredentials{}.VariableSchema().OpenAPIV3Schema,
4954
},
5055
},
5156
}
@@ -175,6 +180,40 @@ func (ExtraAPIServerCertSANs) VariableSchema() clusterv1.VariableSchema {
175180
}
176181
}
177182

183+
// ImageRegistryCredentials required for providing credentials for an image registry URL.
184+
type ImageRegistryCredentials struct {
185+
// Registry URL.
186+
URL string `json:"url"`
187+
188+
// Name of the Secret containing the registry credentials.
189+
// The Secret should have keys 'username' and 'password'.
190+
// This credentials Secret is not required for some registries, e.g. ECR.
191+
// +optional
192+
Secret string `json:"secret,omitempty"`
193+
}
194+
195+
func (ImageRegistryCredentials) VariableSchema() clusterv1.VariableSchema {
196+
return clusterv1.VariableSchema{
197+
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
198+
Description: "Extra Subject Alternative Names for the API Server signing cert",
199+
Type: "object",
200+
Properties: map[string]clusterv1.JSONSchemaProps{
201+
"url": {
202+
Description: "Registry URL.",
203+
Type: "string",
204+
},
205+
"secret": {
206+
Description: "Name of the Secret containing the registry credentials. " +
207+
"The Secret should have keys 'username' and 'password'. " +
208+
"This credentials Secret is not required for some registries, e.g. ECR.",
209+
Type: "string",
210+
},
211+
},
212+
Required: []string{"url"},
213+
},
214+
}
215+
}
216+
178217
type Addons struct {
179218
// +optional
180219
CNI *CNI `json:"cni,omitempty"`

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/capi-runtime-extensions/templates/role.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ rules:
2323
resources:
2424
- secrets
2525
verbs:
26+
- create
2627
- get
2728
- list
29+
- patch
2830
- watch
2931
- apiGroups:
3032
- addons.cluster.x-k8s.io

cmd/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/mutation/etcd"
3838
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/mutation/extraapiservercertsans"
3939
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/mutation/httpproxy"
40+
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/mutation/imageregistrycredentials"
4041
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/mutation/kubernetesimagerepository"
4142
)
4243

@@ -133,6 +134,7 @@ func main() {
133134
extraapiservercertsans.NewMetaPatch(),
134135
httpproxy.NewMetaPatch(mgr.GetClient()),
135136
kubernetesimagerepository.NewMetaPatch(),
137+
imageregistrycredentials.NewMetaPatch(mgr.GetClient()),
136138
}
137139

138140
// awsMetaPatchHandlers combines all AWS patch and variable handlers under a single handler.

common/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/spf13/pflag v1.0.5
1212
github.com/stretchr/testify v1.8.4
1313
gomodules.xyz/jsonpatch/v2 v2.4.0
14+
k8s.io/api v0.28.2
1415
k8s.io/apiextensions-apiserver v0.28.2
1516
k8s.io/apimachinery v0.28.2
1617
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
@@ -74,7 +75,6 @@ require (
7475
gopkg.in/inf.v0 v0.9.1 // indirect
7576
gopkg.in/yaml.v2 v2.4.0 // indirect
7677
gopkg.in/yaml.v3 v3.0.1 // indirect
77-
k8s.io/api v0.28.2 // indirect
7878
k8s.io/apiserver v0.28.2 // indirect
7979
k8s.io/client-go v0.28.2 // indirect
8080
k8s.io/cluster-bootstrap v0.27.2 // indirect

common/pkg/testutils/capitest/patches.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package capitest
66
import (
77
"context"
88
"encoding/json"
9+
"fmt"
910
"testing"
1011

1112
"github.com/onsi/gomega"
@@ -55,7 +56,7 @@ func ValidateGeneratePatches[T mutation.GeneratePatches](
5556
}
5657
resp := &runtimehooksv1.GeneratePatchesResponse{}
5758
h.GeneratePatches(context.Background(), req, resp)
58-
g.Expect(resp.Status).To(gomega.Equal(runtimehooksv1.ResponseStatusSuccess))
59+
g.Expect(resp.Status).To(gomega.Equal(runtimehooksv1.ResponseStatusSuccess), fmt.Sprintf("Message: %s", resp.Message))
5960

6061
if len(tt.ExpectedPatchMatchers) == 0 {
6162
g.Expect(resp.Items).To(gomega.BeEmpty())

common/pkg/testutils/capitest/request/items.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package request
55

66
import (
7+
corev1 "k8s.io/api/core/v1"
78
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
89
"k8s.io/apimachinery/pkg/runtime"
910
"k8s.io/apimachinery/pkg/types"
@@ -15,6 +16,13 @@ import (
1516
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest/serializer"
1617
)
1718

19+
const (
20+
ClusterName = "test-cluster"
21+
KubeadmConfigTemplateRequestObjectName = "test-kubeadmconfigtemplate"
22+
KubeadmControlPlaneTemplateRequestObjectName = "test-kubeadmcontrolplanetemplate"
23+
Namespace = corev1.NamespaceDefault
24+
)
25+
1826
// NewRequestItem returns a GeneratePatchesRequestItem with the given variables and object.
1927
func NewRequestItem(
2028
object runtime.Object,
@@ -41,6 +49,10 @@ func NewKubeadmConfigTemplateRequestItem(uid types.UID) runtimehooksv1.GenerateP
4149
Kind: "KubeadmConfigTemplate",
4250
APIVersion: bootstrapv1.GroupVersion.String(),
4351
},
52+
ObjectMeta: metav1.ObjectMeta{
53+
Name: KubeadmConfigTemplateRequestObjectName,
54+
Namespace: Namespace,
55+
},
4456
Spec: bootstrapv1.KubeadmConfigTemplateSpec{
4557
Template: bootstrapv1.KubeadmConfigTemplateResource{
4658
Spec: bootstrapv1.KubeadmConfigSpec{
@@ -66,10 +78,16 @@ func NewKubeadmControlPlaneTemplateRequestItem(
6678
Kind: "KubeadmControlPlaneTemplate",
6779
APIVersion: controlplanev1.GroupVersion.String(),
6880
},
81+
ObjectMeta: metav1.ObjectMeta{
82+
Name: KubeadmControlPlaneTemplateRequestObjectName,
83+
Namespace: Namespace,
84+
},
6985
},
7086
&runtimehooksv1.HolderReference{
7187
Kind: "Cluster",
7288
FieldPath: "spec.controlPlaneRef",
89+
Name: ClusterName,
90+
Namespace: Namespace,
7391
},
7492
uid,
7593
)

docs/content/addons/calico-cni.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,6 @@ configure defaults specific for their environment rather than compiling the defa
3838
The Helm chart comes with default configurations for the Calico Installation CRS per supported provider, but overriding
3939
is possible. To do so, specify:
4040
41-
```bash
41+
```shell
4242
--set-file handlers.CalicoCNI.defaultInstallationConfigMaps.DockerCluster.configMap.content=<file>
4343
```

docs/content/customization/_index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ spec:
3939
additionalNo:
4040
- no-proxy-1.example.com
4141
- no-proxy-2.example.com
42+
imageRegistryCredentials:
43+
url: https://my-registry.io
44+
secret: my-registry-credentials
4245
cni:
4346
provider: calico
4447
```
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
+++
2+
title = "Image registry credentials"
3+
+++
4+
5+
In some network environments it is necessary to use HTTP proxy to successfuly execute HTTP requests.
6+
To configure Kubernetes components (`containerd`, `kubelet`) to use HTTP proxy use the `httpproxypatch`
7+
external patch that will generate appropriate configuration for control plane and worker nodes.
8+
9+
Add image registry credentials to all Nodes in the cluster.
10+
When this handle is enabled, the handler will add `files` and `preKubeadmnCommands` with configurations for
11+
[Kubelet image credential provider](https://kubernetes.io/docs/tasks/administer-cluster/kubelet-credential-provider/)
12+
and [dynamic credential provider](https://github.com/mesosphere/dynamic-credential-provider).
13+
14+
This customization will be available when the
15+
[provider-specific cluster configuration patch]({{< ref "..">}}) is included in the `ClusterClass`.
16+
17+
## Example
18+
19+
If your registry requires static credentials, create a Kubernetes Secret with keys for `username` and `password`:
20+
21+
```shell
22+
kubectl create secret generic my-registry-credentials \
23+
--from-literal username=${REGISTRY_USERNAME} password=${REGISTRY_PASSWORD}
24+
```
25+
26+
On the cluster resource then specify desired image registry credentials:
27+
28+
```yaml
29+
apiVersion: cluster.x-k8s.io/v1beta1
30+
kind: Cluster
31+
metadata:
32+
name: <NAME>
33+
spec:
34+
topology:
35+
variables:
36+
- name: clusterConfig
37+
value:
38+
imageRegistryCredentials:
39+
url: https://my-registry.io
40+
secret: my-registry-credentials
41+
```
42+
43+
Applying this configuration will result in new files and preKubeadmCommands
44+
on the `KubeadmControlPlaneTemplate` and `KubeadmConfigTemplate`.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ require (
2020
k8s.io/client-go v0.28.2
2121
k8s.io/component-base v0.28.2
2222
k8s.io/klog/v2 v2.100.1
23+
k8s.io/kubelet v0.28.2
2324
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
2425
sigs.k8s.io/cluster-api v1.5.1
2526
sigs.k8s.io/controller-runtime v0.16.2

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,8 @@ k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
512512
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
513513
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
514514
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
515+
k8s.io/kubelet v0.28.2 h1:wqe5zKtVhNWwtdABU0mpcWVe8hc6VdVvs2kqQridZRw=
516+
k8s.io/kubelet v0.28.2/go.mod h1:rvd0e7T5TjPcfZvy62P90XhFzp0IhPIOy+Pqy3Rtipo=
515517
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
516518
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
517519
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

0 commit comments

Comments
 (0)