Skip to content

Commit 2c58cff

Browse files
authored
Merge pull request #5 from carlpett/serve-over-tls
Add flags, serve over TLS by default
2 parents 605c6d4 + 2eaa1b0 commit 2c58cff

File tree

5 files changed

+61
-14
lines changed

5 files changed

+61
-14
lines changed

README.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,21 @@ It validates a JWT token passed in the `Authorization` header against a configur
77
The configuration format currently only supports a single elliptic curve public key for signature validation, and does not have a facility for rotating keys without restart. Basic support in the configuration format for supporting multiple active keys, and of different types, at once is in place but currently not used.
88

99
# Configuration
10-
The service takes a configuration file in YAML format. For example:
10+
A number of flags affect how the service is started:
11+
12+
Flag | Description | Default
13+
---------|-------------|--------------------
14+
--help | Show help | -
15+
--config | Path to configuration file | config.yaml
16+
--log-level| Log level | info
17+
--tls-key | Path to TLS key | `<required>`
18+
--tls-cert | Path to TLS cert | `<required>`
19+
--addr | Address/port to serve traffic in TLS mode | :8443
20+
--insecure | Serve traffic unencrypted over http | false
21+
--insecure-addr | Address/port to serve traffic in insecure mode | :8080
22+
23+
## Configuration file
24+
The service takes a configuration file in YAML format, by default `config.yaml`. For example:
1125

1226
```yaml
1327
validationKeys:
@@ -27,7 +41,7 @@ With this configuration, a JWT will be validated against the given public key, a
2741

2842
Claims can either be statically set, as in the above example, or passed via query string parameters. The `claimsSource` configuration parameter controls which mode the server operates in, and can be either `static` or `queryString`. Further examples of the two modes are given below.
2943

30-
## Static
44+
### Static
3145

3246
Multiple alternative allowed sets of claims can be configured, for example:
3347

@@ -68,7 +82,7 @@ claims:
6882

6983
Here, the token claims must **both** have the groups as before, **and** a `location` of `hq`.
7084

71-
## Query string
85+
### Query string
7286
In query string mode, the allowed claims are passed via query string parameters to the /validate endpoint. For example, with `/validate?claims_group=developers&claims_group=administrators&claims_location=hq`, the token claims must **both** have a `group` claim of **either** `developers` or `administrators`, **and** a `location` claim of `hq`.
7387

7488
Each claim must be prefixed with `claims_`. Giving the same claim multiple time results in any value being accepted.
@@ -81,13 +95,13 @@ If no claims are passed in this mode, the request will be denied.
8195
To use with the NGINX Ingress Controller, first create a deployment and a service for this endpoint. See the [kubernetes/](kubernetes/) directory for example manifests. Then on the ingress object you wish to authenticate, add this annotation for a server in static claims source mode:
8296

8397
```yaml
84-
nginx.ingress.kubernetes.io/auth-url: http://nginx-subrequest-auth-jwt.default.svc.cluster.local:8080/validate
98+
nginx.ingress.kubernetes.io/auth-url: https://nginx-subrequest-auth-jwt.default.svc.cluster.local:8443/validate
8599
```
86100

87101
Or, in query string mode:
88102

89103
```yaml
90-
nginx.ingress.kubernetes.io/auth-url: http://nginx-subrequest-auth-jwt.default.svc.cluster.local:8080/validate?claims_group=developers
104+
nginx.ingress.kubernetes.io/auth-url: https://nginx-subrequest-auth-jwt.default.svc.cluster.local:8443/validate?claims_group=developers
91105
```
92106

93107
Change the url to match the name of the service and namespace you chose when deploying. All requests will now have their JWTs validated before getting passed to the upstream service.

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ module github.com/carlpett/nginx-subrequest-auth-jwt
33
go 1.12
44

55
require (
6+
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
7+
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 // indirect
68
github.com/dgrijalva/jwt-go v3.2.0+incompatible
79
github.com/prometheus/client_golang v1.1.0
810
go.uber.org/atomic v1.4.0 // indirect
911
go.uber.org/multierr v1.1.0 // indirect
1012
go.uber.org/zap v1.10.0
13+
gopkg.in/alecthomas/kingpin.v2 v2.2.6
1114
gopkg.in/yaml.v2 v2.2.1
1215
)

go.sum

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
2+
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
3+
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
24
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
5+
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
6+
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
37
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
48
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
59
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -75,6 +79,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
7579
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0=
7680
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
7781
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
82+
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
7883
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
7984
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
8085
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

kubernetes/deployment.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ spec:
2424
containers:
2525
- name: nginx-subrequest-auth-jwt
2626
image: carlpett/nginx-subrequest-auth-jwt:latest
27+
args:
28+
- --insecure
2729
imagePullPolicy: IfNotPresent
2830
ports:
2931
- name: http

main.go

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"io/ioutil"
77
"net/http"
8-
"os"
98
"strings"
109
"time"
1110

@@ -15,6 +14,7 @@ import (
1514
"github.com/dgrijalva/jwt-go/request"
1615
"github.com/prometheus/client_golang/prometheus"
1716
"github.com/prometheus/client_golang/prometheus/promhttp"
17+
"gopkg.in/alecthomas/kingpin.v2"
1818
"gopkg.in/yaml.v2"
1919
)
2020

@@ -54,8 +54,8 @@ type server struct {
5454
StaticClaims []map[string][]string
5555
}
5656

57-
func newServer(logger logger.Logger) (*server, error) {
58-
cfg, err := ioutil.ReadFile("config.yaml")
57+
func newServer(logger logger.Logger, configFilePath string) (*server, error) {
58+
cfg, err := ioutil.ReadFile(configFilePath)
5959
if err != nil {
6060
return nil, err
6161
}
@@ -99,22 +99,45 @@ type config struct {
9999
StaticClaims []map[string][]string `yaml:"claims"`
100100
}
101101

102+
var (
103+
configFilePath = kingpin.Flag("config", "Path to configuration file").Default("config.yaml").ExistingFile()
104+
logLevel = kingpin.Flag("log-level", "Log level").Default("info").Enum("debug", "info", "warn", "error", "fatal")
105+
106+
tlsKey = kingpin.Flag("tls-key", "Path to TLS key").ExistingFile()
107+
tlsCert = kingpin.Flag("tls-cert", "Path to TLS cert").ExistingFile()
108+
bindAddr = kingpin.Flag("addr", "Address/port to serve traffic in TLS mode").Default(":8443").String()
109+
110+
insecure = kingpin.Flag("insecure", "Serve traffic unencrypted over http (default false)").Bool()
111+
insecureBindAddr = kingpin.Flag("insecure-addr", "Address/port to serve traffic in insecure mode").Default(":8080").String()
112+
)
113+
102114
func main() {
103-
logger := logger.NewLogger(os.Getenv("LOG_LEVEL"))
115+
kingpin.HelpFlag.Short('h')
116+
kingpin.Parse()
104117

105-
server, err := newServer(logger)
118+
logger := logger.NewLogger(*logLevel)
119+
120+
server, err := newServer(logger, *configFilePath)
106121
if err != nil {
107122
logger.Fatalw("Couldn't initialize server", "err", err)
108123
}
109124

110-
logger.Infow("Starting server on :8080")
111-
112125
http.Handle("/metrics", promhttp.Handler())
113126
http.HandleFunc("/validate", server.validate)
114127
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "OK") })
115-
err = http.ListenAndServe(":8080", nil)
128+
129+
if *insecure {
130+
logger.Infow("Starting server", "addr", *insecureBindAddr)
131+
err = http.ListenAndServe(*insecureBindAddr, nil)
132+
} else {
133+
logger.Infow("Starting server", "addr", *bindAddr)
134+
if *tlsKey == "" || *tlsCert == "" {
135+
logger.Fatalw("tls-key and tls-cert are required in TLS mode")
136+
}
137+
err = http.ListenAndServeTLS(*bindAddr, *tlsCert, *tlsKey, nil)
138+
}
116139
if err != nil {
117-
logger.Fatalw("Error serving http", "err", err)
140+
logger.Fatalw("Error running server", "err", err)
118141
}
119142
}
120143

0 commit comments

Comments
 (0)