git.iko.soy/typeable/oauth2-proxy
on master help sign in
Added ability to specify allowed TLS cipher suites.
ebacc2dChris Bednarz
CHANGELOG.md+1
@@ -18,6 +18,7 @@ N/A
18- [#1669](https://github.com/oauth2-proxy/oauth2-proxy/pull/1699) Fix method deprecated error in lint (@t-katsumura)
18- [#1669](https://github.com/oauth2-proxy/oauth2-proxy/pull/1699) Fix method deprecated error in lint (@t-katsumura)
19
19
20- [#1709](https://github.com/oauth2-proxy/oauth2-proxy/pull/1709) Show an alert message when basic auth credentials are invalid (@aiciobanu)
20- [#1709](https://github.com/oauth2-proxy/oauth2-proxy/pull/1709) Show an alert message when basic auth credentials are invalid (@aiciobanu)
21+- [#1723](https://github.com/oauth2-proxy/oauth2-proxy/pull/1723) Added ability to specify allowed TLS cipher suites. (@crbednarz)
21
22
22- [#1720](https://github.com/oauth2-proxy/oauth2-proxy/pull/1720) Extract roles from authToken, to allow using allowed roles with Keycloak.
23- [#1720](https://github.com/oauth2-proxy/oauth2-proxy/pull/1720) Extract roles from authToken, to allow using allowed roles with Keycloak.
23
24
docs/docs/configuration/alpha_config.md+1
@@ -478,6 +478,7 @@ as well as an optional minimal TLS version that is acceptable.
478| `Key` | _[SecretSource](#secretsource)_ | Key is the TLS key data to use.<br/>Typically this will come from a file. |
478| `Key` | _[SecretSource](#secretsource)_ | Key is the TLS key data to use.<br/>Typically this will come from a file. |
479| `Cert` | _[SecretSource](#secretsource)_ | Cert is the TLS certificate data to use.<br/>Typically this will come from a file. |
479| `Cert` | _[SecretSource](#secretsource)_ | Cert is the TLS certificate data to use.<br/>Typically this will come from a file. |
480| `MinVersion` | _string_ | MinVersion is the minimal TLS version that is acceptable.<br/>E.g. Set to "TLS1.3" to select TLS version 1.3 |
480| `MinVersion` | _string_ | MinVersion is the minimal TLS version that is acceptable.<br/>E.g. Set to "TLS1.3" to select TLS version 1.3 |
481+| `CipherSuites` | _[]string_ | CipherSuites is a list of TLS cipher suites that are allowed.<br/>E.g.:<br/>- TLS_RSA_WITH_RC4_128_SHA<br/>- TLS_RSA_WITH_AES_256_GCM_SHA384<br/>If not specified, the default Go safe cipher list is used.<br/>List of valid cipher suites can be found in the [crypto/tls documentation](https://pkg.go.dev/crypto/tls#pkg-constants). |
481
482
482### URLParameterRule
483### URLParameterRule
483
484
docs/docs/configuration/overview.md+1
@@ -196,6 +196,7 @@ An example [oauth2-proxy.cfg](https://github.com/oauth2-proxy/oauth2-proxy/blob/
196| `--standard-logging` | bool | Log standard runtime information | true |
196| `--standard-logging` | bool | Log standard runtime information | true |
197| `--standard-logging-format` | string | Template for standard log lines | see [Logging Configuration](#logging-configuration) |
197| `--standard-logging-format` | string | Template for standard log lines | see [Logging Configuration](#logging-configuration) |
198| `--tls-cert-file` | string | path to certificate file | |
198| `--tls-cert-file` | string | path to certificate file | |
199+| `--tls-cipher-suite` | string \| list | Restricts TLS cipher suites used by server to those listed (e.g. TLS_RSA_WITH_RC4_128_SHA) (may be given multiple times). If not specified, the default Go safe cipher list is used. List of valid cipher suites can be found in the [crypto/tls documentation](https://pkg.go.dev/crypto/tls#pkg-constants). | |
199| `--tls-key-file` | string | path to private key file | |
200| `--tls-key-file` | string | path to private key file | |
200| `--tls-min-version` | string | minimum TLS version that is acceptable, either `"TLS1.2"` or `"TLS1.3"` | `"TLS1.2"` |
201| `--tls-min-version` | string | minimum TLS version that is acceptable, either `"TLS1.2"` or `"TLS1.3"` | `"TLS1.2"` |
201| `--upstream` | string \| list | the http url(s) of the upstream endpoint, file:// paths for static files or `static://<status_code>` for static response. Routing is based on the path | |
202| `--upstream` | string \| list | the http url(s) of the upstream endpoint, file:// paths for static files or `static://<status_code>` for static response. Routing is based on the path | |
docs/docs/configuration/tls.md+3−2
@@ -32,8 +32,9 @@ There are two recommended configurations:
32 The defaults set `TLS1.2` as the minimal version.
32 The defaults set `TLS1.2` as the minimal version.
33 Regardless of the minimum version configured, `TLS1.3` is currently always used as the maximal version.
33 Regardless of the minimum version configured, `TLS1.3` is currently always used as the maximal version.
34
34
35+ TLS server side cipher suites can be specified with `--tls-cipher-suite=TLS_RSA_WITH_RC4_128_SHA`.
35− The server side cipher suites are the defaults from [`crypto/tls`](https://pkg.go.dev/crypto/tls#CipherSuites) of
36+ If not specified, the defaults from [`crypto/tls`](https://pkg.go.dev/crypto/tls#CipherSuites) of the currently used `go` version for building `oauth2-proxy` will be used.
36− the currently used `go` version for building `oauth2-proxy`.
37+ A complete list of valid TLS cipher suite names can be found in [`crypto/tls`](https://pkg.go.dev/crypto/tls#pkg-constants).
37
38
38### Terminate TLS at Reverse Proxy, e.g. Nginx
39### Terminate TLS at Reverse Proxy, e.g. Nginx
39
40
pkg/apis/options/legacy_options.go+14−9
@@ -447,15 +447,16 @@ func getXAuthRequestAccessTokenHeader() Header {
447}
447}
448
448
449type LegacyServer struct {
449type LegacyServer struct {
450− MetricsAddress string `flag:"metrics-address" cfg:"metrics_address"`
450+ MetricsAddress string `flag:"metrics-address" cfg:"metrics_address"`
451− MetricsSecureAddress string `flag:"metrics-secure-address" cfg:"metrics_secure_address"`
451+ MetricsSecureAddress string `flag:"metrics-secure-address" cfg:"metrics_secure_address"`
452− MetricsTLSCertFile string `flag:"metrics-tls-cert-file" cfg:"metrics_tls_cert_file"`
452+ MetricsTLSCertFile string `flag:"metrics-tls-cert-file" cfg:"metrics_tls_cert_file"`
453− MetricsTLSKeyFile string `flag:"metrics-tls-key-file" cfg:"metrics_tls_key_file"`
453+ MetricsTLSKeyFile string `flag:"metrics-tls-key-file" cfg:"metrics_tls_key_file"`
454− HTTPAddress string `flag:"http-address" cfg:"http_address"`
454+ HTTPAddress string `flag:"http-address" cfg:"http_address"`
455− HTTPSAddress string `flag:"https-address" cfg:"https_address"`
455+ HTTPSAddress string `flag:"https-address" cfg:"https_address"`
456− TLSCertFile string `flag:"tls-cert-file" cfg:"tls_cert_file"`
456+ TLSCertFile string `flag:"tls-cert-file" cfg:"tls_cert_file"`
457− TLSKeyFile string `flag:"tls-key-file" cfg:"tls_key_file"`
457+ TLSKeyFile string `flag:"tls-key-file" cfg:"tls_key_file"`
458− TLSMinVersion string `flag:"tls-min-version" cfg:"tls_min_version"`
458+ TLSMinVersion string `flag:"tls-min-version" cfg:"tls_min_version"`
459+ TLSCipherSuites []string `flag:"tls-cipher-suite" cfg:"tls_cipher_suites"`
459}
460}
460
461
461func legacyServerFlagset() *pflag.FlagSet {
462func legacyServerFlagset() *pflag.FlagSet {
@@ -470,6 +471,7 @@ func legacyServerFlagset() *pflag.FlagSet {
470 flagSet.String("tls-cert-file", "", "path to certificate file")
471 flagSet.String("tls-cert-file", "", "path to certificate file")
471 flagSet.String("tls-key-file", "", "path to private key file")
472 flagSet.String("tls-key-file", "", "path to private key file")
472 flagSet.String("tls-min-version", "", "minimal TLS version for HTTPS clients (either \"TLS1.2\" or \"TLS1.3\")")
473 flagSet.String("tls-min-version", "", "minimal TLS version for HTTPS clients (either \"TLS1.2\" or \"TLS1.3\")")
474+ flagSet.StringSlice("tls-cipher-suite", []string{}, "restricts TLS cipher suites to those listed (e.g. TLS_RSA_WITH_RC4_128_SHA) (may be given multiple times)")
473
475
474 return flagSet
476 return flagSet
475}
477}
@@ -600,6 +602,9 @@ func (l LegacyServer) convert() (Server, Server) {
600 },
602 },
601 MinVersion: l.TLSMinVersion,
603 MinVersion: l.TLSMinVersion,
602 }
604 }
605+ if len(l.TLSCipherSuites) != 0 {
606+ appServer.TLS.CipherSuites = l.TLSCipherSuites
607+ }
603 // Preserve backwards compatibility, only run one server
608 // Preserve backwards compatibility, only run one server
604 appServer.BindAddress = ""
609 appServer.BindAddress = ""
605 } else {
610 } else {
pkg/apis/options/legacy_options_test.go+23
@@ -804,6 +804,7 @@ var _ = Describe("Legacy Options", func() {
804 keyPath = "tls.key"
804 keyPath = "tls.key"
805 minVersion = "TLS1.3"
805 minVersion = "TLS1.3"
806 )
806 )
807+ cipherSuites := []string{"TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_GCM_SHA384"}
807
808
808 var tlsConfig = &TLS{
809 var tlsConfig = &TLS{
809 Cert: &SecretSource{
810 Cert: &SecretSource{
@@ -820,6 +821,15 @@ var _ = Describe("Legacy Options", func() {
820 MinVersion: minVersion,
821 MinVersion: minVersion,
821 }
822 }
822
823
824+ var tlsConfigCipherSuites = &TLS{
825+ Cert: tlsConfig.Cert,
826+ Key: tlsConfig.Key,
827+ CipherSuites: []string{
828+ "TLS_RSA_WITH_AES_128_GCM_SHA256",
829+ "TLS_RSA_WITH_AES_256_GCM_SHA384",
830+ },
831+ }
832+
823 DescribeTable("should convert to app and metrics servers",
833 DescribeTable("should convert to app and metrics servers",
824 func(in legacyServersTableInput) {
834 func(in legacyServersTableInput) {
825 appServer, metricsServer := in.legacyServer.convert()
835 appServer, metricsServer := in.legacyServer.convert()
@@ -860,6 +870,19 @@ var _ = Describe("Legacy Options", func() {
860 TLS: tlsConfigMinVersion,
870 TLS: tlsConfigMinVersion,
861 },
871 },
862 }),
872 }),
873+ Entry("with TLS options specified with CipherSuites", legacyServersTableInput{
874+ legacyServer: LegacyServer{
875+ HTTPAddress: insecureAddr,
876+ HTTPSAddress: secureAddr,
877+ TLSKeyFile: keyPath,
878+ TLSCertFile: crtPath,
879+ TLSCipherSuites: cipherSuites,
880+ },
881+ expectedAppServer: Server{
882+ SecureBindAddress: secureAddr,
883+ TLS: tlsConfigCipherSuites,
884+ },
885+ }),
863 Entry("with metrics HTTP and HTTPS addresses", legacyServersTableInput{
886 Entry("with metrics HTTP and HTTPS addresses", legacyServersTableInput{
864 legacyServer: LegacyServer{
887 legacyServer: LegacyServer{
865 HTTPAddress: insecureAddr,
888 HTTPAddress: insecureAddr,
pkg/apis/options/server.go+8
@@ -29,4 +29,12 @@ type TLS struct {
29 // MinVersion is the minimal TLS version that is acceptable.
29 // MinVersion is the minimal TLS version that is acceptable.
30 // E.g. Set to "TLS1.3" to select TLS version 1.3
30 // E.g. Set to "TLS1.3" to select TLS version 1.3
31 MinVersion string
31 MinVersion string
32+
33+ // CipherSuites is a list of TLS cipher suites that are allowed.
34+ // E.g.:
35+ // - TLS_RSA_WITH_RC4_128_SHA
36+ // - TLS_RSA_WITH_AES_256_GCM_SHA384
37+ // If not specified, the default Go safe cipher list is used.
38+ // List of valid cipher suites can be found in the [crypto/tls documentation](https://pkg.go.dev/crypto/tls#pkg-constants).
39+ CipherSuites []string
32}
40}
pkg/http/server.go+29
@@ -81,6 +81,27 @@ func (s *server) setupListener(opts Opts) error {
81 return nil
81 return nil
82}
82}
83
83
84+func parseCipherSuites(names []string) ([]uint16, error) {
85+ cipherNameMap := make(map[string]uint16)
86+
87+ for _, cipherSuite := range tls.CipherSuites() {
88+ cipherNameMap[cipherSuite.Name] = cipherSuite.ID
89+ }
90+ for _, cipherSuite := range tls.InsecureCipherSuites() {
91+ cipherNameMap[cipherSuite.Name] = cipherSuite.ID
92+ }
93+
94+ result := make([]uint16, len(names))
95+ for i, name := range names {
96+ id, present := cipherNameMap[name]
97+ if !present {
98+ return nil, fmt.Errorf("unknown TLS cipher suite name specified %q", name)
99+ }
100+ result[i] = id
101+ }
102+ return result, nil
103+}
104+
84// setupTLSListener sets the server TLS listener if the HTTPS server is enabled.
105// setupTLSListener sets the server TLS listener if the HTTPS server is enabled.
85// The HTTPS server can be disabled by setting the SecureBindAddress to "-" or by
106// The HTTPS server can be disabled by setting the SecureBindAddress to "-" or by
86// leaving it empty.
107// leaving it empty.
@@ -104,6 +125,14 @@ func (s *server) setupTLSListener(opts Opts) error {
104 }
125 }
105 config.Certificates = []tls.Certificate{cert}
126 config.Certificates = []tls.Certificate{cert}
106
127
128+ if len(opts.TLS.CipherSuites) > 0 {
129+ cipherSuites, err := parseCipherSuites(opts.TLS.CipherSuites)
130+ if err != nil {
131+ return fmt.Errorf("could not parse cipher suites: %v", err)
132+ }
133+ config.CipherSuites = cipherSuites
134+ }
135+
107 if len(opts.TLS.MinVersion) > 0 {
136 if len(opts.TLS.MinVersion) > 0 {
108 switch opts.TLS.MinVersion {
137 switch opts.TLS.MinVersion {
109 case "TLS1.2":
138 case "TLS1.2":
pkg/http/server_test.go+68
@@ -261,6 +261,40 @@ var _ = Describe("Server", func() {
261 expectHTTPListener: false,
261 expectHTTPListener: false,
262 expectTLSListener: true,
262 expectTLSListener: true,
263 }),
263 }),
264+ Entry("with an ipv4 valid https bind address, and valid TLS config with CipherSuites", &newServerTableInput{
265+ opts: Opts{
266+ Handler: handler,
267+ SecureBindAddress: "127.0.0.1:0",
268+ TLS: &options.TLS{
269+ Key: &ipv4KeyDataSource,
270+ Cert: &ipv4CertDataSource,
271+ CipherSuites: []string{
272+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
273+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
274+ },
275+ },
276+ },
277+ expectedErr: nil,
278+ expectHTTPListener: false,
279+ expectTLSListener: true,
280+ }),
281+ Entry("with an ipv4 valid https bind address, and invalid TLS config with unknown CipherSuites", &newServerTableInput{
282+ opts: Opts{
283+ Handler: handler,
284+ SecureBindAddress: "127.0.0.1:0",
285+ TLS: &options.TLS{
286+ Key: &ipv4KeyDataSource,
287+ Cert: &ipv4CertDataSource,
288+ CipherSuites: []string{
289+ "TLS_RSA_WITH_RC4_64_SHA",
290+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
291+ },
292+ },
293+ },
294+ expectedErr: errors.New("error setting up TLS listener: could not parse cipher suites: unknown TLS cipher suite name specified \"TLS_RSA_WITH_RC4_64_SHA\""),
295+ expectHTTPListener: false,
296+ expectTLSListener: true,
297+ }),
264 Entry("with an ipv6 valid http bind address", &newServerTableInput{
298 Entry("with an ipv6 valid http bind address", &newServerTableInput{
265 opts: Opts{
299 opts: Opts{
266 Handler: handler,
300 Handler: handler,
@@ -454,6 +488,40 @@ var _ = Describe("Server", func() {
454 expectHTTPListener: false,
488 expectHTTPListener: false,
455 expectTLSListener: true,
489 expectTLSListener: true,
456 }),
490 }),
491+ Entry("with an ipv6 valid https bind address, and valid TLS config with CipherSuites", &newServerTableInput{
492+ opts: Opts{
493+ Handler: handler,
494+ SecureBindAddress: "[::1]:0",
495+ TLS: &options.TLS{
496+ Key: &ipv4KeyDataSource,
497+ Cert: &ipv4CertDataSource,
498+ CipherSuites: []string{
499+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
500+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
501+ },
502+ },
503+ },
504+ expectedErr: nil,
505+ expectHTTPListener: false,
506+ expectTLSListener: true,
507+ }),
508+ Entry("with an ipv6 valid https bind address, and invalid TLS config with unknown CipherSuites", &newServerTableInput{
509+ opts: Opts{
510+ Handler: handler,
511+ SecureBindAddress: "[::1]:0",
512+ TLS: &options.TLS{
513+ Key: &ipv4KeyDataSource,
514+ Cert: &ipv4CertDataSource,
515+ CipherSuites: []string{
516+ "TLS_RSA_WITH_RC4_64_SHA",
517+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
518+ },
519+ },
520+ },
521+ expectedErr: errors.New("error setting up TLS listener: could not parse cipher suites: unknown TLS cipher suite name specified \"TLS_RSA_WITH_RC4_64_SHA\""),
522+ expectHTTPListener: false,
523+ expectTLSListener: true,
524+ }),
457 )
525 )
458 })
526 })
459
527