Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OIDC Auth via OAuth2-proxy #14

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions dev/alive/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
}
},
"Authentication": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"SessionTimeoutMinutes": 480,
"InactivityTimeoutMinutes": 20,
"Logout": {
Expand All @@ -33,14 +33,14 @@
},
"SAML2": {
"Headers": {
"ScopedIdentity": "eppn"
"ScopedIdentity": "X-Auth-Request-Email"
}
}
},
"Authorization": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"AllowAllAuthenticatedUsers": true,
"UnsecuredIsAdmin": true,
"UnsecuredIsAdmin": false,
"SAML2": {
"HeadersMapping": {
"Entitlements": {
Expand All @@ -49,11 +49,11 @@
}
},
"RolesMapping": {
"User": "urn:mace:users",
"Super": "urn:mace:supers",
"Identified": "urn:mace:phi",
"Admin": "urn:mace:sudos",
"Federated": "urn:mace:federated"
"User": "leaf_users",
"Super": "leaf_supers",
"Identified": "leaf_phi",
"Admin": "leaf_admin",
"Federated": "leaf_federated"
}
}
},
Expand Down
21 changes: 11 additions & 10 deletions dev/alive/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,23 @@ services:
LEAF_APP_DB: Server=alive-mssql,1433;Database=LeafDB;uid=sa;Password=${MSSQL_SA_PASSWORD}
LEAF_CLIN_DB: Server=clin-db,3306;Database=alive;uid=db-user;Password=${MYSQL_PASSWORD};Pooling=false
labels:
- traefik.http.routers.alive-coreapi-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`) && PathPrefix(`/api`)
- traefik.http.routers.alive-coreapi-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.alive-coreapi-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt
# https://leafdocs.rit.uw.edu/installation/installation_steps/9_saml2/#route-protection-setup
- traefik.http.routers.alive-coreapi-auth-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`) && Path(`/api/user`)
- traefik.http.routers.alive-coreapi-auth-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME},leaf-groups-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.alive-coreapi-auth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.alive-coreapi-auth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

- traefik.http.routers.alive-coreapi-unauth-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`) && PathPrefix(`/api`) && !Path(`/api/user`)
- traefik.http.routers.alive-coreapi-unauth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.alive-coreapi-unauth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.alive-coreapi-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
node:
labels:
- traefik.enable=true
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`)
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.rule=Host(`alive.${LEAF_DOMAIN}`) && !PathPrefix(`/api`)
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.alive-node-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
volumes:
leaf-alive-mssql:
8 changes: 8 additions & 0 deletions dev/default.env
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,11 @@ HYMTRUTH_JWT_KEY_PW=
MASH_JWT_KEY_PW=
MSTUDY_JWT_KEY_PW=
RADAR_JWT_KEY_PW=

# generate via: python3 -c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'
ivan-c marked this conversation as resolved.
Show resolved Hide resolved
OAUTH2_PROXY_COOKIE_SECRET=

# obtain from Keycloak/OIDC provider
OAUTH2_PROXY_CLIENT_ID=
OAUTH2_PROXY_CLIENT_SECRET=
OAUTH2_PROXY_OIDC_ISSUER_URL=
18 changes: 9 additions & 9 deletions dev/gateway/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
}
},
"Authentication": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"SessionTimeoutMinutes": 480,
"InactivityTimeoutMinutes": 20,
"Logout": {
Expand All @@ -33,14 +33,14 @@
},
"SAML2": {
"Headers": {
"ScopedIdentity": "eppn"
"ScopedIdentity": "X-Auth-Request-Email"
}
}
},
"Authorization": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"AllowAllAuthenticatedUsers": true,
"UnsecuredIsAdmin": true,
"UnsecuredIsAdmin": false,
"SAML2": {
"HeadersMapping": {
"Entitlements": {
Expand All @@ -49,11 +49,11 @@
}
},
"RolesMapping": {
"User": "urn:mace:users",
"Super": "urn:mace:supers",
"Identified": "urn:mace:phi",
"Admin": "urn:mace:sudos",
"Federated": "urn:mace:federated"
"User": "leaf_users",
"Super": "leaf_supers",
"Identified": "leaf_phi",
"Admin": "leaf_admin",
"Federated": "leaf_federated"
}
}
},
Expand Down
78 changes: 68 additions & 10 deletions dev/gateway/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,62 @@
version: "3"
services:
auth-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:v7.3.0
# oauth2-proxy does not EXPOSE (advertise) the ports it listens on in its docker image
expose:
- 4180
environment:
OAUTH2_PROXY_HTTP_ADDRESS: 0.0.0.0:4180
OAUTH2_PROXY_REVERSE_PROXY: "true"

# when authenticated, return a static 202 response
# https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview/#forwardauth-with-static-upstreams-configuration
OAUTH2_PROXY_UPSTREAMS: static://202

# needed to set X-Auth-Request-Email
OAUTH2_PROXY_SET_XAUTHREQUEST: "true"

# general cookie settings
OAUTH2_PROXY_COOKIE_SECRET: ${OAUTH2_PROXY_COOKIE_SECRET}
OAUTH2_PROXY_COOKIE_DOMAINS: .${LEAF_DOMAIN}
OAUTH2_PROXY_WHITELIST_DOMAINS: .${LEAF_DOMAIN}
OAUTH2_PROXY_COOKIE_EXPIRE: 30m
OAUTH2_PROXY_COOKIE_REFRESH: 1m
OAUTH2_PROXY_EMAIL_DOMAINS: "*"
OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL: "true"
# TODO test how leaf handles usernames that are not email addresses
# base session cookie on Keycloak username (email not always set in Keycloak)
OAUTH2_PROXY_USER_ID_CLAIM: preferred_username

# OIDC integration settings
OAUTH2_PROXY_PROVIDER: oidc
OAUTH2_PROXY_SCOPE: openid profile email
OAUTH2_PROXY_OIDC_ISSUER_URL: ${OAUTH2_PROXY_OIDC_ISSUER_URL}
OAUTH2_PROXY_CLIENT_ID: ${OAUTH2_PROXY_CLIENT_ID}
OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_PROXY_CLIENT_SECRET}
labels:
- traefik.enable=true
# TODO fix HostRegexp syntax, after upgrading to traefik v3
- traefik.http.routers.auth-proxy-${COMPOSE_PROJECT_NAME}.rule=Host(`auth-proxy.${LEAF_DOMAIN}`) || (PathPrefix(`/oauth2`) && (Host(`${LEAF_DOMAIN}`) || HostRegexp(`{subdomain:.+}.${LEAF_DOMAIN}`)))

- traefik.http.routers.auth-proxy-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.auth-proxy-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# https://oauth2-proxy.github.io/oauth2-proxy/configuration/integration/#forwardauth-with-static-upstreams-configuration
- traefik.http.middlewares.oidc-auth-${COMPOSE_PROJECT_NAME}.forwardAuth.address=http://auth-proxy-${COMPOSE_PROJECT_NAME}:4180/
- traefik.http.middlewares.oidc-auth-${COMPOSE_PROJECT_NAME}.forwardAuth.trustForwardHeader=true
- traefik.http.middlewares.oidc-auth-${COMPOSE_PROJECT_NAME}.forwardAuth.authResponseHeaders=X-Auth-Request-User,X-Auth-Request-Email,X-Auth-Request-Access-Token,Authorization

# TODO dynamically look up from OIDC tokens
# add Leaf group to all users via HTTP request header; see appsettings.json for available roles
- traefik.http.middlewares.leaf-groups-${COMPOSE_PROJECT_NAME}.headers.customrequestheaders.gws-groups=leaf_users;leaf_phi;leaf_admin

networks:
ingress:
aliases:
- auth-proxy-${COMPOSE_PROJECT_NAME}
internal:

gateway-mssql:
extends:
file: ../common-services.yaml
Expand All @@ -19,26 +76,27 @@ services:
LEAF_APP_DB: Server=gateway-mssql,1433;Database=LeafDB;uid=sa;Password=${MSSQL_SA_PASSWORD}
LEAF_CLIN_DB: Server=clin-db,3306;Database=gateway;uid=db-user;Password=${MYSQL_PASSWORD};Pooling=false
labels:
- traefik.http.routers.gateway-coreapi-${COMPOSE_PROJECT_NAME}.rule=Host(`${LEAF_DOMAIN}`) && PathPrefix(`/api`)
- traefik.http.routers.gateway-coreapi-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.gateway-coreapi-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt
# https://leafdocs.rit.uw.edu/installation/installation_steps/9_saml2/#route-protection-setup
- traefik.http.routers.gateway-coreapi-auth-${COMPOSE_PROJECT_NAME}.rule=Host(`${LEAF_DOMAIN}`) && Path(`/api/user`)
- traefik.http.routers.gateway-coreapi-auth-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME},leaf-groups-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.gateway-coreapi-auth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.gateway-coreapi-auth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

- traefik.http.routers.gateway-coreapi-unauth-${COMPOSE_PROJECT_NAME}.rule=Host(`${LEAF_DOMAIN}`) && PathPrefix(`/api`) && !Path(`/api/user`)
- traefik.http.routers.gateway-coreapi-unauth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.gateway-coreapi-unauth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.gateway-coreapi-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
node:
extends:
file: ../common-services.yaml
service: node
labels:
- traefik.enable=true
- traefik.http.routers.gateway-node-${COMPOSE_PROJECT_NAME}.rule=Host(`${LEAF_DOMAIN}`)
- traefik.http.routers.gateway-node-${COMPOSE_PROJECT_NAME}.rule=Host(`${LEAF_DOMAIN}`) && !PathPrefix(`/api`)
- traefik.http.routers.gateway-node-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.gateway-node-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.gateway-node-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.gateway-node-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
clin-db:
extends:
file: ../common-services.yaml
Expand Down
18 changes: 9 additions & 9 deletions dev/hymtruth/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
}
},
"Authentication": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"SessionTimeoutMinutes": 480,
"InactivityTimeoutMinutes": 20,
"Logout": {
Expand All @@ -33,14 +33,14 @@
},
"SAML2": {
"Headers": {
"ScopedIdentity": "eppn"
"ScopedIdentity": "X-Auth-Request-Email"
}
}
},
"Authorization": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"AllowAllAuthenticatedUsers": true,
"UnsecuredIsAdmin": true,
"UnsecuredIsAdmin": false,
"SAML2": {
"HeadersMapping": {
"Entitlements": {
Expand All @@ -49,11 +49,11 @@
}
},
"RolesMapping": {
"User": "urn:mace:users",
"Super": "urn:mace:supers",
"Identified": "urn:mace:phi",
"Admin": "urn:mace:sudos",
"Federated": "urn:mace:federated"
"User": "leaf_users",
"Super": "leaf_supers",
"Identified": "leaf_phi",
"Admin": "leaf_admin",
"Federated": "leaf_federated"
}
}
},
Expand Down
21 changes: 11 additions & 10 deletions dev/hymtruth/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,23 @@ services:
LEAF_APP_DB: Server=hymtruth-mssql,1433;Database=LeafDB;uid=sa;Password=${MSSQL_SA_PASSWORD}
LEAF_CLIN_DB: Server=clin-db,3306;Database=hymtruth;uid=db-user;Password=${MYSQL_PASSWORD};Pooling=false
labels:
- traefik.http.routers.hymtruth-coreapi-${COMPOSE_PROJECT_NAME}.rule=Host(`hymtruth.${LEAF_DOMAIN}`) && PathPrefix(`/api`)
- traefik.http.routers.hymtruth-coreapi-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.hymtruth-coreapi-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt
# https://leafdocs.rit.uw.edu/installation/installation_steps/9_saml2/#route-protection-setup
- traefik.http.routers.hymtruth-coreapi-auth-${COMPOSE_PROJECT_NAME}.rule=Host(`hymtruth.${LEAF_DOMAIN}`) && Path(`/api/user`)
- traefik.http.routers.hymtruth-coreapi-auth-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME},leaf-groups-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.hymtruth-coreapi-auth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.hymtruth-coreapi-auth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

- traefik.http.routers.hymtruth-coreapi-unauth-${COMPOSE_PROJECT_NAME}.rule=Host(`hymtruth.${LEAF_DOMAIN}`) && PathPrefix(`/api`) && !Path(`/api/user`)
- traefik.http.routers.hymtruth-coreapi-unauth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.hymtruth-coreapi-unauth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.hymtruth-coreapi-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
node:
labels:
- traefik.enable=true
- traefik.http.routers.hymtruth-node-${COMPOSE_PROJECT_NAME}.rule=Host(`hymtruth.${LEAF_DOMAIN}`)
- traefik.http.routers.hymtruth-node-${COMPOSE_PROJECT_NAME}.rule=Host(`hymtruth.${LEAF_DOMAIN}`) && !PathPrefix(`/api`)
- traefik.http.routers.hymtruth-node-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.hymtruth-node-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.hymtruth-node-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.hymtruth-node-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
volumes:
leaf-hymtruth-mssql:
18 changes: 9 additions & 9 deletions dev/mash/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
}
},
"Authentication": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"SessionTimeoutMinutes": 480,
"InactivityTimeoutMinutes": 20,
"Logout": {
Expand All @@ -33,14 +33,14 @@
},
"SAML2": {
"Headers": {
"ScopedIdentity": "eppn"
"ScopedIdentity": "X-Auth-Request-Email"
}
}
},
"Authorization": {
"Mechanism": "UNSECURED",
"Mechanism": "SAML2",
"AllowAllAuthenticatedUsers": true,
"UnsecuredIsAdmin": true,
"UnsecuredIsAdmin": false,
"SAML2": {
"HeadersMapping": {
"Entitlements": {
Expand All @@ -49,11 +49,11 @@
}
},
"RolesMapping": {
"User": "urn:mace:users",
"Super": "urn:mace:supers",
"Identified": "urn:mace:phi",
"Admin": "urn:mace:sudos",
"Federated": "urn:mace:federated"
"User": "leaf_users",
"Super": "leaf_supers",
"Identified": "leaf_phi",
"Admin": "leaf_admin",
"Federated": "leaf_federated"
}
}
},
Expand Down
21 changes: 11 additions & 10 deletions dev/mash/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,23 @@ services:
LEAF_APP_DB: Server=mash-mssql,1433;Database=LeafDB;uid=sa;Password=${MSSQL_SA_PASSWORD}
LEAF_CLIN_DB: Server=clin-db,3306;Database=mash;uid=db-user;Password=${MYSQL_PASSWORD};Pooling=false
labels:
- traefik.http.routers.mash-coreapi-${COMPOSE_PROJECT_NAME}.rule=Host(`mash.${LEAF_DOMAIN}`) && PathPrefix(`/api`)
- traefik.http.routers.mash-coreapi-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.mash-coreapi-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt
# https://leafdocs.rit.uw.edu/installation/installation_steps/9_saml2/#route-protection-setup
- traefik.http.routers.mash-coreapi-auth-${COMPOSE_PROJECT_NAME}.rule=Host(`mash.${LEAF_DOMAIN}`) && Path(`/api/user`)
- traefik.http.routers.mash-coreapi-auth-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME},leaf-groups-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.mash-coreapi-auth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.mash-coreapi-auth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

- traefik.http.routers.mash-coreapi-unauth-${COMPOSE_PROJECT_NAME}.rule=Host(`mash.${LEAF_DOMAIN}`) && PathPrefix(`/api`) && !Path(`/api/user`)
- traefik.http.routers.mash-coreapi-unauth-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.mash-coreapi-unauth-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.mash-coreapi-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
node:
labels:
- traefik.enable=true
- traefik.http.routers.mash-node-${COMPOSE_PROJECT_NAME}.rule=Host(`mash.${LEAF_DOMAIN}`)
- traefik.http.routers.mash-node-${COMPOSE_PROJECT_NAME}.rule=Host(`mash.${LEAF_DOMAIN}`) && !PathPrefix(`/api`)
- traefik.http.routers.mash-node-${COMPOSE_PROJECT_NAME}.middlewares=oidc-auth-${COMPOSE_PROJECT_NAME}
- traefik.http.routers.mash-node-${COMPOSE_PROJECT_NAME}.entrypoints=websecure
- traefik.http.routers.mash-node-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt

# TODO remove after auth implemented via oauth2-proxy
# only allow access from localhost and CIRG IP ranges
- traefik.http.routers.mash-node-${COMPOSE_PROJECT_NAME}.middlewares=limit-access-to-cirg-dc-cidr
volumes:
leaf-mash-mssql:
Loading