Skip to content

Commit 89c1be3

Browse files
authored
Merge pull request #434 from fluxcd/tls-secret
imagerepo: adopt Kubernetes style TLS secrets
2 parents 175e1d3 + 70360ee commit 89c1be3

File tree

7 files changed

+221
-85
lines changed

7 files changed

+221
-85
lines changed

api/v1beta2/imagerepository_types.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,21 @@ type ImageRepositorySpec struct {
6363
// +optional
6464
ServiceAccountName string `json:"serviceAccountName,omitempty"`
6565

66-
// CertSecretRef can be given the name of a secret containing
66+
// CertSecretRef can be given the name of a Secret containing
6767
// either or both of
6868
//
69-
// - a PEM-encoded client certificate (`certFile`) and private
70-
// key (`keyFile`);
71-
// - a PEM-encoded CA certificate (`caFile`)
69+
// - a PEM-encoded client certificate (`tls.crt`) and private
70+
// key (`tls.key`);
71+
// - a PEM-encoded CA certificate (`ca.crt`)
7272
//
73-
// and whichever are supplied, will be used for connecting to the
74-
// registry. The client cert and key are useful if you are
75-
// authenticating with a certificate; the CA cert is useful if
76-
// you are using a self-signed server certificate.
73+
// and whichever are supplied, will be used for connecting to the
74+
// registry. The client cert and key are useful if you are
75+
// authenticating with a certificate; the CA cert is useful if
76+
// you are using a self-signed server certificate. The Secret must
77+
// be of type `Opaque` or `kubernetes.io/tls`.
78+
//
79+
// Note: Support for the `caFile`, `certFile` and `keyFile` keys has
80+
// been deprecated.
7781
// +optional
7882
CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"`
7983

config/crd/bases/image.toolkit.fluxcd.io_imagerepositories.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,15 @@ spec:
287287
- namespaceSelectors
288288
type: object
289289
certSecretRef:
290-
description: "CertSecretRef can be given the name of a secret containing
291-
either or both of \n - a PEM-encoded client certificate (`certFile`)
292-
and private key (`keyFile`); - a PEM-encoded CA certificate (`caFile`)
290+
description: "CertSecretRef can be given the name of a Secret containing
291+
either or both of \n - a PEM-encoded client certificate (`tls.crt`)
292+
and private key (`tls.key`); - a PEM-encoded CA certificate (`ca.crt`)
293293
\n and whichever are supplied, will be used for connecting to the
294294
registry. The client cert and key are useful if you are authenticating
295295
with a certificate; the CA cert is useful if you are using a self-signed
296-
server certificate."
296+
server certificate. The Secret must be of type `Opaque` or `kubernetes.io/tls`.
297+
\n Note: Support for the `caFile`, `certFile` and `keyFile` keys
298+
has been deprecated."
297299
properties:
298300
name:
299301
description: Name of the referent.

docs/api/v1beta2/image-reflector.md

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -473,17 +473,20 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
473473
</td>
474474
<td>
475475
<em>(Optional)</em>
476-
<p>CertSecretRef can be given the name of a secret containing
476+
<p>CertSecretRef can be given the name of a Secret containing
477477
either or both of</p>
478478
<ul>
479-
<li>a PEM-encoded client certificate (<code>certFile</code>) and private
480-
key (<code>keyFile</code>);</li>
481-
<li>a PEM-encoded CA certificate (<code>caFile</code>)</li>
479+
<li>a PEM-encoded client certificate (<code>tls.crt</code>) and private
480+
key (<code>tls.key</code>);</li>
481+
<li>a PEM-encoded CA certificate (<code>ca.crt</code>)</li>
482482
</ul>
483483
<p>and whichever are supplied, will be used for connecting to the
484484
registry. The client cert and key are useful if you are
485485
authenticating with a certificate; the CA cert is useful if
486-
you are using a self-signed server certificate.</p>
486+
you are using a self-signed server certificate. The Secret must
487+
be of type <code>Opaque</code> or <code>kubernetes.io/tls</code>.</p>
488+
<p>Note: Support for the <code>caFile</code>, <code>certFile</code> and <code>keyFile</code> keys has
489+
been deprecated.</p>
487490
</td>
488491
</tr>
489492
<tr>
@@ -658,17 +661,20 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
658661
</td>
659662
<td>
660663
<em>(Optional)</em>
661-
<p>CertSecretRef can be given the name of a secret containing
664+
<p>CertSecretRef can be given the name of a Secret containing
662665
either or both of</p>
663666
<ul>
664-
<li>a PEM-encoded client certificate (<code>certFile</code>) and private
665-
key (<code>keyFile</code>);</li>
666-
<li>a PEM-encoded CA certificate (<code>caFile</code>)</li>
667+
<li>a PEM-encoded client certificate (<code>tls.crt</code>) and private
668+
key (<code>tls.key</code>);</li>
669+
<li>a PEM-encoded CA certificate (<code>ca.crt</code>)</li>
667670
</ul>
668671
<p>and whichever are supplied, will be used for connecting to the
669672
registry. The client cert and key are useful if you are
670673
authenticating with a certificate; the CA cert is useful if
671-
you are using a self-signed server certificate.</p>
674+
you are using a self-signed server certificate. The Secret must
675+
be of type <code>Opaque</code> or <code>kubernetes.io/tls</code>.</p>
676+
<p>Note: Support for the <code>caFile</code>, <code>certFile</code> and <code>keyFile</code> keys has
677+
been deprecated.</p>
672678
</td>
673679
</tr>
674680
<tr>

docs/spec/v1beta2/imagerepositories.md

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -175,41 +175,60 @@ secret to a ServiceAccount, see [Add image pull secret to service account](https
175175

176176
### Certificate secret reference
177177

178-
`.spec.certSecretRef` is an optional field to specify a name reference to a
179-
Secret in the same namespace as the ImageRepository containing TLS certificate
180-
data. This is for two separate purposes:
181-
- to provide a client certificate and private key, if you use a certificate to authenticate with the image registry; and,
182-
- to provide a CA certificate, if the registry uses a self-signed certificate
178+
`.spec.certSecretRef.name` is an optional field to specify a secret containing
179+
TLS certificate data. The secret can contain the following keys:
183180

184-
These will often go together in case of self-hosted image registry. All the
185-
files in the secret are expected to be [PEM-encoded][pem-encoding]. This is an
186-
ASCII format for certificates and keys; `openssl` and such tools typically
187-
provide an option for PEM output.
181+
* `tls.crt` and `tls.key`, to specify the client certificate and private key used
182+
for TLS client authentication. These must be used in conjunction, i.e.
183+
specifying one without the other will lead to an error.
184+
* `ca.crt`, to specify the CA certificate used to verify the server, which is
185+
required if the server is using a self-signed certificate.
188186

189-
Assuming that a certificate file and private key are in files `client.crt` and
190-
`client.key` respectively, a secret can be created with `kubectl`:
187+
If the server is using a self-signed certificate and has TLS client
188+
authentication enabled, all three values are required.
189+
190+
The Secret should be of type `Opaque` or `kubernetes.io/tls`. All the files in
191+
the Secret are expected to be [PEM-encoded][pem-encoding]. Assuming you have
192+
three files; `client.key`, `client.crt` and `ca.crt` for the client private key,
193+
client certificate and the CA certificate respectively, you can generate the
194+
required Secret using the `flux create secret tls` command:
191195

192196
```sh
193-
kubectl create secret generic tls-certs \
194-
--from-file=certFile=client.crt \
195-
--from-file=keyFile=client.key
197+
flux create secret tls --tls-key-file=client.key --tls-crt-file=client.crt --ca-crt-file=ca.crt
196198
```
197199

198-
An [encrypted secret](sops-guide) can also be used; the important bit is that
199-
the data keys in the secret are `certFile` and `keyFile`.
200-
201-
In case of a CA certificate for the client to use, the data key for it is
202-
`caFile`. Adapting the previous example, if the certificate is in the file
203-
`ca.crt`, and the client certificate and key are as before, the whole command
204-
would be:
200+
Example usage:
205201

206-
```sh
207-
kubectl create secret generic tls-certs \
208-
--from-file=certFile=client.crt \
209-
--from-file=keyFile=client.key \
210-
--from-file=caFile=ca.crt
202+
```yaml
203+
---
204+
apiVersion: image.toolkit.fluxcd.io/v1beta2
205+
kind: ImageRepository
206+
metadata:
207+
name: example
208+
namespace: default
209+
spec:
210+
interval: 5m0s
211+
url: example.com
212+
certSecretRef:
213+
name: example-tls
214+
---
215+
apiVersion: v1
216+
kind: Secret
217+
metadata:
218+
name: example-tls
219+
namespace: default
220+
type: kubernetes.io/tls # or Opaque
221+
data:
222+
tls.crt: <BASE64>
223+
tls.key: <BASE64>
224+
# NOTE: Can be supplied without the above values
225+
ca.crt: <BASE64>
211226
```
212227

228+
**Warning:** Support for the `caFile`, `certFile` and `keyFile` keys have been
229+
deprecated. If you have any Secrets using these keys and specified in an
230+
ImageRepository, the controller will log a deprecation warning.
231+
213232
### Suspend
214233

215234
`.spec.suspend` is an optional field to suspend the reconciliation of an

internal/controller/imagerepository_controller.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,20 @@ func (r *ImageRepositoryReconciler) setAuthOptions(ctx context.Context, obj *ima
384384
}
385385
}
386386

387-
tr, err := secret.TransportFromSecret(&certSecret)
387+
tr, err := secret.TransportFromKubeTLSSecret(&certSecret)
388388
if err != nil {
389389
return nil, err
390390
}
391+
if tr.TLSClientConfig == nil {
392+
tr, err = secret.TransportFromSecret(&certSecret)
393+
if err != nil {
394+
return nil, err
395+
}
396+
if tr.TLSClientConfig != nil {
397+
ctrl.LoggerFrom(ctx).
398+
Info("warning: specifying TLS auth data via `certFile`/`keyFile`/`caFile` is deprecated, please use `tls.crt`/`tls.key`/`ca.crt` instead")
399+
}
400+
}
391401
options = append(options, remote.WithTransport(tr))
392402
}
393403

internal/controller/imagerepository_controller_test.go

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ func TestImageRepositoryReconciler_setAuthOptions(t *testing.T) {
102102
testImg := "example.com/foo/bar"
103103
testSecretName := "test-secret"
104104
testTLSSecretName := "test-tls-secret"
105+
testDeprecatedTLSSecretName := "test-deprecated-tls-secret"
105106
testServiceAccountName := "test-service-account"
106107
testNamespace := "test-ns"
107108

@@ -132,18 +133,27 @@ func TestImageRepositoryReconciler_setAuthOptions(t *testing.T) {
132133
testTLSSecret.Namespace = testNamespace
133134
testTLSSecret.Type = corev1.SecretTypeTLS
134135
testTLSSecret.Data = map[string][]byte{
136+
secret.CACrtKey: rootCertPEM,
137+
corev1.TLSCertKey: clientCertPEM,
138+
corev1.TLSPrivateKeyKey: clientKeyPEM,
139+
}
140+
141+
testDeprecatedTLSSecret := &corev1.Secret{}
142+
testDeprecatedTLSSecret.Name = testDeprecatedTLSSecretName
143+
testDeprecatedTLSSecret.Namespace = testNamespace
144+
testDeprecatedTLSSecret.Type = corev1.SecretTypeTLS
145+
testDeprecatedTLSSecret.Data = map[string][]byte{
135146
secret.CACert: rootCertPEM,
136147
secret.ClientCert: clientCertPEM,
137148
secret.ClientKey: clientKeyPEM,
138149
}
139150

140-
// Secret with docker config and TLS secrets.
141-
testSecretWithTLS := testSecret.DeepCopy()
142-
testSecretWithTLS.Data = map[string][]byte{
143-
".dockerconfigjson": dockerconfigjson,
144-
secret.CACert: rootCertPEM,
145-
secret.ClientCert: clientCertPEM,
146-
secret.ClientKey: clientKeyPEM,
151+
// Docker config secret with TLS data.
152+
testDockerCfgSecretWithTLS := testSecret.DeepCopy()
153+
testDockerCfgSecretWithTLS.Data = map[string][]byte{
154+
secret.CACrtKey: rootCertPEM,
155+
corev1.TLSCertKey: clientCertPEM,
156+
corev1.TLSPrivateKeyKey: clientKeyPEM,
147157
}
148158

149159
// ServiceAccount without image pull secret.
@@ -211,6 +221,16 @@ func TestImageRepositoryReconciler_setAuthOptions(t *testing.T) {
211221
},
212222
},
213223
},
224+
{
225+
name: "cert secret ref with existing secret using deprecated keys",
226+
mockObjs: []client.Object{testDeprecatedTLSSecret},
227+
imageRepoSpec: imagev1.ImageRepositorySpec{
228+
Image: testImg,
229+
CertSecretRef: &meta.LocalObjectReference{
230+
Name: testDeprecatedTLSSecretName,
231+
},
232+
},
233+
},
214234
{
215235
name: "cert secret ref with non-existing secret",
216236
imageRepoSpec: imagev1.ImageRepositorySpec{
@@ -235,17 +255,15 @@ func TestImageRepositoryReconciler_setAuthOptions(t *testing.T) {
235255
},
236256
},
237257
{
238-
name: "same secret ref and cert secret ref",
239-
mockObjs: []client.Object{testSecretWithTLS},
258+
name: "cert secret ref of type docker config",
259+
mockObjs: []client.Object{testDockerCfgSecretWithTLS},
240260
imageRepoSpec: imagev1.ImageRepositorySpec{
241261
Image: testImg,
242-
SecretRef: &meta.LocalObjectReference{
243-
Name: testSecretName,
244-
},
245262
CertSecretRef: &meta.LocalObjectReference{
246263
Name: testSecretName,
247264
},
248265
},
266+
wantErr: true,
249267
},
250268
{
251269
name: "service account without pull secret",

0 commit comments

Comments
 (0)