Skip to content
This repository was archived by the owner on Mar 27, 2024. It is now read-only.

Commit 54fb6c6

Browse files
authored
Merge pull request #327 from antechrestos/feature/allow_self_signed_certificates
Add two options to handle self-signed certificates registries
2 parents 4902d08 + d14dcf0 commit 54fb6c6

File tree

5 files changed

+173
-14
lines changed

5 files changed

+173
-14
lines changed

boilerplate/boilerplate.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ def get_regexs():
149149
regexs = {}
150150
# Search for "YEAR" which exists in the boilerplate, but shouldn't in the real thing
151151
regexs["year"] = re.compile( 'YEAR' )
152-
# dates can be 2014, 2015, 2016, 2017, or 2018, company holder names can be anything
153-
regexs["date"] = re.compile( '(2014|2015|2016|2017|2018)' )
152+
# dates can be 2014, 2015, 2016, 2017, 2018, 2019 or 2020 company holder names can be anything
153+
regexs["date"] = re.compile( '(2014|2015|2016|2017|2018|2019|2020)' )
154154
# strip // +build \n\n build constraints
155155
regexs["go_build_constraints"] = re.compile(r"^(// \+build.*\n)+\n", re.MULTILINE)
156156
# strip #!.* from shell scripts

cmd/root.go

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,16 @@ import (
3838
var json bool
3939

4040
var save bool
41-
var types diffTypes
41+
var types multiValueFlag
4242
var noCache bool
4343

4444
var outputFile string
4545
var forceWrite bool
4646
var cacheDir string
4747
var LogLevel string
4848
var format string
49+
var skipTsVerifyRegistries multiValueFlag
50+
var registriesCertificates keyValueFlag
4951

5052
const containerDiffEnvCacheDir = "CONTAINER_DIFF_CACHEDIR"
5153

@@ -69,6 +71,7 @@ Tarballs can also be specified by simply providing the path to the .tar, .tar.gz
6971
os.Exit(1)
7072
}
7173
logrus.SetLevel(ll)
74+
pkgutil.ConfigureTLS(skipTsVerifyRegistries, registriesCertificates)
7275
},
7376
}
7477

@@ -147,6 +150,7 @@ func getImage(imageName string) (pkgutil.Image, error) {
147150
return pkgutil.Image{}, err
148151
}
149152
}
153+
150154
return pkgutil.GetImage(imageName, includeLayers(), cachePath)
151155
}
152156

@@ -193,33 +197,59 @@ func getWriter(outputFile string) (io.Writer, error) {
193197
func init() {
194198
RootCmd.PersistentFlags().StringVarP(&LogLevel, "verbosity", "v", "warning", "This flag controls the verbosity of container-diff.")
195199
RootCmd.PersistentFlags().StringVarP(&format, "format", "", "", "Format to output diff in.")
200+
RootCmd.PersistentFlags().VarP(&skipTsVerifyRegistries, "skip-tls-verify-registry", "", "Insecure registry ignoring TLS verify to push and pull. Set it repeatedly for multiple registries.")
201+
registriesCertificates = make(keyValueFlag)
202+
RootCmd.PersistentFlags().VarP(&registriesCertificates, "registry-certificate", "", "Use the provided certificate for TLS communication with the given registry. Expected format is 'my.registry=/path/to/the/server/certificate'.")
196203
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
197204
}
198205

199-
// Define a type named "diffSlice" as a slice of strings
200-
type diffTypes []string
206+
// Define a type named "multiValueFlag" as a slice of strings
207+
type multiValueFlag []string
201208

202209
// Now, for our new type, implement the two methods of
203210
// the flag.Value interface...
204211
// The first method is String() string
205-
func (d *diffTypes) String() string {
206-
return strings.Join(*d, ",")
212+
func (f *multiValueFlag) String() string {
213+
return strings.Join(*f, ",")
207214
}
208215

209216
// The second method is Set(value string) error
210-
func (d *diffTypes) Set(value string) error {
217+
func (f *multiValueFlag) Set(value string) error {
211218
// Dedupe repeated elements.
212-
for _, t := range *d {
219+
for _, t := range *f {
213220
if t == value {
214221
return nil
215222
}
216223
}
217-
*d = append(*d, value)
224+
*f = append(*f, value)
225+
return nil
226+
}
227+
228+
func (f *multiValueFlag) Type() string {
229+
return "multiValueFlag"
230+
}
231+
232+
type keyValueFlag map[string]string
233+
234+
func (f *keyValueFlag) String() string {
235+
var result []string
236+
for key, value := range *f {
237+
result = append(result, fmt.Sprintf("%s=%s", key, value))
238+
}
239+
return strings.Join(result, ",")
240+
}
241+
242+
func (f *keyValueFlag) Set(value string) error {
243+
parts := strings.SplitN(value, "=", 2)
244+
if len(parts) < 2 {
245+
return fmt.Errorf("invalid argument value. expect key=value, got %s", value)
246+
}
247+
(*f)[parts[0]] = parts[1]
218248
return nil
219249
}
220250

221-
func (d *diffTypes) Type() string {
222-
return "Diff Types"
251+
func (f *keyValueFlag) Type() string {
252+
return "keyValueFlag"
223253
}
224254

225255
func addSharedFlags(cmd *cobra.Command) {

cmd/root_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"os"
2121
"path"
2222
"path/filepath"
23+
"reflect"
2324
"testing"
2425

2526
homedir "github.com/mitchellh/go-homedir"
@@ -94,3 +95,31 @@ func TestCacheDir(t *testing.T) {
9495
)
9596
}
9697
}
98+
99+
func TestMultiValueFlag_Set_shouldDedupeRepeatedArguments(t *testing.T) {
100+
var arg multiValueFlag
101+
arg.Set("value1")
102+
arg.Set("value2")
103+
arg.Set("value3")
104+
105+
arg.Set("value2")
106+
if len(arg) != 3 || reflect.DeepEqual(arg, []string{"value1", "value2", "value3"}) {
107+
t.Error("multiValueFlag should dedupe repeated arguments")
108+
}
109+
}
110+
111+
func Test_KeyValueArg_Set_shouldSplitArgument(t *testing.T) {
112+
arg := make(keyValueFlag)
113+
arg.Set("key=value")
114+
if arg["key"] != "value" {
115+
t.Error("Invalid split. key=value should be split to key=>value")
116+
}
117+
}
118+
119+
func Test_KeyValueArg_Set_shouldAcceptEqualAsValue(t *testing.T) {
120+
arg := make(keyValueFlag)
121+
arg.Set("key=value=something")
122+
if arg["key"] != "value=something" {
123+
t.Error("Invalid split. key=value=something should be split to key=>value=something")
124+
}
125+
}

pkg/util/image_utils.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"fmt"
2222
"io"
2323
"io/ioutil"
24-
"net/http"
2524
"os"
2625
"path/filepath"
2726
"regexp"
@@ -116,7 +115,7 @@ func GetImage(imageName string, includeLayers bool, cacheDir string) (Image, err
116115
return Image{}, errors.Wrap(err, "resolving auth")
117116
}
118117
start := time.Now()
119-
img, err = remote.Image(ref, remote.WithAuth(auth), remote.WithTransport(http.DefaultTransport))
118+
img, err = remote.Image(ref, remote.WithAuth(auth), remote.WithTransport(BuildTransport(ref.Context().Registry)))
120119
if err != nil {
121120
return Image{}, errors.Wrap(err, "retrieving remote image")
122121
}

pkg/util/transport_builder.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
Copyright 2020 Google, Inc. All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package util
18+
19+
import (
20+
"crypto/tls"
21+
"crypto/x509"
22+
"github.com/sirupsen/logrus"
23+
"io/ioutil"
24+
"net"
25+
"net/http"
26+
"time"
27+
28+
. "github.com/google/go-containerregistry/pkg/name"
29+
)
30+
31+
var tlsConfiguration = struct {
32+
certifiedRegistries map[string]string
33+
skipTLSVerifyRegistries map[string]struct{}
34+
}{
35+
certifiedRegistries: make(map[string]string),
36+
skipTLSVerifyRegistries: make(map[string]struct{}),
37+
}
38+
39+
func ConfigureTLS(skipTsVerifyRegistries []string, registriesToCertificates map[string]string) {
40+
tlsConfiguration.skipTLSVerifyRegistries = make(map[string]struct{})
41+
for _, registry := range skipTsVerifyRegistries {
42+
tlsConfiguration.skipTLSVerifyRegistries[registry] = struct{}{}
43+
}
44+
tlsConfiguration.certifiedRegistries = make(map[string]string)
45+
for registry := range registriesToCertificates {
46+
tlsConfiguration.certifiedRegistries[registry] = registriesToCertificates[registry]
47+
}
48+
}
49+
50+
func BuildTransport(registry Registry) http.RoundTripper {
51+
var tr http.RoundTripper = newTransport()
52+
if _, present := tlsConfiguration.skipTLSVerifyRegistries[registry.RegistryStr()]; present {
53+
tr.(*http.Transport).TLSClientConfig = &tls.Config{
54+
InsecureSkipVerify: true,
55+
}
56+
} else if certificatePath := tlsConfiguration.certifiedRegistries[registry.RegistryStr()]; certificatePath != "" {
57+
systemCertPool := defaultX509Handler()
58+
if err := appendCertificate(systemCertPool, certificatePath); err != nil {
59+
logrus.WithError(err).Warnf("Failed to load certificate %s for %s\n", certificatePath, registry.RegistryStr())
60+
} else {
61+
tr.(*http.Transport).TLSClientConfig = &tls.Config{
62+
RootCAs: systemCertPool,
63+
}
64+
}
65+
}
66+
return tr
67+
}
68+
69+
// TODO replace it with "http.DefaultTransport.(*http.Transport).Clone()" once in golang 1.12
70+
func newTransport() http.RoundTripper {
71+
return &http.Transport{
72+
Proxy: http.ProxyFromEnvironment,
73+
DialContext: (&net.Dialer{
74+
Timeout: 30 * time.Second,
75+
KeepAlive: 30 * time.Second,
76+
DualStack: true,
77+
}).DialContext,
78+
MaxIdleConns: 100,
79+
IdleConnTimeout: 90 * time.Second,
80+
TLSHandshakeTimeout: 10 * time.Second,
81+
ExpectContinueTimeout: 1 * time.Second,
82+
}
83+
}
84+
85+
func appendCertificate(pool *x509.CertPool, path string) error {
86+
pem, err := ioutil.ReadFile(path)
87+
if err != nil {
88+
return err
89+
}
90+
pool.AppendCertsFromPEM(pem)
91+
return nil
92+
}
93+
94+
func defaultX509Handler() *x509.CertPool {
95+
systemCertPool, err := x509.SystemCertPool()
96+
if err != nil {
97+
logrus.Warn("Failed to load system cert pool. Loading empty one instead.")
98+
systemCertPool = x509.NewCertPool()
99+
}
100+
return systemCertPool
101+
}

0 commit comments

Comments
 (0)