Merge pull request #111 from timothy-spencer/jwtsigningkeyfile
added jwt-key-file option
This commit is contained in:
commit
46a0d7ca54
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
## Changes since v3.2.0
|
## Changes since v3.2.0
|
||||||
|
|
||||||
|
- [#111](https://github.com/pusher/oauth2_proxy/pull/111) Add option for telling where to find a login.gov JWT key file (@timothy-spencer)
|
||||||
|
|
||||||
# v3.2.0
|
# v3.2.0
|
||||||
|
|
||||||
## Release highlights
|
## Release highlights
|
||||||
|
10
Dockerfile
10
Dockerfile
@ -11,13 +11,19 @@ COPY . .
|
|||||||
# Fetch dependencies
|
# Fetch dependencies
|
||||||
RUN dep ensure --vendor-only
|
RUN dep ensure --vendor-only
|
||||||
|
|
||||||
# Build binary
|
# Build binary and make sure there is at least an empty key file.
|
||||||
RUN ./configure && make build
|
# This is useful for GCP App Engine custom runtime builds, because
|
||||||
|
# you cannot use multiline variables in their app.yaml, so you have to
|
||||||
|
# build the key into the container and then tell it where it is
|
||||||
|
# by setting OAUTH2_PROXY_JWT_KEY_FILE=/etc/ssl/private/jwt_signing_key.pem
|
||||||
|
# in app.yaml instead.
|
||||||
|
RUN ./configure && make build && touch jwt_signing_key.pem
|
||||||
|
|
||||||
# Copy binary to alpine
|
# Copy binary to alpine
|
||||||
FROM alpine:3.8
|
FROM alpine:3.8
|
||||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||||
COPY --from=builder /go/src/github.com/pusher/oauth2_proxy/oauth2_proxy /bin/oauth2_proxy
|
COPY --from=builder /go/src/github.com/pusher/oauth2_proxy/oauth2_proxy /bin/oauth2_proxy
|
||||||
|
COPY --from=builder /go/src/github.com/pusher/oauth2_proxy/jwt_signing_key.pem /etc/ssl/private/jwt_signing_key.pem
|
||||||
|
|
||||||
RUN addgroup -S -g 2000 oauth2proxy && adduser -S -u 2000 oauth2proxy -G oauth2proxy
|
RUN addgroup -S -g 2000 oauth2proxy && adduser -S -u 2000 oauth2proxy -G oauth2proxy
|
||||||
USER oauth2proxy
|
USER oauth2proxy
|
||||||
|
@ -11,13 +11,19 @@ COPY . .
|
|||||||
# Fetch dependencies
|
# Fetch dependencies
|
||||||
RUN dep ensure --vendor-only
|
RUN dep ensure --vendor-only
|
||||||
|
|
||||||
# Build binary
|
# Build binary and make sure there is at least an empty key file.
|
||||||
RUN ./configure && GOARCH=arm64 make build
|
# This is useful for GCP App Engine custom runtime builds, because
|
||||||
|
# you cannot use multiline variables in their app.yaml, so you have to
|
||||||
|
# build the key into the container and then tell it where it is
|
||||||
|
# by setting OAUTH2_PROXY_JWT_KEY_FILE=/etc/ssl/private/jwt_signing_key.pem
|
||||||
|
# in app.yaml instead.
|
||||||
|
RUN ./configure && GOARCH=arm64 make build && touch jwt_signing_key.pem
|
||||||
|
|
||||||
# Copy binary to alpine
|
# Copy binary to alpine
|
||||||
FROM arm64v8/alpine:3.8
|
FROM arm64v8/alpine:3.8
|
||||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||||
COPY --from=builder /go/src/github.com/pusher/oauth2_proxy/oauth2_proxy /bin/oauth2_proxy
|
COPY --from=builder /go/src/github.com/pusher/oauth2_proxy/oauth2_proxy /bin/oauth2_proxy
|
||||||
|
COPY --from=builder /go/src/github.com/pusher/oauth2_proxy/jwt_signing_key.pem /etc/ssl/private/jwt_signing_key.pem
|
||||||
|
|
||||||
RUN addgroup -S -g 2000 oauth2proxy && adduser -S -u 2000 oauth2proxy -G oauth2proxy
|
RUN addgroup -S -g 2000 oauth2proxy && adduser -S -u 2000 oauth2proxy -G oauth2proxy
|
||||||
USER oauth2proxy
|
USER oauth2proxy
|
||||||
|
@ -11,13 +11,19 @@ COPY . .
|
|||||||
# Fetch dependencies
|
# Fetch dependencies
|
||||||
RUN dep ensure --vendor-only
|
RUN dep ensure --vendor-only
|
||||||
|
|
||||||
# Build binary
|
# Build binary and make sure there is at least an empty key file.
|
||||||
RUN ./configure && GOARCH=arm GOARM=6 make build
|
# This is useful for GCP App Engine custom runtime builds, because
|
||||||
|
# you cannot use multiline variables in their app.yaml, so you have to
|
||||||
|
# build the key into the container and then tell it where it is
|
||||||
|
# by setting OAUTH2_PROXY_JWT_KEY_FILE=/etc/ssl/private/jwt_signing_key.pem
|
||||||
|
# in app.yaml instead.
|
||||||
|
RUN ./configure && GOARCH=arm GOARM=6 make build && touch jwt_signing_key.pem
|
||||||
|
|
||||||
# Copy binary to alpine
|
# Copy binary to alpine
|
||||||
FROM arm32v6/alpine:3.8
|
FROM arm32v6/alpine:3.8
|
||||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||||
COPY --from=builder /go/src/github.com/pusher/oauth2_proxy/oauth2_proxy /bin/oauth2_proxy
|
COPY --from=builder /go/src/github.com/pusher/oauth2_proxy/oauth2_proxy /bin/oauth2_proxy
|
||||||
|
COPY --from=builder /go/src/github.com/pusher/oauth2_proxy/jwt_signing_key.pem /etc/ssl/private/jwt_signing_key.pem
|
||||||
|
|
||||||
RUN addgroup -S -g 2000 oauth2proxy && adduser -S -u 2000 oauth2proxy -G oauth2proxy
|
RUN addgroup -S -g 2000 oauth2proxy && adduser -S -u 2000 oauth2proxy -G oauth2proxy
|
||||||
USER oauth2proxy
|
USER oauth2proxy
|
||||||
|
13
README.md
13
README.md
@ -216,6 +216,13 @@ Now start the proxy up with the following options:
|
|||||||
-jwt-key="${OAUTH2_PROXY_JWT_KEY}"
|
-jwt-key="${OAUTH2_PROXY_JWT_KEY}"
|
||||||
```
|
```
|
||||||
You can also set all these options with environment variables, for use in cloud/docker environments.
|
You can also set all these options with environment variables, for use in cloud/docker environments.
|
||||||
|
One tricky thing that you may encounter is that some cloud environments will pass in environment
|
||||||
|
variables in a docker env-file, which does not allow multiline variables like a PEM file.
|
||||||
|
If you encounter this, then you can create a `jwt_signing_key.pem` file in the top level
|
||||||
|
directory of the repo which contains the key in PEM format and then do your docker build.
|
||||||
|
The docker build process will copy that file into your image which you can then access by
|
||||||
|
setting the `OAUTH2_PROXY_JWT_KEY_FILE=/etc/ssl/private/jwt_signing_key.pem`
|
||||||
|
environment variable, or by setting `-jwt-key-file=/etc/ssl/private/jwt_signing_key.pem` on the commandline.
|
||||||
|
|
||||||
Once it is running, you should be able to go to `http://localhost:4180/` in your browser,
|
Once it is running, you should be able to go to `http://localhost:4180/` in your browser,
|
||||||
get authenticated by the login.gov integration server, and then get proxied on to your
|
get authenticated by the login.gov integration server, and then get proxied on to your
|
||||||
@ -261,6 +268,7 @@ An example [oauth2_proxy.cfg](contrib/oauth2_proxy.cfg.example) config file is i
|
|||||||
|
|
||||||
```
|
```
|
||||||
Usage of oauth2_proxy:
|
Usage of oauth2_proxy:
|
||||||
|
-acr-values string: optional, used by login.gov (default "http://idmanagement.gov/ns/assurance/loa/1")
|
||||||
-approval-prompt string: OAuth approval_prompt (default "force")
|
-approval-prompt string: OAuth approval_prompt (default "force")
|
||||||
-authenticated-emails-file string: authenticate against emails via file (one per line)
|
-authenticated-emails-file string: authenticate against emails via file (one per line)
|
||||||
-azure-tenant string: go to a tenant-specific or common (tenant-independent) endpoint. (default "common")
|
-azure-tenant string: go to a tenant-specific or common (tenant-independent) endpoint. (default "common")
|
||||||
@ -269,10 +277,10 @@ Usage of oauth2_proxy:
|
|||||||
-client-secret string: the OAuth Client Secret
|
-client-secret string: the OAuth Client Secret
|
||||||
-config string: path to config file
|
-config string: path to config file
|
||||||
-cookie-domain string: an optional cookie domain to force cookies to (ie: .yourcompany.com)
|
-cookie-domain string: an optional cookie domain to force cookies to (ie: .yourcompany.com)
|
||||||
-cookie-path string: an optional cookie path to force cookies to (ie: /foo)
|
|
||||||
-cookie-expire duration: expire timeframe for cookie (default 168h0m0s)
|
-cookie-expire duration: expire timeframe for cookie (default 168h0m0s)
|
||||||
-cookie-httponly: set HttpOnly cookie flag (default true)
|
-cookie-httponly: set HttpOnly cookie flag (default true)
|
||||||
-cookie-name string: the name of the cookie that the oauth_proxy creates (default "_oauth2_proxy")
|
-cookie-name string: the name of the cookie that the oauth_proxy creates (default "_oauth2_proxy")
|
||||||
|
-cookie-path string: an optional cookie path to force cookies to (ie: /poc/)* (default "/")
|
||||||
-cookie-refresh duration: refresh the cookie after this duration; 0 to disable
|
-cookie-refresh duration: refresh the cookie after this duration; 0 to disable
|
||||||
-cookie-secret string: the seed string for secure cookies (optionally base64 encoded)
|
-cookie-secret string: the seed string for secure cookies (optionally base64 encoded)
|
||||||
-cookie-secure: set secure (HTTPS) cookie flag (default true)
|
-cookie-secure: set secure (HTTPS) cookie flag (default true)
|
||||||
@ -290,6 +298,8 @@ Usage of oauth2_proxy:
|
|||||||
-htpasswd-file string: additionally authenticate against a htpasswd file. Entries must be created with "htpasswd -s" for SHA encryption
|
-htpasswd-file string: additionally authenticate against a htpasswd file. Entries must be created with "htpasswd -s" for SHA encryption
|
||||||
-http-address string: [http://]<addr>:<port> or unix://<path> to listen on for HTTP clients (default "127.0.0.1:4180")
|
-http-address string: [http://]<addr>:<port> or unix://<path> to listen on for HTTP clients (default "127.0.0.1:4180")
|
||||||
-https-address string: <addr>:<port> to listen on for HTTPS clients (default ":443")
|
-https-address string: <addr>:<port> to listen on for HTTPS clients (default ":443")
|
||||||
|
-jwt-key string: private key in PEM format used to sign JWT, so that you can say something like -jwt-key="${OAUTH2_PROXY_JWT_KEY}": required by login.gov
|
||||||
|
-jwt-key-file string: path to the private key file in PEM format used to sign the JWT so that you can say something like -jwt-key-file=/etc/ssl/private/jwt_signing_key.pem: required by login.gov
|
||||||
-login-url string: Authentication endpoint
|
-login-url string: Authentication endpoint
|
||||||
-oidc-issuer-url: the OpenID Connect issuer URL. ie: "https://accounts.google.com"
|
-oidc-issuer-url: the OpenID Connect issuer URL. ie: "https://accounts.google.com"
|
||||||
-oidc-jwks-url string: OIDC JWKS URI for token verification; required if OIDC discovery is disabled
|
-oidc-jwks-url string: OIDC JWKS URI for token verification; required if OIDC discovery is disabled
|
||||||
@ -302,6 +312,7 @@ Usage of oauth2_proxy:
|
|||||||
-provider string: OAuth provider (default "google")
|
-provider string: OAuth provider (default "google")
|
||||||
-proxy-prefix string: the url root path that this proxy should be nested under (e.g. /<oauth2>/sign_in) (default "/oauth2")
|
-proxy-prefix string: the url root path that this proxy should be nested under (e.g. /<oauth2>/sign_in) (default "/oauth2")
|
||||||
-proxy-websockets: enables WebSocket proxying (default true)
|
-proxy-websockets: enables WebSocket proxying (default true)
|
||||||
|
-pubjwk-url string: JWK pubkey access endpoint: required by login.gov
|
||||||
-redeem-url string: Token redemption endpoint
|
-redeem-url string: Token redemption endpoint
|
||||||
-redirect-url string: the OAuth Redirect URL. ie: "https://internalapp.yourcompany.com/oauth2/callback"
|
-redirect-url string: the OAuth Redirect URL. ie: "https://internalapp.yourcompany.com/oauth2/callback"
|
||||||
-request-logging: Log requests to stdout (default true)
|
-request-logging: Log requests to stdout (default true)
|
||||||
|
3
main.go
3
main.go
@ -92,7 +92,8 @@ func main() {
|
|||||||
|
|
||||||
flagSet.String("signature-key", "", "GAP-Signature request signature key (algorithm:secretkey)")
|
flagSet.String("signature-key", "", "GAP-Signature request signature key (algorithm:secretkey)")
|
||||||
flagSet.String("acr-values", "http://idmanagement.gov/ns/assurance/loa/1", "acr values string: optional, used by login.gov")
|
flagSet.String("acr-values", "http://idmanagement.gov/ns/assurance/loa/1", "acr values string: optional, used by login.gov")
|
||||||
flagSet.String("jwt-key", "", "private key used to sign JWT: required by login.gov")
|
flagSet.String("jwt-key", "", "private key in PEM format used to sign JWT, so that you can say something like -jwt-key=\"${OAUTH2_PROXY_JWT_KEY}\": required by login.gov")
|
||||||
|
flagSet.String("jwt-key-file", "", "path to the private key file in PEM format used to sign the JWT so that you can say something like -jwt-key-file=/etc/ssl/private/jwt_signing_key.pem: required by login.gov")
|
||||||
flagSet.String("pubjwk-url", "", "JWK pubkey access endpoint: required by login.gov")
|
flagSet.String("pubjwk-url", "", "JWK pubkey access endpoint: required by login.gov")
|
||||||
flagSet.Bool("gcp-healthchecks", false, "Enable GCP/GKE healthcheck endpoints")
|
flagSet.Bool("gcp-healthchecks", false, "Enable GCP/GKE healthcheck endpoints")
|
||||||
|
|
||||||
|
24
options.go
24
options.go
@ -6,6 +6,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@ -90,6 +91,7 @@ type Options struct {
|
|||||||
SignatureKey string `flag:"signature-key" cfg:"signature_key" env:"OAUTH2_PROXY_SIGNATURE_KEY"`
|
SignatureKey string `flag:"signature-key" cfg:"signature_key" env:"OAUTH2_PROXY_SIGNATURE_KEY"`
|
||||||
AcrValues string `flag:"acr-values" cfg:"acr_values" env:"OAUTH2_PROXY_ACR_VALUES"`
|
AcrValues string `flag:"acr-values" cfg:"acr_values" env:"OAUTH2_PROXY_ACR_VALUES"`
|
||||||
JWTKey string `flag:"jwt-key" cfg:"jwt_key" env:"OAUTH2_PROXY_JWT_KEY"`
|
JWTKey string `flag:"jwt-key" cfg:"jwt_key" env:"OAUTH2_PROXY_JWT_KEY"`
|
||||||
|
JWTKeyFile string `flag:"jwt-key-file" cfg:"jwt_key_file" env:"OAUTH2_PROXY_JWT_KEY_FILE"`
|
||||||
PubJWKURL string `flag:"pubjwk-url" cfg:"pubjwk_url" env:"OAUTH2_PROXY_PUBJWK_URL"`
|
PubJWKURL string `flag:"pubjwk-url" cfg:"pubjwk_url" env:"OAUTH2_PROXY_PUBJWK_URL"`
|
||||||
GCPHealthChecks bool `flag:"gcp-healthchecks" cfg:"gcp_healthchecks" env:"OAUTH2_PROXY_GCP_HEALTHCHECKS"`
|
GCPHealthChecks bool `flag:"gcp-healthchecks" cfg:"gcp_healthchecks" env:"OAUTH2_PROXY_GCP_HEALTHCHECKS"`
|
||||||
|
|
||||||
@ -328,15 +330,33 @@ func parseProviderInfo(o *Options, msgs []string) []string {
|
|||||||
case *providers.LoginGovProvider:
|
case *providers.LoginGovProvider:
|
||||||
p.AcrValues = o.AcrValues
|
p.AcrValues = o.AcrValues
|
||||||
p.PubJWKURL, msgs = parseURL(o.PubJWKURL, "pubjwk", msgs)
|
p.PubJWKURL, msgs = parseURL(o.PubJWKURL, "pubjwk", msgs)
|
||||||
if o.JWTKey == "" {
|
|
||||||
|
// JWT key can be supplied via env variable or file in the filesystem, but not both.
|
||||||
|
switch {
|
||||||
|
case o.JWTKey != "" && o.JWTKeyFile != "":
|
||||||
|
msgs = append(msgs, "cannot set both jwt-key and jwt-key-file options")
|
||||||
|
case o.JWTKey == "" && o.JWTKeyFile == "":
|
||||||
msgs = append(msgs, "login.gov provider requires a private key for signing JWTs")
|
msgs = append(msgs, "login.gov provider requires a private key for signing JWTs")
|
||||||
} else {
|
case o.JWTKey != "":
|
||||||
|
// The JWT Key is in the commandline argument
|
||||||
signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(o.JWTKey))
|
signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(o.JWTKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msgs = append(msgs, "could not parse RSA Private Key PEM")
|
msgs = append(msgs, "could not parse RSA Private Key PEM")
|
||||||
} else {
|
} else {
|
||||||
p.JWTKey = signKey
|
p.JWTKey = signKey
|
||||||
}
|
}
|
||||||
|
case o.JWTKeyFile != "":
|
||||||
|
// The JWT key is in the filesystem
|
||||||
|
keyData, err := ioutil.ReadFile(o.JWTKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
msgs = append(msgs, "could not read key file: "+o.JWTKeyFile)
|
||||||
|
}
|
||||||
|
signKey, err := jwt.ParseRSAPrivateKeyFromPEM(keyData)
|
||||||
|
if err != nil {
|
||||||
|
msgs = append(msgs, "could not parse private key from PEM file:"+o.JWTKeyFile)
|
||||||
|
} else {
|
||||||
|
p.JWTKey = signKey
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return msgs
|
return msgs
|
||||||
|
Loading…
Reference in New Issue
Block a user