Skip to content

Commit be16da9

Browse files
authored
fix: image registries with no credentials but with a CA (#927)
**What problem does this PR solve?**: Passing `imageRegistries` with a CA but without credentials is still a valid configuration and should not error. **Which issue(s) this PR fixes**: Fixes # **How Has This Been Tested?**: <!-- Please describe the tests that you ran to verify your changes. Provide output from the tests and any manual steps needed to replicate the tests. --> **Special notes for your reviewer**: <!-- Use this to provide any additional information to the reviewers. This may include: - Best way to review the PR. - Where the author wants the most review attention on. - etc. -->
1 parent 08f70d4 commit be16da9

File tree

3 files changed

+115
-49
lines changed

3 files changed

+115
-49
lines changed

pkg/handlers/generic/mutation/imageregistries/credentials/credential_provider_config_files.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"path"
1212
"text/template"
1313

14+
corev1 "k8s.io/api/core/v1"
1415
credentialproviderv1 "k8s.io/kubelet/pkg/apis/credentialprovider/v1"
1516
cabpkv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
1617

@@ -28,6 +29,8 @@ const (
2829
kubeletDynamicCredentialProviderConfigOnRemote = "/etc/kubernetes/dynamic-credential-provider-config.yaml"
2930

3031
azureCloudConfigFilePath = "/etc/kubernetes/azure.json"
32+
33+
secretKeyForCACert = "ca.crt"
3134
)
3235

3336
var (
@@ -47,10 +50,11 @@ var (
4750
)
4851

4952
type providerConfig struct {
50-
URL string
51-
Username string
52-
Password string
53-
Mirror bool
53+
URL string
54+
Username string
55+
Password string
56+
HasCACert bool
57+
Mirror bool
5458
}
5559

5660
func (c providerConfig) isCredentialsEmpty() bool {
@@ -249,3 +253,12 @@ func fileFromTemplate(
249253
Permissions: "0600",
250254
}, nil
251255
}
256+
257+
func secretHasCACert(secret *corev1.Secret) bool {
258+
if secret == nil {
259+
return false
260+
}
261+
262+
_, ok := secret.Data[secretKeyForCACert]
263+
return ok
264+
}

pkg/handlers/generic/mutation/imageregistries/credentials/inject.go

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func (h *imageRegistriesPatchHandler) Mutate(
116116
}
117117

118118
if globalMirrorErr == nil {
119-
mirrorCredentials, generateErr := mirrorConfigFromGlobalImageRegistryMirror(
119+
mirrorCredentials, generateErr := mirrorWithOptionalCredentialsFromGlobalImageRegistryMirror(
120120
ctx,
121121
h.client,
122122
globalMirror,
@@ -131,19 +131,19 @@ func (h *imageRegistriesPatchHandler) Mutate(
131131
)
132132
}
133133

134-
needCredentials, err := needImageRegistryCredentialsConfiguration(
134+
registriesThatNeedConfiguration, err := providerConfigsThatNeedConfiguration(
135135
registriesWithOptionalCredentials,
136136
)
137137
if err != nil {
138138
return err
139139
}
140-
if !needCredentials {
141-
log.V(5).Info("Only Global Registry Mirror is defined but credentials are not needed")
140+
if len(registriesThatNeedConfiguration) == 0 {
141+
log.V(5).Info("Image registry credentials are not needed")
142142
return nil
143143
}
144144

145145
files, commands, generateErr := generateFilesAndCommands(
146-
registriesWithOptionalCredentials,
146+
registriesThatNeedConfiguration,
147147
clusterKey.Name,
148148
)
149149
if generateErr != nil {
@@ -185,7 +185,7 @@ func (h *imageRegistriesPatchHandler) Mutate(
185185
return err
186186
}
187187

188-
err = createSecretIfNeeded(ctx, h.client, registriesWithOptionalCredentials, cluster)
188+
err = createSecretIfNeeded(ctx, h.client, registriesThatNeedConfiguration, cluster)
189189
if err != nil {
190190
return err
191191
}
@@ -243,7 +243,7 @@ func (h *imageRegistriesPatchHandler) Mutate(
243243
return err
244244
}
245245

246-
err = createSecretIfNeeded(ctx, h.client, registriesWithOptionalCredentials, cluster)
246+
err = createSecretIfNeeded(ctx, h.client, registriesThatNeedConfiguration, cluster)
247247
if err != nil {
248248
return err
249249
}
@@ -332,12 +332,13 @@ func registryWithOptionalCredentialsFromImageRegistryCredentials(
332332
if secret != nil {
333333
registryWithOptionalCredentials.Username = string(secret.Data["username"])
334334
registryWithOptionalCredentials.Password = string(secret.Data["password"])
335+
registryWithOptionalCredentials.HasCACert = secretHasCACert(secret)
335336
}
336337

337338
return registryWithOptionalCredentials, nil
338339
}
339340

340-
func mirrorConfigFromGlobalImageRegistryMirror(
341+
func mirrorWithOptionalCredentialsFromGlobalImageRegistryMirror(
341342
ctx context.Context,
342343
c ctrlclient.Client,
343344
mirror v1alpha1.GlobalImageRegistryMirror,
@@ -365,6 +366,7 @@ func mirrorConfigFromGlobalImageRegistryMirror(
365366
if secret != nil {
366367
mirrorCredentials.Username = string(secret.Data["username"])
367368
mirrorCredentials.Password = string(secret.Data["password"])
369+
mirrorCredentials.HasCACert = secretHasCACert(secret)
368370
}
369371

370372
return mirrorCredentials, nil
@@ -438,31 +440,35 @@ func createSecretIfNeeded(
438440
// This handler reads input from two user provided variables: globalImageRegistryMirror and imageRegistries.
439441
// We expect if imageRegistries is set it will either have static credentials
440442
// or be for a registry where the credential plugin returns the credentials, ie ECR, GCR, ACR, etc,
443+
// or have no credentials set but to contain a CA cert,
441444
// and if that is not the case we assume the users missed setting static credentials and return an error.
442445
// However, in addition to passing credentials with the globalImageRegistryMirror variable,
443446
// it can also be used to only set Containerd mirror configuration,
444-
// in that case it valid for static credentials to not be set and will return false, no error
447+
// in which case it is valid for static credentials to not be set and will be skipped, no error
445448
// and this handler will skip generating any credential plugin related configuration.
446-
func needImageRegistryCredentialsConfiguration(configs []providerConfig) (bool, error) {
449+
func providerConfigsThatNeedConfiguration(configs []providerConfig) ([]providerConfig, error) {
450+
var needConfiguration []providerConfig //nolint:prealloc // We don't know the size of the slice yet.
447451
for _, config := range configs {
448452
requiresStaticCredentials, err := config.requiresStaticCredentials()
449453
if err != nil {
450-
return false,
454+
return nil,
451455
fmt.Errorf("error determining if Image Registry is a supported provider: %w", err)
452456
}
453457
// verify the credentials are actually set if the plugin requires static credentials
454458
if config.isCredentialsEmpty() && requiresStaticCredentials {
455-
// not setting credentials for a mirror is valid
456-
// but if it's the only configuration then return false here and exit the handler early
457-
if config.Mirror {
458-
if len(configs) == 1 {
459-
return false, nil
460-
}
461-
} else {
462-
return false, fmt.Errorf("invalid image registry: %s: %w", config.URL, ErrCredentialsNotFound)
459+
if config.Mirror || config.HasCACert {
460+
// not setting credentials for a mirror is valid, but won't need any configuration
461+
// not setting credentials for a registry with a CA cert is valid, but won't need any configuration
462+
continue
463463
}
464+
return nil, fmt.Errorf(
465+
"invalid image registry: %s: %w",
466+
config.URL,
467+
ErrCredentialsNotFound,
468+
)
464469
}
470+
needConfiguration = append(needConfiguration, config)
465471
}
466472

467-
return true, nil
473+
return needConfiguration, nil
468474
}

pkg/handlers/generic/mutation/imageregistries/credentials/inject_test.go

Lines changed: 72 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,23 @@ const (
3333
validSecretName = "myregistry-credentials"
3434
)
3535

36-
func Test_needImageRegistryCredentialsConfiguration(t *testing.T) {
36+
func Test_providerConfigsThatNeedConfiguration(t *testing.T) {
3737
t.Parallel()
3838

3939
testCases := []struct {
40-
name string
41-
configs []providerConfig
42-
need bool
43-
wantErr error
40+
name string
41+
configs []providerConfig
42+
expected []providerConfig
43+
wantErr error
4444
}{
4545
{
46-
name: "ECR credentials",
46+
name: "ECR registry with no credentials",
4747
configs: []providerConfig{
4848
{URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com"},
4949
},
50-
need: true,
50+
expected: []providerConfig{
51+
{URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com"},
52+
},
5153
},
5254
{
5355
name: "registry with static credentials",
@@ -56,35 +58,45 @@ func Test_needImageRegistryCredentialsConfiguration(t *testing.T) {
5658
Username: "myuser",
5759
Password: "mypassword",
5860
}},
59-
need: true,
61+
expected: []providerConfig{{
62+
URL: "https://myregistry.com",
63+
Username: "myuser",
64+
Password: "mypassword",
65+
}},
6066
},
6167
{
62-
name: "ECR mirror",
63-
configs: []providerConfig{
64-
{
65-
URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com",
66-
Mirror: true,
67-
},
68-
},
69-
need: true,
68+
name: "ECR mirror with no credentials",
69+
configs: []providerConfig{{
70+
URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com",
71+
Mirror: true,
72+
}},
73+
expected: []providerConfig{{
74+
URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com",
75+
Mirror: true,
76+
}},
7077
},
7178
{
7279
name: "mirror with static credentials",
7380
configs: []providerConfig{{
74-
URL: "https://myregistry.com",
81+
URL: "https://mymirror.com",
82+
Username: "myuser",
83+
Password: "mypassword",
84+
Mirror: true,
85+
}},
86+
expected: []providerConfig{{
87+
URL: "https://mymirror.com",
7588
Username: "myuser",
7689
Password: "mypassword",
7790
Mirror: true,
7891
}},
79-
need: true,
8092
},
8193
{
8294
name: "mirror with no credentials",
8395
configs: []providerConfig{{
84-
URL: "https://myregistry.com",
96+
URL: "https://mymirror.com",
8597
Mirror: true,
8698
}},
87-
need: false,
99+
expected: nil,
88100
},
89101
{
90102
name: "a registry with static credentials and a mirror with no credentials",
@@ -93,23 +105,58 @@ func Test_needImageRegistryCredentialsConfiguration(t *testing.T) {
93105
URL: "https://myregistry.com",
94106
Username: "myuser",
95107
Password: "mypassword",
96-
Mirror: true,
108+
Mirror: false,
97109
},
110+
{
111+
URL: "https://mymirror.com",
112+
Mirror: true,
113+
},
114+
},
115+
expected: []providerConfig{
116+
{
117+
URL: "https://myregistry.com",
118+
Username: "myuser",
119+
Password: "mypassword",
120+
Mirror: false,
121+
},
122+
},
123+
},
124+
{
125+
name: "a registry with missing credentials and a mirror with no credentials",
126+
configs: []providerConfig{
98127
{
99128
URL: "https://myregistry.com",
129+
Mirror: false,
130+
},
131+
{
132+
URL: "https://mymirror.com",
100133
Mirror: true,
101134
},
102135
},
103-
need: true,
136+
wantErr: ErrCredentialsNotFound,
104137
},
105138
{
106139
name: "registry with missing credentials",
107140
configs: []providerConfig{{
108141
URL: "https://myregistry.com",
109142
}},
110-
need: false,
111143
wantErr: ErrCredentialsNotFound,
112144
},
145+
{
146+
name: "registry with missing credentials but with a CA",
147+
configs: []providerConfig{{
148+
URL: "https://myregistry.com",
149+
HasCACert: true,
150+
}},
151+
},
152+
{
153+
name: "mirror with missing credentials but with a CA",
154+
configs: []providerConfig{{
155+
URL: "https://mymirror.com",
156+
HasCACert: true,
157+
Mirror: true,
158+
}},
159+
},
113160
}
114161

115162
for idx := range testCases {
@@ -118,9 +165,9 @@ func Test_needImageRegistryCredentialsConfiguration(t *testing.T) {
118165
t.Run(tt.name, func(t *testing.T) {
119166
t.Parallel()
120167

121-
need, err := needImageRegistryCredentialsConfiguration(tt.configs)
168+
expected, err := providerConfigsThatNeedConfiguration(tt.configs)
122169
require.ErrorIs(t, err, tt.wantErr)
123-
assert.Equal(t, tt.need, need)
170+
assert.Equal(t, tt.expected, expected)
124171
})
125172
}
126173
}

0 commit comments

Comments
 (0)