added jwt-key-file option, update docs

This commit is contained in:
timothy-spencer 2019-03-20 15:15:47 -07:00
parent ee4ebe53bf
commit 1ae62a3343
No known key found for this signature in database
GPG Key ID: B9DC267D2CB410CD
7 changed files with 62 additions and 10 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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")

View File

@ -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