Skip to content

Commit ec98511

Browse files
author
Michal Minář
committed
Prefer secure connection during image pruning
The default stays the same. When a CA bundle or a registry url is specified, require secure connection with certificate verification. Allow the user to force insecure connection using --force-insecure if he has to. Signed-off-by: Michal Minář <[email protected]>
1 parent aa4f611 commit ec98511

File tree

1 file changed

+38
-12
lines changed

1 file changed

+38
-12
lines changed

pkg/cmd/admin/prune/images.go

+38-12
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ var (
4646
--confirm flag is needed for changes to be effective.
4747
4848
Only a user with a cluster role %s or higher who is logged-in will be able to actually
49-
delete the images.`)
49+
delete the images.
50+
51+
If the registry is secured with a certificate signed by a self-signed root certificate
52+
authority other than the one used for the cluster and present in current user's config, you
53+
may need to specify it using --certificate-authority flag.`)
5054

5155
imagesExample = templates.Examples(`
5256
# See, what the prune command would delete if only images more than an hour old and obsoleted
@@ -80,6 +84,7 @@ type PruneImagesOptions struct {
8084
CABundle string
8185
RegistryUrlOverride string
8286
Namespace string
87+
ForceInsecure bool
8388

8489
OSClient client.Interface
8590
KClient kclientset.Interface
@@ -117,8 +122,9 @@ func NewCmdPruneImages(f *clientcmd.Factory, parentName, name string, out io.Wri
117122
cmd.Flags().DurationVar(opts.KeepYoungerThan, "keep-younger-than", *opts.KeepYoungerThan, "Specify the minimum age of an image for it to be considered a candidate for pruning.")
118123
cmd.Flags().IntVar(opts.KeepTagRevisions, "keep-tag-revisions", *opts.KeepTagRevisions, "Specify the number of image revisions for a tag in an image stream that will be preserved.")
119124
cmd.Flags().BoolVar(opts.PruneOverSizeLimit, "prune-over-size-limit", *opts.PruneOverSizeLimit, "Specify if images which are exceeding LimitRanges (see 'openshift.io/Image'), specified in the same namespace, should be considered for pruning. This flag cannot be combined with --keep-younger-than nor --keep-tag-revisions.")
120-
cmd.Flags().StringVar(&opts.CABundle, "certificate-authority", opts.CABundle, "The path to a certificate authority bundle to use when communicating with the managed Docker registries. Defaults to the certificate authority data from the current user's config file.")
125+
cmd.Flags().StringVar(&opts.CABundle, "certificate-authority", opts.CABundle, "The path to a certificate authority bundle to use when communicating with the managed Docker registries. Defaults to the certificate authority data from the current user's config file. It cannot be used together with --force-insecure.")
121126
cmd.Flags().StringVar(&opts.RegistryUrlOverride, "registry-url", opts.RegistryUrlOverride, "The address to use when contacting the registry, instead of using the default value. This is useful if you can't resolve or reach the registry (e.g.; the default is a cluster-internal URL) but you do have an alternative route that works.")
127+
cmd.Flags().BoolVar(&opts.ForceInsecure, "force-insecure", opts.ForceInsecure, "If true, allow an insecure connection to the docker registry that is hosted via HTTP or has an invalid HTTPS certificate. By default, insecure connection is allowed only in case where neither certificate-authority nor registry-url is specified. Whenever possible, use --certificate-authority instead of this dangerous option.")
122128

123129
return cmd
124130
}
@@ -151,7 +157,8 @@ func (o *PruneImagesOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command,
151157
}
152158
o.Out = out
153159

154-
osClient, kClient, registryClient, err := getClients(f, o.CABundle)
160+
insecure := (len(o.RegistryUrlOverride) == 0 && len(o.CABundle) == 0) || o.ForceInsecure
161+
osClient, kClient, registryClient, err := getClients(f, o.CABundle, insecure)
155162
if err != nil {
156163
return err
157164
}
@@ -176,6 +183,9 @@ func (o PruneImagesOptions) Validate() error {
176183
if _, err := url.Parse(o.RegistryUrlOverride); err != nil {
177184
return fmt.Errorf("invalid --registry-url flag: %v", err)
178185
}
186+
if o.ForceInsecure && len(o.CABundle) > 0 {
187+
return fmt.Errorf("--certificate-authority cannot be specified with --force-insecure")
188+
}
179189
return nil
180190
}
181191

@@ -436,7 +446,7 @@ func (p *describingManifestDeleter) DeleteManifest(registryClient *http.Client,
436446
}
437447

438448
// getClients returns a Kube client, OpenShift client, and registry client.
439-
func getClients(f *clientcmd.Factory, caBundle string) (*client.Client, kclientset.Interface, *http.Client, error) {
449+
func getClients(f *clientcmd.Factory, registryCABundle string, registryInsecure bool) (*client.Client, kclientset.Interface, *http.Client, error) {
440450
clientConfig, err := f.ClientConfig()
441451
if err != nil {
442452
return nil, nil, nil, err
@@ -463,6 +473,7 @@ func getClients(f *clientcmd.Factory, caBundle string) (*client.Client, kclients
463473

464474
// copy the config
465475
registryClientConfig := *clientConfig
476+
registryClientConfig.TLSClientConfig.Insecure = registryInsecure
466477

467478
// zero out everything we don't want to use
468479
registryClientConfig.BearerToken = ""
@@ -471,8 +482,25 @@ func getClients(f *clientcmd.Factory, caBundle string) (*client.Client, kclients
471482
registryClientConfig.KeyFile = ""
472483
registryClientConfig.KeyData = []byte{}
473484

474-
// we have to set a username to something for the Docker login
475-
// but it's not actually used
485+
registryCABundleIncluded := false
486+
if registryInsecure {
487+
// it's not allowed to specify insecure flag together with CAs
488+
registryClientConfig.CAFile = ""
489+
registryClientConfig.CAData = []byte{}
490+
491+
} else if len(registryCABundle) > 0 && len(registryClientConfig.CAData) == 0 {
492+
// If given, we want to append registryCABundle to the resulting tlsConfig.RootCAs. However, if we
493+
// leave CAData unset, tlsConfig may not be created. We could append the caBundle to the CAData here
494+
// directly if we were ok doing a binary magic, which is not the case.
495+
cadata, err := ioutil.ReadFile(registryCABundle)
496+
if err != nil {
497+
return nil, nil, nil, fmt.Errorf("failed to read registry ca bundle: %v", err)
498+
}
499+
registryClientConfig.CAData = cadata
500+
registryCABundleIncluded = true
501+
}
502+
503+
// we have to set a username to something for the Docker login but it's not actually used
476504
registryClientConfig.Username = "unused"
477505

478506
// set the "password" to be the token
@@ -483,18 +511,16 @@ func getClients(f *clientcmd.Factory, caBundle string) (*client.Client, kclients
483511
return nil, nil, nil, err
484512
}
485513

486-
// if the user specified a CA on the command line, add it to the
487-
// client config's CA roots
488-
if tlsConfig != nil && len(caBundle) > 0 {
489-
data, err := ioutil.ReadFile(caBundle)
514+
// Add the CA bundle to the client config's CA roots if provided and we haven't done that already.
515+
// FIXME: handle registryCABundle on one place
516+
if tlsConfig != nil && len(registryCABundle) > 0 && !registryCABundleIncluded && !registryInsecure {
517+
data, err := ioutil.ReadFile(registryCABundle)
490518
if err != nil {
491519
return nil, nil, nil, err
492520
}
493-
494521
if tlsConfig.RootCAs == nil {
495522
tlsConfig.RootCAs = x509.NewCertPool()
496523
}
497-
498524
tlsConfig.RootCAs.AppendCertsFromPEM(data)
499525
}
500526

0 commit comments

Comments
 (0)