Skip to content

Commit 808ed5b

Browse files
author
Josef Karasek
committed
add support for custom upstream CAs
1 parent 4109f99 commit 808ed5b

File tree

5 files changed

+132
-0
lines changed

5 files changed

+132
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Usage of _output/linux/amd64/kube-rbac-proxy:
5454
--tls-min-version string Minimum TLS version supported. Value must match version names from https://golang.org/pkg/crypto/tls/#pkg-constants. (default "VersionTLS12")
5555
--tls-private-key-file string File containing the default x509 private key matching --tls-cert-file.
5656
--upstream string The upstream URL to proxy to once requests have successfully been authenticated and authorized.
57+
--upstream-ca-file string The CA the upstream uses for TLS connection. This is required when the upstream uses TLS and its own CA certificate
5758
--upstream-force-h2c Force h2c to communiate with the upstream. This is required when the upstream speaks h2c(http/2 cleartext - insecure variant of http/2) only. For example, go-grpc server in the insecure mode, such as helm's tiller w/o TLS, speaks h2c only
5859
-v, --v Level log level for V logs
5960
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging

main.go

+8
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type config struct {
5353
secureListenAddress string
5454
upstream string
5555
upstreamForceH2C bool
56+
upstreamCAFile string
5657
auth proxy.Config
5758
tls tlsConfig
5859
kubeconfigLocation string
@@ -104,6 +105,7 @@ func main() {
104105
flagset.StringVar(&cfg.secureListenAddress, "secure-listen-address", "", "The address the kube-rbac-proxy HTTPs server should listen on.")
105106
flagset.StringVar(&cfg.upstream, "upstream", "", "The upstream URL to proxy to once requests have successfully been authenticated and authorized.")
106107
flagset.BoolVar(&cfg.upstreamForceH2C, "upstream-force-h2c", false, "Force h2c to communiate with the upstream. This is required when the upstream speaks h2c(http/2 cleartext - insecure variant of http/2) only. For example, go-grpc server in the insecure mode, such as helm's tiller w/o TLS, speaks h2c only")
108+
flagset.StringVar(&cfg.upstreamCAFile, "upstream-ca-file", "", "The CA the upstream uses for TLS connection. This is required when the upstream uses TLS and its own CA certificate")
107109
flagset.StringVar(&configFileName, "config-file", "", "Configuration file to configure kube-rbac-proxy.")
108110

109111
// TLS flags
@@ -193,7 +195,13 @@ func main() {
193195
glog.Fatalf("Failed to create rbac-proxy: %v", err)
194196
}
195197

198+
upstreamTransport, err := initTransport(cfg.upstreamCAFile)
199+
if err != nil {
200+
glog.Fatalf("Failed to set up upstream TLS connection: %v", err)
201+
}
202+
196203
proxy := httputil.NewSingleHostReverseProxy(upstreamURL)
204+
proxy.Transport = upstreamTransport
197205
mux := http.NewServeMux()
198206
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
199207
ok := auth.Handle(w, req)

test/ca.pem

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIC6jCCAdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu
3+
c2hpZnQtc2lnbmVyQDE1NDA0NzY0NTUwHhcNMTgxMDI1MTQwNzM1WhcNMjMxMDI0
4+
MTQwNzM2WjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1NDA0NzY0NTUw
5+
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQ1+8Z00Ovc93IpUjOsWs2
6+
ueNfcaDpDYW7P2y50jqy4XGdRRdHiLQKQv7S3Zqy/wTlnaDpk8TLMp6YSZ41p1Qy
7+
5HhIbXMviR9Bqg1JziSx9HaFvo5w79gn7YbICpftKpsi1L2KBk2ekgnTnt+pw+Ml
8+
L8N/ELtWtK8pu5cNZJIkJptxTWJzPyeUSVfDDPbEXP0VSDw2MOSoIxqcH1C4mR42
9+
Wr/6Crxtr2oyvAzLZvAtWCtUEY9fkmJVTGMjzfwRnrvxsfMguwSHKyyrRdDLoQMp
10+
sFn8cRBu0omTIbyMQlHo+QVgdQ+P6LnV9Dbjn5fX7+5ithyu4iTrJFqjDsd47vBN
11+
AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
12+
SIb3DQEBCwUAA4IBAQBIzSylEYbVIl/KzelTWz0FZznczPMJnBlJAa4OGUHt8VuY
13+
viUcItOdjrGhzwCzJn+IfbLtuv7d5YHYKEZZFNbUIPyvRByAM+iNKXXFSSnGBelz
14+
J3onnrM4kMD8TwNZA4AJGpWy7Ntmtw/ie2BZ1AgBR9AhpxLC1Md7zxly59QGmahT
15+
ym2aYUfblwQRm0AgRlccRgyVZdf3fCU5/BxLZkRT/hOKMQbAPPlxIGnpk/uJJcD4
16+
ZxKXypiQ2tzsKId8VybBYmgdG482bKrd6q/bsJGZx4B1++hHrvIPDaJYrmJG3UMP
17+
x8z5unyK1BzrXFcyID1Dw998m4dhspjJeYPVNd2a
18+
-----END CERTIFICATE-----

transport.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
Copyright 2017 Frederic Branczyk 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 main
18+
19+
import (
20+
"crypto/tls"
21+
"crypto/x509"
22+
"errors"
23+
"fmt"
24+
"io/ioutil"
25+
"net"
26+
"net/http"
27+
"time"
28+
)
29+
30+
func initTransport(upstreamCAFile string) (http.RoundTripper, error) {
31+
if upstreamCAFile == "" {
32+
return http.DefaultTransport, nil
33+
}
34+
35+
rootPEM, err := ioutil.ReadFile(upstreamCAFile)
36+
if err != nil {
37+
return nil, fmt.Errorf("error reading upstream CA file: %v", err)
38+
}
39+
40+
roots := x509.NewCertPool()
41+
if ok := roots.AppendCertsFromPEM([]byte(rootPEM)); !ok {
42+
return nil, errors.New("error parsing upstream CA certificate")
43+
}
44+
45+
// http.Transport sourced from go 1.10.7
46+
transport := &http.Transport{
47+
Proxy: http.ProxyFromEnvironment,
48+
DialContext: (&net.Dialer{
49+
Timeout: 30 * time.Second,
50+
KeepAlive: 30 * time.Second,
51+
DualStack: true,
52+
}).DialContext,
53+
MaxIdleConns: 100,
54+
IdleConnTimeout: 90 * time.Second,
55+
TLSHandshakeTimeout: 10 * time.Second,
56+
ExpectContinueTimeout: 1 * time.Second,
57+
TLSClientConfig: &tls.Config{RootCAs: roots},
58+
}
59+
60+
return transport, nil
61+
}

transport_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
Copyright 2017 Frederic Branczyk 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+
package main
17+
18+
import (
19+
"net/http"
20+
"testing"
21+
)
22+
23+
func TestInitTransportWithDefault(t *testing.T) {
24+
roundTripper, err := initTransport("")
25+
if err != nil {
26+
t.Errorf("want err to be nil, but got %v", err)
27+
return
28+
}
29+
if roundTripper == nil {
30+
t.Error("expected roundtripper, got nil")
31+
}
32+
}
33+
34+
func TestInitTransportWithCustomCA(t *testing.T) {
35+
roundTripper, err := initTransport("test/ca.pem")
36+
if err != nil {
37+
t.Errorf("want err to be nil, but got %v", err)
38+
return
39+
}
40+
transport := roundTripper.(*http.Transport)
41+
if transport.TLSClientConfig.RootCAs == nil {
42+
t.Error("expected root CA to be set, got nil")
43+
}
44+
}

0 commit comments

Comments
 (0)