├── .dockerignore ├── examples ├── httpserver │ ├── reverseProxy.key │ ├── Procfile │ ├── mykey.pub │ ├── signer.yaml │ ├── verifier.yaml │ ├── mykey.crt │ ├── mykey.key │ └── README.md └── kubernetes-httpserver │ ├── nginx.conf │ ├── mykey.pub │ ├── tester-app.yaml │ ├── signer.yaml │ ├── verifier.yaml │ ├── nginx-app.yaml │ ├── mykey.key │ └── README.md ├── NOTICE ├── .gitignore ├── Dockerfile ├── go.mod ├── jwt ├── keyserver │ ├── keyregistry │ │ ├── keycache │ │ │ ├── memory │ │ │ │ └── memory.go │ │ │ └── keycache.go │ │ ├── README.md │ │ └── keyregistry.go │ ├── result.go │ ├── keyserver.go │ └── preshared │ │ └── preshared.go ├── noncestorage │ ├── noncestorage.go │ └── local │ │ └── local.go ├── claims │ ├── verifier.go │ └── static │ │ └── static.go ├── privatekey │ ├── privatekey.go │ ├── preshared │ │ └── preshared.go │ └── autogenerated │ │ └── autogenerated.go ├── jwt.go ├── jwt_test.go └── proxy_handlers.go ├── DCO ├── glide.yaml ├── bill-of-materials.json ├── glide.lock ├── stop └── stopper.go ├── CONTRIBUTING.md ├── config.example.yaml ├── cmd └── jwtproxy │ └── main.go ├── code-of-conduct.md ├── jwtproxy.go ├── go.sum ├── config └── config.go ├── proxy └── proxy.go ├── README.md └── LICENSE /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | -------------------------------------------------------------------------------- /examples/httpserver/reverseProxy.key: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | CoreOS Project 2 | Copyright 2016 CoreOS, Inc 3 | 4 | This product includes software developed at CoreOS, Inc. 5 | (http://www.coreos.com/). 6 | -------------------------------------------------------------------------------- /examples/kubernetes-httpserver/nginx.conf: -------------------------------------------------------------------------------- 1 | server{ 2 | listen 8080; 3 | 4 | location / { 5 | return 200 "Welcome to this authenticated web service.\n"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/httpserver/Procfile: -------------------------------------------------------------------------------- 1 | web: go get github.com/rif/spark && $GOPATH/bin/spark -port 8081 "Welcome to this authenticated web service." 2 | signer: go get github.com/quay/jwtproxy/cmd/jwtproxy && $GOPATH/bin/jwtproxy -config $(pwd)/signer.yaml 3 | verifier: go get github.com/quay/jwtproxy/cmd/jwtproxy && $GOPATH/bin/jwtproxy -config $(pwd)/verifier.yaml 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | cmd/jwtproxy/jwtproxy 27 | jwtproxy 28 | -------------------------------------------------------------------------------- /examples/httpserver/mykey.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA36q857+m4TVXr5qAsdtA 3 | vpuSMtZKKt9Ronl1eQxrDlZ4Cc4fyRAuWT5awg7zuEjTVv3HTITmGoEDmginZAlY 4 | Pa8X9ATse0GvAqIdHGyRjKB725yWtcKKKzud6xPNTuBJ+IV1vzZrbABx9ubrY3ye 5 | txGqton8sGf8p14TBZKmylGcWrKur8zqFoSYdg2fovCNUCaICAs9rAtJWmCvVKiG 6 | jwemabhlKjBb3UflTOVkMGgHIQ+yRS3Eb6Ggh9by0yriCZPHuadRK/PBev5IC3ht 7 | dBRfc8R1+um8wtIc4XuJDBjZon8wQjSleqeJt4cAVRuHnmA3OktrTj92X/8UEpo+ 8 | rwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /examples/kubernetes-httpserver/mykey.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA36q857+m4TVXr5qAsdtA 3 | vpuSMtZKKt9Ronl1eQxrDlZ4Cc4fyRAuWT5awg7zuEjTVv3HTITmGoEDmginZAlY 4 | Pa8X9ATse0GvAqIdHGyRjKB725yWtcKKKzud6xPNTuBJ+IV1vzZrbABx9ubrY3ye 5 | txGqton8sGf8p14TBZKmylGcWrKur8zqFoSYdg2fovCNUCaICAs9rAtJWmCvVKiG 6 | jwemabhlKjBb3UflTOVkMGgHIQ+yRS3Eb6Ggh9by0yriCZPHuadRK/PBev5IC3ht 7 | dBRfc8R1+um8wtIc4XuJDBjZon8wQjSleqeJt4cAVRuHnmA3OktrTj92X/8UEpo+ 8 | rwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /examples/httpserver/signer.yaml: -------------------------------------------------------------------------------- 1 | jwtproxy: 2 | signer_proxy: 3 | listen_addr: :3128 4 | 5 | signer: 6 | issuer: jwtproxy 7 | expiration_time: 5m 8 | max_skew: 1m 9 | nonce_length: 32 10 | private_key: 11 | type: preshared 12 | options: 13 | key_id: mykey 14 | private_key_path: mykey.key 15 | 16 | # To sign requests to HTTPS endpoints, we need to 17 | # specify a CA certificate (trusted by the clients) 18 | # and its private key that the MITM mechanism will use. 19 | #ca_key_file: ca.key 20 | #ca_crt_file: ca.crt 21 | 22 | verifier_proxies: 23 | - enabled: false 24 | -------------------------------------------------------------------------------- /examples/kubernetes-httpserver/tester-app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: tester 5 | spec: 6 | volumes: 7 | - name: secret-tester-volume 8 | secret: 9 | secretName: secret-tester-config 10 | containers: 11 | - name: jwtproxy 12 | image: quay.io/quay/jwtproxy 13 | args: 14 | - -config 15 | - /etc/jwtproxy/signer.yaml 16 | volumeMounts: 17 | - mountPath: /etc/jwtproxy/ 18 | name: secret-tester-volume 19 | - name: tester 20 | image: alpine:edge 21 | command: 22 | - sh 23 | - -c 24 | - while :; do http_proxy=http://localhost:3128 wget -qO- -Y on http://nginx/; sleep 5; done 25 | -------------------------------------------------------------------------------- /examples/kubernetes-httpserver/signer.yaml: -------------------------------------------------------------------------------- 1 | jwtproxy: 2 | signer_proxy: 3 | listen_addr: :3128 4 | shutdown_timeout: 3s 5 | 6 | signer: 7 | issuer: jwtproxy 8 | expiration_time: 5m 9 | max_skew: 1m 10 | nonce_length: 32 11 | private_key: 12 | type: preshared 13 | options: 14 | key_id: mykey 15 | private_key_path: /etc/jwtproxy/mykey.key 16 | 17 | # To sign requests to HTTPS endpoints, we need to 18 | # specify a CA certificate (trusted by the clients) 19 | # and its private key that the MITM mechanism will use. 20 | #ca_key_file: ca.key 21 | #ca_crt_file: ca.crt 22 | 23 | verifier_proxies: 24 | - enabled: false 25 | -------------------------------------------------------------------------------- /examples/httpserver/verifier.yaml: -------------------------------------------------------------------------------- 1 | jwtproxy: 2 | verifier_proxies: 3 | - listen_addr: :8080 4 | 5 | verifier: 6 | upstream: http://localhost:8081/ 7 | audience: http://localhost:8080/ # host used to talk to the verifier proxy 8 | max_skew: 1m 9 | max_ttl: 5m 10 | key_server: 11 | type: preshared 12 | options: 13 | issuer: jwtproxy 14 | key_id: mykey 15 | public_key_path: mykey.pub 16 | claims_verifiers: 17 | - type: static 18 | options: 19 | iss: jwtproxy 20 | 21 | # Key pair used to terminate TLS. 22 | #key_file: localhost.key 23 | #crt_file: localhost.crt 24 | 25 | signer_proxy: 26 | enabled: false 27 | -------------------------------------------------------------------------------- /examples/kubernetes-httpserver/verifier.yaml: -------------------------------------------------------------------------------- 1 | jwtproxy: 2 | verifier_proxies: 3 | - listen_addr: :80 4 | 5 | verifier: 6 | upstream: http://localhost:8080/ 7 | audience: http://nginx/ # host used to talk to the verifier proxy 8 | max_skew: 1m 9 | max_ttl: 5m 10 | key_server: 11 | type: preshared 12 | options: 13 | issuer: jwtproxy 14 | key_id: mykey 15 | public_key_path: /etc/jwtproxy/mykey.pub 16 | claims_verifiers: 17 | - type: static 18 | options: 19 | iss: jwtproxy 20 | 21 | # Key pair used to terminate TLS. 22 | #key_file: localhost.key 23 | #crt_file: localhost.crt 24 | 25 | signer_proxy: 26 | enabled: false 27 | -------------------------------------------------------------------------------- /examples/kubernetes-httpserver/nginx-app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: nginx 5 | spec: 6 | type: NodePort 7 | ports: 8 | - port: 80 9 | protocol: TCP 10 | name: http 11 | selector: 12 | app: nginx 13 | --- 14 | apiVersion: v1 15 | kind: Pod 16 | metadata: 17 | name: nginx 18 | labels: 19 | app: nginx 20 | spec: 21 | volumes: 22 | - name: secret-nginx-volume 23 | secret: 24 | secretName: secret-nginx-config 25 | - name: secret-verifier-volume 26 | secret: 27 | secretName: secret-verifier-config 28 | containers: 29 | - name: nginx 30 | image: nginx 31 | volumeMounts: 32 | - mountPath: /etc/nginx/conf.d/ 33 | name: secret-nginx-volume 34 | - name: jwtproxy 35 | image: quay.io/quay/jwtproxy 36 | ports: 37 | - containerPort: 80 38 | args: 39 | - -config 40 | - /etc/jwtproxy/verifier.yaml 41 | volumeMounts: 42 | - mountPath: /etc/jwtproxy/ 43 | name: secret-verifier-volume 44 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2015 CoreOS, Inc 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http:#www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM golang:1.12-alpine 16 | 17 | MAINTAINER Quentin Machu 18 | 19 | ENV XDG_CONFIG_HOME=/config/ 20 | VOLUME /config 21 | 22 | ENTRYPOINT ["jwtproxy"] 23 | CMD ["-config", "/config/config.yaml"] 24 | 25 | ADD . /go/src/github.com/quay/jwtproxy/ 26 | WORKDIR /go/src/github.com/quay/jwtproxy/ 27 | 28 | RUN go install -v github.com/quay/jwtproxy/cmd/jwtproxy 29 | RUN rm -r /usr/local/go 30 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/quay/jwtproxy/v2 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/coreos/go-oidc v0.0.0-20160330172125-f427f54ef96b 7 | github.com/coreos/go-systemd v0.0.0-20160202211425-7b2428fec400 // indirect 8 | github.com/coreos/goproxy v0.0.0-20170222233530-25fe2597a3d1 9 | github.com/coreos/pkg v0.0.0-20160314094717-1914e367e85e // indirect 10 | github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2 // indirect 11 | github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4 // indirect 12 | github.com/elazarl/goproxy/ext v0.0.0-20210801061803-8e322dfb79c4 // indirect 13 | github.com/gregjones/httpcache v0.0.0-20160313132734-4b02602f71f4 14 | github.com/jonboulle/clockwork v0.0.0-20151121001658-ed104f61ea48 // indirect 15 | github.com/kylelemons/godebug v1.1.0 // indirect 16 | github.com/patrickmn/go-cache v2.1.0+incompatible 17 | github.com/pmezard/go-difflib v1.0.0 // indirect 18 | github.com/quay/jwtproxy v0.0.4 19 | github.com/sirupsen/logrus v0.11.5 20 | github.com/stretchr/testify v1.1.4-0.20160418225827-c5d7a69bf8a2 21 | github.com/tylerb/graceful v1.2.15 22 | golang.org/x/net v0.0.0-20160403195514-024ed629fd29 // indirect 23 | golang.org/x/sys v0.0.0-20160402023915-a60af9cbbc6a // indirect 24 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 25 | gopkg.in/square/go-jose.v2 v2.0.0-20160419061419-77e6c51d4de6 26 | gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129 27 | ) 28 | -------------------------------------------------------------------------------- /jwt/keyserver/keyregistry/keycache/memory/memory.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 CoreOS, Inc 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package memory 16 | 17 | import ( 18 | "github.com/gregjones/httpcache" 19 | log "github.com/sirupsen/logrus" 20 | 21 | "github.com/quay/jwtproxy/config" 22 | "github.com/quay/jwtproxy/jwt/keyserver/keyregistry/keycache" 23 | "github.com/quay/jwtproxy/stop" 24 | ) 25 | 26 | func init() { 27 | keycache.RegisterCache("memory", constructor) 28 | } 29 | 30 | type cache struct { 31 | *httpcache.MemoryCache 32 | } 33 | 34 | func constructor(registrableComponentConfig config.RegistrableComponentConfig) (keycache.Cache, error) { 35 | log.Debug("Initializing in-memory key cache.") 36 | 37 | return &cache{ 38 | MemoryCache: httpcache.NewMemoryCache(), 39 | }, nil 40 | } 41 | 42 | func (c *cache) Stop() <-chan struct{} { 43 | return stop.AlreadyDone 44 | } 45 | -------------------------------------------------------------------------------- /jwt/keyserver/result.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 CoreOS, Inc 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package keyserver 16 | 17 | type PublishResult struct { 18 | errorOrNil chan error 19 | cancelPub chan struct{} 20 | } 21 | 22 | func NewPublishResult() *PublishResult { 23 | return &PublishResult{ 24 | errorOrNil: make(chan error, 1), 25 | cancelPub: make(chan struct{}), 26 | } 27 | } 28 | 29 | func (pr *PublishResult) Success() { 30 | pr.errorOrNil <- nil 31 | close(pr.errorOrNil) 32 | } 33 | 34 | func (pr *PublishResult) Cancel() { 35 | close(pr.cancelPub) 36 | } 37 | 38 | func (pr *PublishResult) SetError(err error) { 39 | pr.errorOrNil <- err 40 | close(pr.errorOrNil) 41 | } 42 | 43 | func (pr *PublishResult) Result() <-chan error { 44 | return pr.errorOrNil 45 | } 46 | 47 | func (pr *PublishResult) WaitForCancel() <-chan struct{} { 48 | return pr.cancelPub 49 | } 50 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 660 York Street, Suite 102, 6 | San Francisco, CA 94110 USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies of this 9 | license document, but changing it is not allowed. 10 | 11 | 12 | Developer's Certificate of Origin 1.1 13 | 14 | By making a contribution to this project, I certify that: 15 | 16 | (a) The contribution was created in whole or in part by me and I 17 | have the right to submit it under the open source license 18 | indicated in the file; or 19 | 20 | (b) The contribution is based upon previous work that, to the best 21 | of my knowledge, is covered under an appropriate open source 22 | license and I have the right under that license to submit that 23 | work with modifications, whether created in whole or in part 24 | by me, under the same open source license (unless I am 25 | permitted to submit under a different license), as indicated 26 | in the file; or 27 | 28 | (c) The contribution was provided directly to me by some other 29 | person who certified (a), (b) or (c) and I have not modified 30 | it. 31 | 32 | (d) I understand and agree that this project and the contribution 33 | are public and that a record of the contribution (including all 34 | personal information I submit with it, including my sign-off) is 35 | maintained indefinitely and may be redistributed consistent with 36 | this project or the open source license(s) involved. 37 | -------------------------------------------------------------------------------- /examples/httpserver/mykey.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEFTCCAv2gAwIBAgIJALM32kF9XINSMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV 3 | BAYTAlVTMQswCQYDVQQIEwJOWTEWMBQGA1UEBxMNTmV3IFlvcmsgQ2l0eTEVMBMG 4 | A1UEChMMQ29yZW9zLCBJbmMuMRkwFwYDVQQDFBBqd3Rwcm94eV9leGFtcGxlMB4X 5 | DTE2MDUwNDE3MzUwMloXDTE3MDUwNDE3MzUwMlowZDELMAkGA1UEBhMCVVMxCzAJ 6 | BgNVBAgTAk5ZMRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MRUwEwYDVQQKEwxDb3Jl 7 | b3MsIEluYy4xGTAXBgNVBAMUEGp3dHByb3h5X2V4YW1wbGUwggEiMA0GCSqGSIb3 8 | DQEBAQUAA4IBDwAwggEKAoIBAQDfqrznv6bhNVevmoCx20C+m5Iy1koq31GieXV5 9 | DGsOVngJzh/JEC5ZPlrCDvO4SNNW/cdMhOYagQOaCKdkCVg9rxf0BOx7Qa8Coh0c 10 | bJGMoHvbnJa1woorO53rE81O4En4hXW/NmtsAHH25utjfJ63Eaq2ifywZ/ynXhMF 11 | kqbKUZxasq6vzOoWhJh2DZ+i8I1QJogICz2sC0laYK9UqIaPB6ZpuGUqMFvdR+VM 12 | 5WQwaAchD7JFLcRvoaCH1vLTKuIJk8e5p1Er88F6/kgLeG10FF9zxHX66bzC0hzh 13 | e4kMGNmifzBCNKV6p4m3hwBVG4eeYDc6S2tOP3Zf/xQSmj6vAgMBAAGjgckwgcYw 14 | HQYDVR0OBBYEFC7Mlj5jDJAgVlhO9trpRcUaGDLjMIGWBgNVHSMEgY4wgYuAFC7M 15 | lj5jDJAgVlhO9trpRcUaGDLjoWikZjBkMQswCQYDVQQGEwJVUzELMAkGA1UECBMC 16 | TlkxFjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxFTATBgNVBAoTDENvcmVvcywgSW5j 17 | LjEZMBcGA1UEAxQQand0cHJveHlfZXhhbXBsZYIJALM32kF9XINSMAwGA1UdEwQF 18 | MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFQ/F4qeZvu9IIls9w06Itt2edlV6Jfx 19 | +y7X2v1XF+tXHUaOXbBn6lfIgElX/s1UYGVUpHAWK8gNTSmhRF1XuWoDJyBwSxZb 20 | fn9WYnwyGuylHIzEsVW4ChvOL8ZCBKOv8p3n2l3nMPsBg9TerzVLzp1Nn9IUBHDu 21 | oSPucVrsmSsjjHFRS3l4srs97sPrZnJXrZmaN9bWpgUVcsNQ2oqL95jHlhmvnw4h 22 | Qb9PC/mUtoCGQzBqTCtNzOA774S6phJNRFVGRdXwMqiV+UpwFu0KnqeMpcA4BDWe 23 | jMeWCpUYJlA3ulaZjNi4Q6ioMy7/7G+0aLTkxDeVDwYYgfHqjLDHezw= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /jwt/noncestorage/noncestorage.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 CoreOS, Inc 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package noncestorage 16 | 17 | import ( 18 | "fmt" 19 | "time" 20 | 21 | "github.com/quay/jwtproxy/config" 22 | "github.com/quay/jwtproxy/stop" 23 | ) 24 | 25 | type Constructor func(config.RegistrableComponentConfig) (NonceStorage, error) 26 | 27 | type NonceStorage interface { 28 | stop.Stoppable 29 | Verify(nonce string, expiration time.Time) bool 30 | } 31 | 32 | var storages = make(map[string]Constructor) 33 | 34 | func Register(name string, nsc Constructor) { 35 | if nsc == nil { 36 | panic("server: could not register nil NonceStorage") 37 | } 38 | if _, dup := storages[name]; dup { 39 | panic("server: could not register duplicate NonceStorage: " + name) 40 | } 41 | storages[name] = nsc 42 | } 43 | 44 | func New(cfg config.RegistrableComponentConfig) (NonceStorage, error) { 45 | nsc, ok := storages[cfg.Type] 46 | if !ok { 47 | return nil, fmt.Errorf("server: unknown NonceStorage %q (forgotten import?)", cfg.Type) 48 | } 49 | return nsc(cfg) 50 | } 51 | -------------------------------------------------------------------------------- /jwt/keyserver/keyregistry/keycache/keycache.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 CoreOS, Inc 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package keycache 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/gregjones/httpcache" 21 | 22 | "github.com/quay/jwtproxy/config" 23 | "github.com/quay/jwtproxy/stop" 24 | ) 25 | 26 | type Constructor func(config.RegistrableComponentConfig) (Cache, error) 27 | 28 | type Cache interface { 29 | stop.Stoppable 30 | httpcache.Cache 31 | } 32 | 33 | var keycaches = make(map[string]Constructor) 34 | 35 | func RegisterCache(name string, c Constructor) { 36 | if c == nil { 37 | panic("server: could not register nil ReaderConstructor") 38 | } 39 | if _, dup := keycaches[name]; dup { 40 | panic("server: could not register duplicate ReaderConstructor: " + name) 41 | } 42 | keycaches[name] = c 43 | } 44 | 45 | func NewCache(cfg config.RegistrableComponentConfig) (Cache, error) { 46 | c, ok := keycaches[cfg.Type] 47 | if !ok { 48 | return nil, fmt.Errorf("server: unknown Cache type %q (forgotten import?)", cfg.Type) 49 | } 50 | return c(cfg) 51 | } 52 | -------------------------------------------------------------------------------- /jwt/claims/verifier.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 CoreOS, Inc 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package claims 16 | 17 | import ( 18 | "fmt" 19 | "net/http" 20 | 21 | "github.com/coreos/go-oidc/jose" 22 | 23 | "github.com/quay/jwtproxy/config" 24 | "github.com/quay/jwtproxy/stop" 25 | ) 26 | 27 | type Constructor func(config.RegistrableComponentConfig) (Verifier, error) 28 | 29 | type Verifier interface { 30 | stop.Stoppable 31 | Handle(*http.Request, jose.Claims) error 32 | } 33 | 34 | var verifierTypes = make(map[string]Constructor) 35 | 36 | func Register(name string, vc Constructor) { 37 | if vc == nil { 38 | panic("server: could not register nil Verifier Constructor") 39 | } 40 | if _, dup := verifierTypes[name]; dup { 41 | panic("server: could not register duplicate Verifier Constructor type: " + name) 42 | } 43 | verifierTypes[name] = vc 44 | } 45 | 46 | func New(cfg config.RegistrableComponentConfig) (Verifier, error) { 47 | vc, ok := verifierTypes[cfg.Type] 48 | if !ok { 49 | return nil, fmt.Errorf("server: unknown Verifier Constructor type %q (forgotten import?)", cfg.Type) 50 | } 51 | return vc(cfg) 52 | } 53 | -------------------------------------------------------------------------------- /jwt/privatekey/privatekey.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 CoreOS, Inc 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package privatekey 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/coreos/go-oidc/key" 21 | 22 | "github.com/quay/jwtproxy/config" 23 | "github.com/quay/jwtproxy/stop" 24 | ) 25 | 26 | type PrivateKey interface { 27 | stop.Stoppable 28 | GetPrivateKey() (*key.PrivateKey, error) 29 | } 30 | 31 | type Constructor func(config.RegistrableComponentConfig, config.SignerParams) (PrivateKey, error) 32 | 33 | var privatekeys = make(map[string]Constructor) 34 | 35 | func Register(name string, pkc Constructor) { 36 | if pkc == nil { 37 | panic("server: could not register nil Constructor") 38 | } 39 | if _, dup := privatekeys[name]; dup { 40 | panic("server: could not register duplicate Constructor: " + name) 41 | } 42 | privatekeys[name] = pkc 43 | } 44 | 45 | func New(cfg config.RegistrableComponentConfig, params config.SignerParams) (PrivateKey, error) { 46 | pkc, ok := privatekeys[cfg.Type] 47 | if !ok { 48 | return nil, fmt.Errorf("server: unknown Constructor %q (forgotten import?)", cfg.Type) 49 | } 50 | return pkc(cfg, params) 51 | } 52 | -------------------------------------------------------------------------------- /examples/httpserver/mykey.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA36q857+m4TVXr5qAsdtAvpuSMtZKKt9Ronl1eQxrDlZ4Cc4f 3 | yRAuWT5awg7zuEjTVv3HTITmGoEDmginZAlYPa8X9ATse0GvAqIdHGyRjKB725yW 4 | tcKKKzud6xPNTuBJ+IV1vzZrbABx9ubrY3yetxGqton8sGf8p14TBZKmylGcWrKu 5 | r8zqFoSYdg2fovCNUCaICAs9rAtJWmCvVKiGjwemabhlKjBb3UflTOVkMGgHIQ+y 6 | RS3Eb6Ggh9by0yriCZPHuadRK/PBev5IC3htdBRfc8R1+um8wtIc4XuJDBjZon8w 7 | QjSleqeJt4cAVRuHnmA3OktrTj92X/8UEpo+rwIDAQABAoIBAAHdCEnd/OPvb9WU 8 | sfHJY9aysRsfUerdhW6XGHVztwidi855GyavrdMsg9EOEtW8NZaJ8rkeelRKMt97 9 | pvlcYpHQ/aAY0meMeorJEvkDporHY4DG4zKMdl451uz4c0Nu9u7NHdgD+g0iS9DE 10 | x71CcogP654ttB88Hoy+aeYn/J++3lJ+ReHaJRNOABDL/OOxDqAMTx3C1UFOWRGT 11 | sYquxxwWU1xE8JUmLXtB9jg+diSo6nS2HRil6j9cO6P8TFfJW6VkDlETtdH891xD 12 | 60q7WDeMPo8fP0i0dPAGeVlt9fmImhvJ9u5kgXIHTqaLk5v4BpiDdA/L0EsklAZs 13 | WBJYK9ECgYEA/CcayMCUVFGfYkS3yPur6WIcjNLhHnn3NdI3FX+ugB2nRs8gMBKN 14 | HqIWETznXkzPBpkq4fVX6HxTisoCUoJNYdhLtsZtCWIoE7XRMISG7HvF4fVJMgj+ 15 | UlyMkck5dfecJ7AuuuSXhwCRCUlaABwB0vUdBFax2tb8nsbAU7aMvvMCgYEA4xRe 16 | hUorBZ3xsol07j80jOf5fnT0MeKOvjvZXpQfobNIQGFAmWM8uybTXN/ZRSD9wPCn 17 | A4ef/RxW/jIjPdCJXwVZFRuJkRKR2FQMep8GoG8ujquVVNi48iToEEwoGPGFTW0f 18 | W+Eo6qa++XdyUgTCO3D5yUcOvQdDO3dQVhLLyFUCgYBNZl+FYf/mBgwLqRZVHlO9 19 | 1vz2iUDLDxtALR/1fHT/JJsVVD0IJJmm3pAxiGVo/+DIoLmWFK6AUbF/N9UQqKjC 20 | MRfEqhIMQFIXAseMwhF8g93RJ27pafNPKtOHaKI3wOLxF9awTbzpltXuaNK0l+RD 21 | cjQPAeGkUDvJLS8aQz3e2wKBgQCcfvc9SQYpUta1woGxiCHBUkXh3txEXO0fMcP2 22 | qIK8QAB1ThDlJT0/hdx4z1S/jaMUC0Yu6pNaLuPNP+SFv2hM8jSYlWfTcUbOHe6T 23 | u3EntDgT3zCFTu73AnRkdvfTaPADkkbgXWaDgPNwnd9NozXxHUUocC46G/07yFi3 24 | WTDUGQKBgHaDWintEOTVThpBxbNNFDRb1N01raXUMRT1ifIOux8+tdxzP4LjSgF4 25 | 5+icDQ1j2GXbJfmj3X6zTkU90ynfzboqrFyS8hYoFQsOQhmDe9qNSeO1bXmig1HV 26 | rySJ4P8KT0QvEzSUbm72wVBF0GHZ/SgE+zVXnLDtORrC47cd3U2u 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /examples/kubernetes-httpserver/mykey.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA36q857+m4TVXr5qAsdtAvpuSMtZKKt9Ronl1eQxrDlZ4Cc4f 3 | yRAuWT5awg7zuEjTVv3HTITmGoEDmginZAlYPa8X9ATse0GvAqIdHGyRjKB725yW 4 | tcKKKzud6xPNTuBJ+IV1vzZrbABx9ubrY3yetxGqton8sGf8p14TBZKmylGcWrKu 5 | r8zqFoSYdg2fovCNUCaICAs9rAtJWmCvVKiGjwemabhlKjBb3UflTOVkMGgHIQ+y 6 | RS3Eb6Ggh9by0yriCZPHuadRK/PBev5IC3htdBRfc8R1+um8wtIc4XuJDBjZon8w 7 | QjSleqeJt4cAVRuHnmA3OktrTj92X/8UEpo+rwIDAQABAoIBAAHdCEnd/OPvb9WU 8 | sfHJY9aysRsfUerdhW6XGHVztwidi855GyavrdMsg9EOEtW8NZaJ8rkeelRKMt97 9 | pvlcYpHQ/aAY0meMeorJEvkDporHY4DG4zKMdl451uz4c0Nu9u7NHdgD+g0iS9DE 10 | x71CcogP654ttB88Hoy+aeYn/J++3lJ+ReHaJRNOABDL/OOxDqAMTx3C1UFOWRGT 11 | sYquxxwWU1xE8JUmLXtB9jg+diSo6nS2HRil6j9cO6P8TFfJW6VkDlETtdH891xD 12 | 60q7WDeMPo8fP0i0dPAGeVlt9fmImhvJ9u5kgXIHTqaLk5v4BpiDdA/L0EsklAZs 13 | WBJYK9ECgYEA/CcayMCUVFGfYkS3yPur6WIcjNLhHnn3NdI3FX+ugB2nRs8gMBKN 14 | HqIWETznXkzPBpkq4fVX6HxTisoCUoJNYdhLtsZtCWIoE7XRMISG7HvF4fVJMgj+ 15 | UlyMkck5dfecJ7AuuuSXhwCRCUlaABwB0vUdBFax2tb8nsbAU7aMvvMCgYEA4xRe 16 | hUorBZ3xsol07j80jOf5fnT0MeKOvjvZXpQfobNIQGFAmWM8uybTXN/ZRSD9wPCn 17 | A4ef/RxW/jIjPdCJXwVZFRuJkRKR2FQMep8GoG8ujquVVNi48iToEEwoGPGFTW0f 18 | W+Eo6qa++XdyUgTCO3D5yUcOvQdDO3dQVhLLyFUCgYBNZl+FYf/mBgwLqRZVHlO9 19 | 1vz2iUDLDxtALR/1fHT/JJsVVD0IJJmm3pAxiGVo/+DIoLmWFK6AUbF/N9UQqKjC 20 | MRfEqhIMQFIXAseMwhF8g93RJ27pafNPKtOHaKI3wOLxF9awTbzpltXuaNK0l+RD 21 | cjQPAeGkUDvJLS8aQz3e2wKBgQCcfvc9SQYpUta1woGxiCHBUkXh3txEXO0fMcP2 22 | qIK8QAB1ThDlJT0/hdx4z1S/jaMUC0Yu6pNaLuPNP+SFv2hM8jSYlWfTcUbOHe6T 23 | u3EntDgT3zCFTu73AnRkdvfTaPADkkbgXWaDgPNwnd9NozXxHUUocC46G/07yFi3 24 | WTDUGQKBgHaDWintEOTVThpBxbNNFDRb1N01raXUMRT1ifIOux8+tdxzP4LjSgF4 25 | 5+icDQ1j2GXbJfmj3X6zTkU90ynfzboqrFyS8hYoFQsOQhmDe9qNSeO1bXmig1HV 26 | rySJ4P8KT0QvEzSUbm72wVBF0GHZ/SgE+zVXnLDtORrC47cd3U2u 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /glide.yaml: -------------------------------------------------------------------------------- 1 | package: github.com/quay/jwtproxy 2 | import: 3 | - package: github.com/sirupsen/logrus 4 | version: ^0.10.0 5 | - package: github.com/coreos/go-oidc 6 | version: f427f54ef96beaa1db5fabbe4fff00de535d5494 7 | subpackages: 8 | - http 9 | - jose 10 | - key 11 | - oauth2 12 | - oidc 13 | - package: github.com/coreos/go-systemd 14 | version: ^5.0.0 15 | subpackages: 16 | - journal 17 | - package: github.com/coreos/goproxy 18 | version: 25fe2597a3d151ba954d9b3c0fd4663e79de48cc 19 | - package: github.com/coreos/pkg 20 | version: 1914e367e85eaf0c25d495b48e060dfe6190f8d0 21 | subpackages: 22 | - capnslog 23 | - health 24 | - httputil 25 | - timeutil 26 | - package: github.com/davecgh/go-spew 27 | version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d 28 | subpackages: 29 | - spew 30 | - package: github.com/gregjones/httpcache 31 | version: 4b02602f71f4346dfbd3ef8f4d15cc2a318b32c1 32 | - package: github.com/jonboulle/clockwork 33 | version: ed104f61ea4877bea08af6f759805674861e968d 34 | - package: github.com/patrickmn/go-cache 35 | version: ^2.0.0 36 | - package: github.com/pmezard/go-difflib 37 | version: ^1.0.0 38 | subpackages: 39 | - difflib 40 | - package: github.com/stretchr/testify 41 | version: c5d7a69bf8a2c9c374798160849c071093e41dd1 42 | subpackages: 43 | - assert 44 | - package: github.com/tylerb/graceful 45 | version: ^1.2.5 46 | - package: golang.org/x/net 47 | version: 024ed629fd292398cfd43c9678a5bf004f7defdc 48 | subpackages: 49 | - netutil 50 | - package: golang.org/x/sys 51 | version: a60af9cbbc6ab800af4f2be864a31f423a0ae1f2 52 | subpackages: 53 | - unix 54 | - package: gopkg.in/square/go-jose.v2 55 | version: 77e6c51d4de65c9a8d5a27a99e0e2721b12f1a2c 56 | subpackages: 57 | - cipher 58 | - json 59 | - package: gopkg.in/yaml.v2 60 | version: a83829b6f1293c91addabc89d0571c246397bbf4 61 | -------------------------------------------------------------------------------- /bill-of-materials.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "project": "github.com/quay/jwtproxy", 4 | "license": "Apache License 2.0", 5 | "confidence": 1 6 | }, 7 | { 8 | "project": "github.com/sirupsen/logrus", 9 | "license": "MIT License", 10 | "confidence": 1 11 | }, 12 | { 13 | "project": "github.com/coreos/go-oidc", 14 | "license": "Apache License 2.0", 15 | "confidence": 1 16 | }, 17 | { 18 | "project": "github.com/coreos/go-systemd/journal", 19 | "license": "Apache License 2.0", 20 | "confidence": 0.997 21 | }, 22 | { 23 | "project": "github.com/coreos/goproxy", 24 | "license": "BSD 3-clause \"New\" or \"Revised\" License", 25 | "confidence": 0.966 26 | }, 27 | { 28 | "project": "github.com/coreos/pkg", 29 | "license": "Apache License 2.0", 30 | "confidence": 1 31 | }, 32 | { 33 | "project": "github.com/gregjones/httpcache", 34 | "license": "MIT License", 35 | "confidence": 0.989 36 | }, 37 | { 38 | "project": "github.com/jonboulle/clockwork", 39 | "license": "Apache License 2.0", 40 | "confidence": 1 41 | }, 42 | { 43 | "project": "github.com/patrickmn/go-cache", 44 | "license": "MIT License", 45 | "confidence": 0.989 46 | }, 47 | { 48 | "project": "github.com/tylerb/graceful", 49 | "license": "MIT License", 50 | "confidence": 1 51 | }, 52 | { 53 | "project": "golang.org/x/net/netutil", 54 | "license": "BSD 3-clause \"New\" or \"Revised\" License", 55 | "confidence": 0.966 56 | }, 57 | { 58 | "project": "gopkg.in/square/go-jose.v2/cipher", 59 | "license": "Apache License 2.0", 60 | "confidence": 1 61 | }, 62 | { 63 | "project": "gopkg.in/square/go-jose.v2/json", 64 | "license": "BSD 3-clause \"New\" or \"Revised\" License", 65 | "confidence": 0.966 66 | }, 67 | { 68 | "project": "gopkg.in/yaml.v2", 69 | "license": "GNU Lesser General Public License v3.0", 70 | "confidence": 0.953 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /jwt/noncestorage/local/local.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 CoreOS, Inc 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package local 16 | 17 | import ( 18 | "time" 19 | 20 | "gopkg.in/yaml.v2" 21 | 22 | "github.com/quay/jwtproxy/config" 23 | "github.com/quay/jwtproxy/jwt/noncestorage" 24 | "github.com/quay/jwtproxy/stop" 25 | "github.com/patrickmn/go-cache" 26 | ) 27 | 28 | func init() { 29 | noncestorage.Register("local", constructor) 30 | } 31 | 32 | type Local struct { 33 | *cache.Cache 34 | } 35 | 36 | type Config struct { 37 | PurgeInterval time.Duration `yaml:"purge_interval"` 38 | } 39 | 40 | func constructor(registrableComponentConfig config.RegistrableComponentConfig) (noncestorage.NonceStorage, error) { 41 | var cfg Config 42 | bytes, err := yaml.Marshal(registrableComponentConfig.Options) 43 | if err != nil { 44 | return nil, err 45 | } 46 | err = yaml.Unmarshal(bytes, &cfg) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | return &Local{ 52 | Cache: cache.New(cache.NoExpiration, cfg.PurgeInterval), 53 | }, nil 54 | } 55 | 56 | func (ln *Local) Verify(nonce string, expiration time.Time) bool { 57 | if _, found := ln.Get(nonce); found { 58 | return false 59 | } 60 | ln.Set(nonce, struct{}{}, expiration.Sub(time.Now())) 61 | return true 62 | } 63 | 64 | func (ln *Local) Stop() <-chan struct{} { 65 | return stop.AlreadyDone 66 | } 67 | -------------------------------------------------------------------------------- /examples/httpserver/README.md: -------------------------------------------------------------------------------- 1 | # HTTP Server 2 | 3 | This example demonstrates authenticating a web service using jwtproxy. 4 | 5 | ``` 6 | client <--> signer proxy <--> verifier proxy <--> web service 7 | ``` 8 | 9 | Three components are deployed using the Procfile contained in this example folder: 10 | - **A simple web server**: The web server provides a web service on which we want to add authentication. 11 | - **A forward proxy**: Used by the web service clients, the proxy signs every requests to our web service by adding a JWT. 12 | - **A reverse proxy**: The reverse proxy receives requests, validates JWTs and forwards the requests to the web server. 13 | 14 | ### Pre-requisites 15 | 16 | To run this example, you need [Go] and a working [Go environment] and [goreman]. 17 | 18 | [Go 1.6]: https://github.com/golang/go/releases 19 | [Go environment]: https://golang.org/doc/code.html 20 | [goreman]: https://github.com/mattn/goreman 21 | 22 | ### Configuration 23 | 24 | For the sake of simplicity, this example uses a pre-shared key pair to sign and verify the requests. Two configuration files are used, one for the signer and one for the verifier, respectively `signer.yaml` and `verifier.yaml`. It is recommended that you inspect them to understand how jwtproxy works. 25 | 26 | ### Run 27 | 28 | Simply execute the Procfile: 29 | 30 | ``` 31 | goreman start 32 | ``` 33 | 34 | ### Test 35 | 36 | Using curl, we send a request for the web service to the verifier proxy address. The verifier proxy will verify the authentication token and forward it upon success to our web service. We also specify that a forward proxy has to be used - it will sign our requests. 37 | 38 | ``` 39 | curl --proxy localhost:3128 http://localhost:8080/ 40 | ``` 41 | 42 | ### Learn more 43 | 44 | Extensive documentation can be found in the [README]. 45 | To learn more about the different configuration parameters, you may read [config.example.yaml]. 46 | 47 | [README]: ../../README.md 48 | [config.example.yaml]: ../../config.example.yaml 49 | -------------------------------------------------------------------------------- /jwt/claims/static/static.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 CoreOS, Inc 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package static 16 | 17 | import ( 18 | "fmt" 19 | "net/http" 20 | "reflect" 21 | 22 | "github.com/coreos/go-oidc/jose" 23 | log "github.com/sirupsen/logrus" 24 | 25 | "github.com/quay/jwtproxy/config" 26 | "github.com/quay/jwtproxy/jwt/claims" 27 | "github.com/quay/jwtproxy/stop" 28 | ) 29 | 30 | func init() { 31 | claims.Register("static", constructor) 32 | } 33 | 34 | type Static struct { 35 | requiredClaims map[string]interface{} 36 | } 37 | 38 | func (scv *Static) Handle(req *http.Request, claims jose.Claims) error { 39 | log.Debugf("Verifying %d claims", len(scv.requiredClaims)) 40 | for name, requiredValue := range scv.requiredClaims { 41 | log.Debugf("Verifying claim named: %s", name) 42 | // Look for the claim in the JWT claims. 43 | if found, ok := claims[name]; ok { 44 | if !reflect.DeepEqual(found, requiredValue) { 45 | return fmt.Errorf("Claim did not have the required value: %s", name) 46 | } 47 | } else { 48 | return fmt.Errorf("Required claim not found: %s", name) 49 | } 50 | } 51 | 52 | return nil 53 | } 54 | 55 | func (scv *Static) Stop() <-chan struct{} { 56 | return stop.AlreadyDone 57 | } 58 | 59 | func constructor(registrableComponentConfig config.RegistrableComponentConfig) (claims.Verifier, error) { 60 | return &Static{ 61 | requiredClaims: registrableComponentConfig.Options, 62 | }, nil 63 | } 64 | -------------------------------------------------------------------------------- /glide.lock: -------------------------------------------------------------------------------- 1 | hash: e9be2167eed774041b7d368bb6054c64cdb94699fa91b7beffb739c50f4cf583 2 | updated: 2019-05-14T12:30:21.525021-04:00 3 | imports: 4 | - name: github.com/coreos/go-oidc 5 | version: f427f54ef96beaa1db5fabbe4fff00de535d5494 6 | subpackages: 7 | - http 8 | - jose 9 | - key 10 | - oauth2 11 | - oidc 12 | - name: github.com/coreos/go-systemd 13 | version: 7b2428fec40033549c68f54e26e89e7ca9a9ce31 14 | subpackages: 15 | - journal 16 | - name: github.com/coreos/goproxy 17 | version: 25fe2597a3d151ba954d9b3c0fd4663e79de48cc 18 | - name: github.com/coreos/pkg 19 | version: 1914e367e85eaf0c25d495b48e060dfe6190f8d0 20 | subpackages: 21 | - capnslog 22 | - health 23 | - httputil 24 | - timeutil 25 | - name: github.com/davecgh/go-spew 26 | version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d 27 | subpackages: 28 | - spew 29 | - name: github.com/gregjones/httpcache 30 | version: 4b02602f71f4346dfbd3ef8f4d15cc2a318b32c1 31 | - name: github.com/jonboulle/clockwork 32 | version: ed104f61ea4877bea08af6f759805674861e968d 33 | - name: github.com/patrickmn/go-cache 34 | version: a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0 35 | - name: github.com/pmezard/go-difflib 36 | version: 792786c7400a136282c1664665ae0a8db921c6c2 37 | subpackages: 38 | - difflib 39 | - name: github.com/sirupsen/logrus 40 | version: ba1b36c82c5e05c4f912a88eab0dcd91a171688f 41 | - name: github.com/stretchr/testify 42 | version: c5d7a69bf8a2c9c374798160849c071093e41dd1 43 | subpackages: 44 | - assert 45 | - name: github.com/tylerb/graceful 46 | version: 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb 47 | - name: golang.org/x/net 48 | version: 024ed629fd292398cfd43c9678a5bf004f7defdc 49 | subpackages: 50 | - netutil 51 | - name: golang.org/x/sys 52 | version: a60af9cbbc6ab800af4f2be864a31f423a0ae1f2 53 | subpackages: 54 | - unix 55 | - name: gopkg.in/square/go-jose.v2 56 | version: 77e6c51d4de65c9a8d5a27a99e0e2721b12f1a2c 57 | subpackages: 58 | - cipher 59 | - json 60 | - name: gopkg.in/yaml.v2 61 | version: a83829b6f1293c91addabc89d0571c246397bbf4 62 | testImports: [] 63 | -------------------------------------------------------------------------------- /stop/stopper.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 CoreOS, Inc 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package stop 16 | 17 | import ( 18 | "sync" 19 | ) 20 | 21 | var AlreadyDone <-chan struct{} 22 | 23 | func init() { 24 | closeMe := make(chan struct{}) 25 | close(closeMe) 26 | AlreadyDone = closeMe 27 | } 28 | 29 | type Stoppable interface { 30 | Stop() <-chan struct{} 31 | } 32 | 33 | type Group struct { 34 | stoppables []StopperFunc 35 | stoppablesLock sync.Mutex 36 | } 37 | 38 | type StopperFunc func() <-chan struct{} 39 | 40 | func NewGroup() *Group { 41 | return &Group{ 42 | stoppables: make([]StopperFunc, 0), 43 | } 44 | } 45 | 46 | func (cg *Group) Add(toAdd Stoppable) { 47 | cg.stoppablesLock.Lock() 48 | defer cg.stoppablesLock.Unlock() 49 | 50 | cg.stoppables = append(cg.stoppables, toAdd.Stop) 51 | } 52 | 53 | func (cg *Group) AddFunc(toAddFunc StopperFunc) { 54 | cg.stoppablesLock.Lock() 55 | defer cg.stoppablesLock.Unlock() 56 | 57 | cg.stoppables = append(cg.stoppables, toAddFunc) 58 | } 59 | 60 | func (cg *Group) Stop() <-chan struct{} { 61 | cg.stoppablesLock.Lock() 62 | defer cg.stoppablesLock.Unlock() 63 | 64 | whenDone := make(chan struct{}) 65 | 66 | waitChannels := make([]<-chan struct{}, 0, len(cg.stoppables)) 67 | for _, toStop := range cg.stoppables { 68 | waitFor := toStop() 69 | if waitFor == nil { 70 | panic("Someone returned a nil chan from Stop") 71 | } 72 | waitChannels = append(waitChannels, waitFor) 73 | } 74 | 75 | cg.stoppables = make([]StopperFunc, 0) 76 | 77 | go func() { 78 | for _, waitForMe := range waitChannels { 79 | <-waitForMe 80 | } 81 | close(whenDone) 82 | }() 83 | return whenDone 84 | } 85 | -------------------------------------------------------------------------------- /examples/kubernetes-httpserver/README.md: -------------------------------------------------------------------------------- 1 | # Authenticated nginx server on Kubernetes 2 | 3 | This example demonstrates authenticating an nginx server using jwtproxy on Kubernetes. 4 | 5 | In this example, we will deploy a pod that contains a unexposed nginx server and a verifier proxy, exposed on the port 80. Because the nginx server is unexposed, the only way to access it externally (i.e. outside the pod) is to go through the reverse proxy, which enforce authentication by validating JWTs. A service will also be created to enable external access (i.e. outside the cluster) to the service. 6 | 7 | ### Pre-requisites 8 | 9 | To run this example, you need a working [Kubernetes] cluster. 10 | 11 | 12 | For the sake of simplicity, this example uses a pre-shared key pair to sign and verify the requests. 13 | 14 | [Kubernetes]: http://kubernetes.io/ 15 | 16 | ### Deploy 17 | 18 | First of all, we create two Kubernetes secrets: 19 | - **secret-nginx-config**: Contains an nginx virtual host configuration file to make our web server listen on port 8080 (in the pod only) and serve a static response, 20 | - **secret-jwtproxy-config**: Contains the verifier proxy configuration that will listen on port 80 (externally), verify requests' authentication and forward them to nginx. 21 | 22 | ``` 23 | $ kubectl create secret generic secret-nginx-config --from-file nginx.conf 24 | $ kubectl create secret generic secret-verifier-config --from-file verifier.yaml --from-file mykey.pub 25 | ``` 26 | 27 | And then, we deploy the pod and service that expose our secured web service: 28 | 29 | ``` 30 | $ kubectl create -f nginx-app.yaml 31 | ``` 32 | 33 | ### Test 34 | 35 | To demonstrate a bit further, we'll deploy a second pod that will send requests to our web service at regular intervals, via a signer proxy that will provide authentication. 36 | 37 | ``` 38 | $ kubectl create secret generic secret-tester-config --from-file signer.yaml --from-file mykey.key 39 | $ kubectl create -f tester-app.yaml 40 | ``` 41 | 42 | As soon as the pod is deployed, we can watch the logs and read the responses to our authenticated requests. 43 | 44 | ``` 45 | $ kubectl logs -f tester tester 46 | Welcome to this authenticated web service. 47 | Welcome to this authenticated web service. 48 | Welcome to this authenticated web service. 49 | ``` 50 | 51 | ### Learn more 52 | 53 | Extensive documentation can be found in the [README]. 54 | To learn more about the different configuration parameters, you may read [config.example.yaml]. 55 | 56 | [README]: ../../README 57 | [config.example.yaml]: ../../config.example.yaml 58 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | CoreOS projects are [Apache 2.0 licensed](LICENSE) and accept contributions via 4 | GitHub pull requests. This document outlines some of the conventions on 5 | development workflow, commit message formatting, contact points and other 6 | resources to make it easier to get your contribution accepted. 7 | 8 | # Certificate of Origin 9 | 10 | By contributing to this project you agree to the Developer Certificate of 11 | Origin (DCO). This document was created by the Linux Kernel community and is a 12 | simple statement that you, as a contributor, have the legal right to make the 13 | contribution. See the [DCO](DCO) file for details. 14 | 15 | # Email and Chat 16 | 17 | The project currently uses the general CoreOS email list and IRC channel: 18 | - Email: [coreos-dev](https://groups.google.com/forum/#!forum/coreos-dev) 19 | - IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org 20 | 21 | Please avoid emailing maintainers found in the MAINTAINERS file directly. They 22 | are very busy and read the mailing lists. 23 | 24 | ## Getting Started 25 | 26 | - Fork the repository on GitHub 27 | - Read the [README](README.md) for build and test instructions 28 | - Play with the project, submit bugs, submit patches! 29 | 30 | ## Contribution Flow 31 | 32 | This is a rough outline of what a contributor's workflow looks like: 33 | 34 | - Create a topic branch from where you want to base your work (usually master). 35 | - Make commits of logical units. 36 | - Make sure your commit messages are in the proper format (see below). 37 | - Push your changes to a topic branch in your fork of the repository. 38 | - Make sure the tests pass, and add any new tests as appropriate. 39 | - Submit a pull request to the original repository. 40 | 41 | Thanks for your contributions! 42 | 43 | ### Format of the Commit Message 44 | 45 | We follow a rough convention for commit messages that is designed to answer two 46 | questions: what changed and why. The subject line should feature the what and 47 | the body of the commit should describe the why. 48 | 49 | ``` 50 | scripts: add the test-cluster command 51 | 52 | this uses tmux to setup a test cluster that you can easily kill and 53 | start for debugging. 54 | 55 | Fixes #38 56 | ``` 57 | 58 | The format can be described more formally as follows: 59 | 60 | ``` 61 | : 62 | 63 | 64 | 65 |