MatthewJohn / terrareg

Open source Terraform module registry with UI, optional Git integration and deep analysis
https://gitlab.dockstudios.co.uk/pub/terrareg
GNU General Public License v3.0
268 stars 20 forks source link

OIDC Login error: (insecure_transport) OAuth 2 MUST utilize https. #31

Closed whoracle closed 7 months ago

whoracle commented 8 months ago

So, I built myself a terrareg container today from current HEAD on main branch.

It's deploy with the following ENV vars via docker compose:

version: '3'

networks:
  gitea:
    external: false

services:
  terrareg:
    image: git.home.lynxcore.org/homelab/terrareg/terrareg:latest
    container_name: "terrareg"
    restart: unless-stopped
   environment:
      - MIGRATE_DATABASE=True
      - SECRET_KEY=YEAHNO
      - PUBLIC_URL=https://terraform.home.lynxcore.org
      - DOMAIN_NAME=https://terraform.home.lynxcore.org
      - OPENID_CONNECT_CLIENT_ID=STILLNO
      - OPENID_CONNECT_CLIENT_SECRET=NICETRY
      - OPENID_CONNECT_ISSUER=https://auth.home.lynxcore.org/application/o/terrareg/
      - OPENID_CONNECT_SCOPES=openid,profile,email,groups
      - AUTO_CREATE_NAMESPACE=False
      - AUTO_CREATE_MODULE_PROVIDER=False
      - UPLOAD_API_KEYS=ASIF
      - PUBLISH_API_KEYS=INYOURDREAMS
    ports:
      - "127.0.0.1:5000:5000"
    volumes:
      - /srv/docker/code/terrareg:/app/data
    networks:
      - gitea
    healthcheck:
      test: curl --fail http://localhost:5000 || exit 1
      interval: 5s
      retries: 30
      start_period: 30s
      timeout: 10s

When trying to log in, my IdP (authentik) authenticates me just fine, but I get an Invalid response from SSO error.

Now, after digging into this for a few hours with DEBUG=true etc, I managed to coax an error message by changing Line 39 (error_description) in terrareg/server/api/open_id_callback.py to

            res = make_response(
                render_template(
                    "error.html",
                    error_title="Login error",
                    error_description=f"""Invalid response from SSO for url {request.url} | {exc}""",   # this is what I changed
                )
            )

With that I get the following error: Invalid response from SSO for url http://terraform.home.lynxcore.org/openid/callback?code=REDACTED&state=REDACTED | (insecure_transport) OAuth 2 MUST utilize https..

I then proceeded to see where the hell the "http" comes from - no dice. I just can't find it. I verified that everything works IdP-Wise by setting OAUTHLIB_INSECURE_TRANSPORT=1 in my docker-compose.yml, and I can log in just fine.

Something in the depths of the OIDC implementation here overwrites the protocol to http, and I can 't find it.

Setup-wise I have HAProxy before terrareg, and HAProxy terminates SSL for me.

Complete HAProxy config if it's relevant:

global
  chroot  /usr/share/haproxy
  daemon  
  group  haproxy
  log  127.0.0.1 local0
  ssl-default-bind-ciphers  ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
  ssl-default-bind-options  no-sslv3 no-tls-tickets
  ssl-default-server-ciphers  ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
  ssl-default-server-options  no-sslv3 no-tls-tickets
  stats  timeout 30s
  tune.ssl.default-dh-param  2048
  user  haproxy

defaults
  log  global
  maxconn  2000
  mode  http
  option  http-server-close
  option  httplog
  option  dontlognull
  option  redispatch
  option  srvtcpka
  option  clitcpka
  retries  3
  timeout  http-request 10s
  timeout  client 20s
  timeout  connect 4s
  timeout  server 2m
  timeout  http-keep-alive 4s
  timeout  tunnel 2m
  timeout  client-fin 1s
  timeout  server-fin 1s
  timeout  check 10s
  timeout  queue 1m

frontend main
  bind :443 ssl crt /etc/haproxy/ssl
  bind :80 
  mode http
  acl terraform        hdr(host)  -i terraform.home.lynxcore.org
  default_backend terraform
  http-request set-header X-Forwarded-Proto https if  { ssl_fc }
  http-request set-header X-Forwarded-Proto http if  !{ ssl_fc }
  http-request redirect scheme https code 301 unless { ssl_fc }
  log-format %ci\ "%r"\ %ST\ %B\ "%hr"
  option forwardfor except 127.0.0.1/8
  option httplog
  option dontlognull
  use_backend terraform        if terraform

listen stats
  bind 127.0.0.1:9001 
  stats enable
  stats show-legends
  stats uri /
  stats realm haproxy\ statistics
  stats admin if TRUE

backend terraform
  balance roundrobin
  mode http
  server terraform 127.0.0.1:5000 check

I'm at my wits end. Any takers?

MatthewJohn commented 8 months ago

Hey @whoracle ,

Just to double check before delving into this - could you very the URL of Terrareg that is configured in authentik (does it contain a static redirect URL?) (does that definitely contain the https URL)?

Could you also monitor requests to authentik during the authentication flow (or any proxy in front of it to see which protocol the requests are coming from)?

As a side note, although it shouldn't be necessary, the DOMAIN_NAME config is deprecated and the PUBLIC_URL should take priority (in terms of the code base), but just in case, the DOMAIN_NAME should be just the domain (i.e. terraform.home.lynxcore.org) - shouldn't make a difference but might be worth either correcting this, or maybe better, removing DOMAIN_NAME config altogether :)

Maybe one other thing, if you could check, if you look at the meta-data from authentik (https://auth.home.lynxcore.org/application/o/terrareg/.well-known/openid-configuration) and check the URLs that it's returning?

In terms of the Oauth 2 redirect URL, Terrareg (rightly or wrongly) always uses https (openid_connect.py#L35) - which is why I'm possibly suspecting that the callback URL that doesn't contain http might be being set in authentik somewhere

Many thanks Matt

whoracle commented 8 months ago

Hey @MatthewJohn

I just double checked - in authentik in an OAuth Provider I can't set static redirect URLs. The configured redirect_uris in authentik are these:

https://terraform.home.lynxcore.org/openid/callback
https://terraform.home.lynxcore.org/logout
https://terraform.home.lynxcore.org/openid/login

Output of authentiks well-known endpoint looks like this:

{
  "issuer": "https://auth.home.lynxcore.org/application/o/terrareg/",
  "authorization_endpoint": "https://auth.home.lynxcore.org/application/o/authorize/",
  "token_endpoint": "https://auth.home.lynxcore.org/application/o/token/",
  "userinfo_endpoint": "https://auth.home.lynxcore.org/application/o/userinfo/",
  "end_session_endpoint": "https://auth.home.lynxcore.org/application/o/terrareg/end-session/",
  "introspection_endpoint": "https://auth.home.lynxcore.org/application/o/introspect/",
  "revocation_endpoint": "https://auth.home.lynxcore.org/application/o/revoke/",
  "device_authorization_endpoint": "https://auth.home.lynxcore.org/application/o/device/",
  "response_types_supported": [
    "code",
    "id_token",
    "id_token token",
    "code token",
    "code id_token",
    "code id_token token"
  ],
  "response_modes_supported": [
    "query",
    "fragment",
    "form_post"
  ],
  "jwks_uri": "https://auth.home.lynxcore.org/application/o/terrareg/jwks/",
  "grant_types_supported": [
    "authorization_code",
    "refresh_token",
    "implicit",
    "client_credentials",
    "password",
    "urn:ietf:params:oauth:grant-type:device_code"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "subject_types_supported": [
    "public"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "acr_values_supported": [
    "goauthentik.io/providers/oauth2/default"
  ],
  "scopes_supported": [
    "openid",
    "email",
    "profile"
  ],
  "request_parameter_supported": false,
  "claims_supported": [
    "sub",
    "iss",
    "aud",
    "exp",
    "iat",
    "auth_time",
    "acr",
    "amr",
    "nonce",
    "email",
    "email_verified",
    "name",
    "given_name",
    "preferred_username",
    "nickname",
    "groups"
  ],
  "claims_parameter_supported": false,
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ]
}

As for DOMAIN_NAME: I tried without the parameter in the beginning, of course. That's just a leftover of my debugging. I just tried once more with omitting the protocol from it, and observed no changes, so I dropped the parameter completely.

I'll try to have a look at what gets sent to authentik later in the day, but since authentik (correctly) just blocks applications that submit an incorrect redirect_uri (including protocol), I doubt it's there. But it's the one place I did not check yet, so I'll do that.

My one (unfounded) suspicion is that since terrareg itself is not running in SSL mode, it somehow assumes http in some edge case, and it somehow does not know that it's behind an SSL terminating proxy, but as I said - that's unfounded, just a gut feeling.

whoracle commented 8 months ago

OK, here's what I got from the authentik logs:

{"auth_via": "session", "event": "/application/o/authorize/?response_type=code&client_id=VbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T&redirect_uri=https%3A%2F%2Fterraform.home.lynxcore.org%2Fopenid%2Fcallback&scope=openid+profile+email+groups&state=4EhzQHDsxdrF5Vfum6t8YoFC", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 413943, "remote": "10.0.0.10", "request_id": "121bafdd713848a39b51df085ec378bf", "runtime": 31, "scheme": "https", "status": 302, "timestamp": "2024-01-17T07:58:07.303861", "user": "some_user", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"}
{"auth_via": "session", "event": "/if/flow/default-provider-authorization-implicit-consent/?response_type=code&client_id=VbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T&redirect_uri=https%3A%2F%2Fterraform.home.lynxcore.org%2Fopenid%2Fcallback&scope=openid+profile+email+groups&state=4EhzQHDsxdrF5Vfum6t8YoFC", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 413943, "remote": "10.0.0.10", "request_id": "0f22b3672ea842189d9f1003b764bf0d", "runtime": 14, "scheme": "https", "status": 200, "timestamp": "2024-01-17T07:58:07.322207", "user": "some_user", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"}
{"event": "/ws/client/", "level": "info", "logger": "authentik.asgi", "pid": 413943, "remote": "10.0.0.10", "scheme": "ws", "timestamp": "2024-01-17T07:58:07.367981", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"}
{"action": "authorize_application", "auth_via": "session", "client_ip": "10.0.0.10", "context": {"authorized_application": {"app": "authentik_core", "model_name": "application", "name": "Terrareg", "pk": "e69da1e2c8cc4544b0e71185e923de02"}, "flow": "7c83d832266948b9b345222751974d19", "http_request": {"args": {"client_id": "VbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T", "redirect_uri": "https://terraform.home.lynxcore.org/openid/callback", "response_type": "code", "scope": "openid profile email groups", "state": "4EhzQHDsxdrF5Vfum6t8YoFC"}, "method": "GET", "path": "/api/v3/flows/executor/default-provider-authorization-implicit-consent/"}, "scopes": "openid profile email groups"}, "event": "Created Event", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.events.models", "pid": 413943, "request_id": "43825336a1e44fc9822f614552958f21", "timestamp": "2024-01-17T07:58:07.386052", "user": {"email": "some_user@lynxcore.org", "pk": 5, "username": "some_user"}}
{"auth_via": "session", "event": "Task published", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.root.celery", "pid": 413943, "request_id": "43825336a1e44fc9822f614552958f21", "task_id": "f02eee1b1aa9438ca75383e6669e0612", "task_name": "authentik.events.tasks.event_notification_handler", "timestamp": "2024-01-17T07:58:07.454615"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "f02eee1b-1aa9-438c-a753-83e6669e0612", "task_name": "event_notification_handler", "timestamp": "2024-01-17T07:58:07.456137"}
{"event": "Task published", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "32e8ed62dc70468eabb611fe7bbc216d", "task_name": "authentik.events.tasks.event_trigger_handler", "timestamp": "2024-01-17T07:58:07.466100"}
{"event": "Task published", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "03fee4031ad94108aa099054185e2501", "task_name": "authentik.events.tasks.event_trigger_handler", "timestamp": "2024-01-17T07:58:07.467268"}
{"event": "Task published", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "d65f187e57644e9897eebb2015fffd80", "task_name": "authentik.events.tasks.event_trigger_handler", "timestamp": "2024-01-17T07:58:07.468248"}
{"auth_via": "session", "event": "/api/v3/flows/executor/default-provider-authorization-implicit-consent/?query=response_type%3Dcode%26client_id%3DVbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T%26redirect_uri%3Dhttps%253A%252F%252Fterraform.home.lynxcore.org%252Fopenid%252Fcallback%26scope%3Dopenid%2Bprofile%2Bemail%2Bgroups%26state%3D4EhzQHDsxdrF5Vfum6t8YoFC", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 413943, "remote": "10.0.0.10", "request_id": "43825336a1e44fc9822f614552958f21", "runtime": 97, "scheme": "https", "status": 200, "timestamp": "2024-01-17T07:58:07.469557", "user": "some_user", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "f02eee1b1aa9438ca75383e6669e0612", "task_name": "event_notification_handler", "timestamp": "2024-01-17T07:58:07.469191"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "32e8ed62-dc70-468e-abb6-11fe7bbc216d", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.643786"}
{"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-32e8ed62dc70468eabb611fe7bbc216d", "timestamp": "2024-01-17T07:58:07.679136"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "32e8ed62dc70468eabb611fe7bbc216d", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.681191"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "03fee403-1ad9-4108-aa09-9054185e2501", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.683138"}
{"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-03fee4031ad94108aa099054185e2501", "timestamp": "2024-01-17T07:58:07.697115"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "03fee4031ad94108aa099054185e2501", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.699084"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "d65f187e-5764-4e98-97ee-bb2015fffd80", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.701962"}
{"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-d65f187e57644e9897eebb2015fffd80", "timestamp": "2024-01-17T07:58:07.722704"}
{"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-d65f187e57644e9897eebb2015fffd80", "timestamp": "2024-01-17T07:58:07.725301"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "d65f187e57644e9897eebb2015fffd80", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.726802"}

Timestamps omitted for readability. And no, I'm not concerned if I'mleaking secrets in there right now, I'll be redeploying everything once this is figured out anyways. As far as I can see, authentik only gets requests for HTTPS.

MatthewJohn commented 8 months ago

Hey, thank you for investigating - I’m saddened that the metadata didn’t surface an issue 😄 I do fear that your suspicion about it running in non-ssl mode may have something to do with it (though I do feel that I recall something like this, I could have sworn it was only a temporary thing) and, the actual openid library is completely independent of flask. Im afraid I don’t have access to a laptop right now, but might have a time in around 18 hours to take a look. Sorry about all of these issues. One thing I’m interested in, is this an error being returned in the state from the IdP (is authentik unhappy about something or is it coming from the library in terrareg (though you changing the environment variable certainly basically states this being the case))

I’ll have a think in the meantime and try to catch-up (my) tomorrow morning :)

Apologies again

Many thanks Matt

Sent from my iPhone

On 17 Jan 2024, at 15:01, Michael Gerber @.***> wrote:

 OK, here's what I got from the authentik logs:

{"auth_via": "session", "event": "/application/o/authorize/?response_type=code&client_id=VbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T&redirect_uri=https%3A%2F%2Fterraform.home.lynxcore.org%2Fopenid%2Fcallback&scope=openid+profile+email+groups&state=4EhzQHDsxdrF5Vfum6t8YoFC", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 413943, "remote": "10.0.0.10", "request_id": "121bafdd713848a39b51df085ec378bf", "runtime": 31, "scheme": "https", "status": 302, "timestamp": "2024-01-17T07:58:07.303861", "user": "some_user", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"} {"auth_via": "session", "event": "/if/flow/default-provider-authorization-implicit-consent/?response_type=code&client_id=VbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T&redirect_uri=https%3A%2F%2Fterraform.home.lynxcore.org%2Fopenid%2Fcallback&scope=openid+profile+email+groups&state=4EhzQHDsxdrF5Vfum6t8YoFC", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 413943, "remote": "10.0.0.10", "request_id": "0f22b3672ea842189d9f1003b764bf0d", "runtime": 14, "scheme": "https", "status": 200, "timestamp": "2024-01-17T07:58:07.322207", "user": "some_user", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"} {"event": "/ws/client/", "level": "info", "logger": "authentik.asgi", "pid": 413943, "remote": "10.0.0.10", "scheme": "ws", "timestamp": "2024-01-17T07:58:07.367981", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"} {"action": "authorize_application", "auth_via": "session", "client_ip": "10.0.0.10", "context": {"authorized_application": {"app": "authentik_core", "model_name": "application", "name": "Terrareg", "pk": "e69da1e2c8cc4544b0e71185e923de02"}, "flow": "7c83d832266948b9b345222751974d19", "http_request": {"args": {"client_id": "VbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T", "redirect_uri": "https://terraform.home.lynxcore.org/openid/callback", "response_type": "code", "scope": "openid profile email groups", "state": "4EhzQHDsxdrF5Vfum6t8YoFC"}, "method": "GET", "path": "/api/v3/flows/executor/default-provider-authorization-implicit-consent/"}, "scopes": "openid profile email groups"}, "event": "Created Event", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.events.models", "pid": 413943, "request_id": "43825336a1e44fc9822f614552958f21", "timestamp": "2024-01-17T07:58:07.386052", "user": {"email": @.***", "pk": 5, "username": "some_user"}} {"auth_via": "session", "event": "Task published", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.root.celery", "pid": 413943, "request_id": "43825336a1e44fc9822f614552958f21", "task_id": "f02eee1b1aa9438ca75383e6669e0612", "task_name": "authentik.events.tasks.event_notification_handler", "timestamp": "2024-01-17T07:58:07.454615"} {"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "f02eee1b-1aa9-438c-a753-83e6669e0612", "task_name": "event_notification_handler", "timestamp": "2024-01-17T07:58:07.456137"} {"event": "Task published", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "32e8ed62dc70468eabb611fe7bbc216d", "task_name": "authentik.events.tasks.event_trigger_handler", "timestamp": "2024-01-17T07:58:07.466100"} {"event": "Task published", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "03fee4031ad94108aa099054185e2501", "task_name": "authentik.events.tasks.event_trigger_handler", "timestamp": "2024-01-17T07:58:07.467268"} {"event": "Task published", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "d65f187e57644e9897eebb2015fffd80", "task_name": "authentik.events.tasks.event_trigger_handler", "timestamp": "2024-01-17T07:58:07.468248"} {"auth_via": "session", "event": "/api/v3/flows/executor/default-provider-authorization-implicit-consent/?query=response_type%3Dcode%26client_id%3DVbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T%26redirect_uri%3Dhttps%253A%252F%252Fterraform.home.lynxcore.org%252Fopenid%252Fcallback%26scope%3Dopenid%2Bprofile%2Bemail%2Bgroups%26state%3D4EhzQHDsxdrF5Vfum6t8YoFC", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 413943, "remote": "10.0.0.10", "request_id": "43825336a1e44fc9822f614552958f21", "runtime": 97, "scheme": "https", "status": 200, "timestamp": "2024-01-17T07:58:07.469557", "user": "some_user", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"} {"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "f02eee1b1aa9438ca75383e6669e0612", "task_name": "event_notification_handler", "timestamp": "2024-01-17T07:58:07.469191"} {"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "32e8ed62-dc70-468e-abb6-11fe7bbc216d", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.643786"} {"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-32e8ed62dc70468eabb611fe7bbc216d", "timestamp": "2024-01-17T07:58:07.679136"} {"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "32e8ed62dc70468eabb611fe7bbc216d", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.681191"} {"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "03fee403-1ad9-4108-aa09-9054185e2501", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.683138"} {"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-03fee4031ad94108aa099054185e2501", "timestamp": "2024-01-17T07:58:07.697115"} {"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "03fee4031ad94108aa099054185e2501", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.699084"} {"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "d65f187e-5764-4e98-97ee-bb2015fffd80", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.701962"} {"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-d65f187e57644e9897eebb2015fffd80", "timestamp": "2024-01-17T07:58:07.722704"} {"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-d65f187e57644e9897eebb2015fffd80", "timestamp": "2024-01-17T07:58:07.725301"} {"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "d65f187e57644e9897eebb2015fffd80", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.726802"} Timestamps omitted for readability. And no, I'm not concerned if I'mleaking secrets in there right now, I'll be redeploying everything once this is figured out anyways. As far as I can see, authentik only gets requests for HTTPS.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.

MatthewJohn commented 8 months ago

Ahh, of course, it’s the request.url in the openid_callback endpoint class.. maybe it needs manipulating, placing the path and args interpolated onto the PUBLIC_URL config before passing to fetch_access_token. I will give this a try and let you know

Many thanks Matt

Sent from my iPhone

On 17 Jan 2024, at 15:01, Michael Gerber @.***> wrote:

 OK, here's what I got from the authentik logs:

{"auth_via": "session", "event": "/application/o/authorize/?response_type=code&client_id=VbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T&redirect_uri=https%3A%2F%2Fterraform.home.lynxcore.org%2Fopenid%2Fcallback&scope=openid+profile+email+groups&state=4EhzQHDsxdrF5Vfum6t8YoFC", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 413943, "remote": "10.0.0.10", "request_id": "121bafdd713848a39b51df085ec378bf", "runtime": 31, "scheme": "https", "status": 302, "timestamp": "2024-01-17T07:58:07.303861", "user": "some_user", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"} {"auth_via": "session", "event": "/if/flow/default-provider-authorization-implicit-consent/?response_type=code&client_id=VbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T&redirect_uri=https%3A%2F%2Fterraform.home.lynxcore.org%2Fopenid%2Fcallback&scope=openid+profile+email+groups&state=4EhzQHDsxdrF5Vfum6t8YoFC", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 413943, "remote": "10.0.0.10", "request_id": "0f22b3672ea842189d9f1003b764bf0d", "runtime": 14, "scheme": "https", "status": 200, "timestamp": "2024-01-17T07:58:07.322207", "user": "some_user", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"} {"event": "/ws/client/", "level": "info", "logger": "authentik.asgi", "pid": 413943, "remote": "10.0.0.10", "scheme": "ws", "timestamp": "2024-01-17T07:58:07.367981", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"} {"action": "authorize_application", "auth_via": "session", "client_ip": "10.0.0.10", "context": {"authorized_application": {"app": "authentik_core", "model_name": "application", "name": "Terrareg", "pk": "e69da1e2c8cc4544b0e71185e923de02"}, "flow": "7c83d832266948b9b345222751974d19", "http_request": {"args": {"client_id": "VbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T", "redirect_uri": "https://terraform.home.lynxcore.org/openid/callback", "response_type": "code", "scope": "openid profile email groups", "state": "4EhzQHDsxdrF5Vfum6t8YoFC"}, "method": "GET", "path": "/api/v3/flows/executor/default-provider-authorization-implicit-consent/"}, "scopes": "openid profile email groups"}, "event": "Created Event", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.events.models", "pid": 413943, "request_id": "43825336a1e44fc9822f614552958f21", "timestamp": "2024-01-17T07:58:07.386052", "user": {"email": @.***", "pk": 5, "username": "some_user"}} {"auth_via": "session", "event": "Task published", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.root.celery", "pid": 413943, "request_id": "43825336a1e44fc9822f614552958f21", "task_id": "f02eee1b1aa9438ca75383e6669e0612", "task_name": "authentik.events.tasks.event_notification_handler", "timestamp": "2024-01-17T07:58:07.454615"} {"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "f02eee1b-1aa9-438c-a753-83e6669e0612", "task_name": "event_notification_handler", "timestamp": "2024-01-17T07:58:07.456137"} {"event": "Task published", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "32e8ed62dc70468eabb611fe7bbc216d", "task_name": "authentik.events.tasks.event_trigger_handler", "timestamp": "2024-01-17T07:58:07.466100"} {"event": "Task published", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "03fee4031ad94108aa099054185e2501", "task_name": "authentik.events.tasks.event_trigger_handler", "timestamp": "2024-01-17T07:58:07.467268"} {"event": "Task published", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "d65f187e57644e9897eebb2015fffd80", "task_name": "authentik.events.tasks.event_trigger_handler", "timestamp": "2024-01-17T07:58:07.468248"} {"auth_via": "session", "event": "/api/v3/flows/executor/default-provider-authorization-implicit-consent/?query=response_type%3Dcode%26client_id%3DVbATUSx9dF8RYBzsdgkkl2S6R4fYA6MqBYBXwC5T%26redirect_uri%3Dhttps%253A%252F%252Fterraform.home.lynxcore.org%252Fopenid%252Fcallback%26scope%3Dopenid%2Bprofile%2Bemail%2Bgroups%26state%3D4EhzQHDsxdrF5Vfum6t8YoFC", "host": "auth.home.lynxcore.org", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 413943, "remote": "10.0.0.10", "request_id": "43825336a1e44fc9822f614552958f21", "runtime": 97, "scheme": "https", "status": 200, "timestamp": "2024-01-17T07:58:07.469557", "user": "some_user", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"} {"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "f02eee1b1aa9438ca75383e6669e0612", "task_name": "event_notification_handler", "timestamp": "2024-01-17T07:58:07.469191"} {"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "32e8ed62-dc70-468e-abb6-11fe7bbc216d", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.643786"} {"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-32e8ed62dc70468eabb611fe7bbc216d", "timestamp": "2024-01-17T07:58:07.679136"} {"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "32e8ed62dc70468eabb611fe7bbc216d", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.681191"} {"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "03fee403-1ad9-4108-aa09-9054185e2501", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.683138"} {"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-03fee4031ad94108aa099054185e2501", "timestamp": "2024-01-17T07:58:07.697115"} {"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "03fee4031ad94108aa099054185e2501", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.699084"} {"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "task_id": "d65f187e-5764-4e98-97ee-bb2015fffd80", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.701962"} {"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-d65f187e57644e9897eebb2015fffd80", "timestamp": "2024-01-17T07:58:07.722704"} {"checker": "passes_action", "event": "Event matcher check result", "level": "info", "logger": "authentik.policies.event_matcher.models", "pid": 328852, "result": "<PolicyResult passing=False messages=('Action matched.',)>", "task_id": "task-d65f187e57644e9897eebb2015fffd80", "timestamp": "2024-01-17T07:58:07.725301"} {"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 328852, "state": "SUCCESS", "task_id": "d65f187e57644e9897eebb2015fffd80", "task_name": "event_trigger_handler", "timestamp": "2024-01-17T07:58:07.726802"} Timestamps omitted for readability. And no, I'm not concerned if I'mleaking secrets in there right now, I'll be redeploying everything once this is figured out anyways. As far as I can see, authentik only gets requests for HTTPS.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.

whoracle commented 8 months ago

Take your time - for me this is not a breaker, since my use case for terrareg has sadly gone away, I just created the Issue to help maybe fix a bug or a documentation issue or whatever it's going to be in the end for others :)

Unrelated: Kudos for making the only private registry that is

If I actually went ahead with replacing GitLab for my needs, I'd totally run terrareg regularly, and maybe I'll even run this as a mirror for my (now not to be replaced due to too many other dependencies) GitLab instance :)

MatthewJohn commented 7 months ago

Hey @whoracle,

hopefully this patch will solve the issue - if you'd be able to give it a little try at some point (at least to prove the theory that this is the cause of the problem :D)

diff --git a/terrareg/server/api/open_id_callback.py b/terrareg/server/api/open_id_callback.py
index abf9474a..24570275 100644
--- a/terrareg/server/api/open_id_callback.py
+++ b/terrareg/server/api/open_id_callback.py
@@ -1,5 +1,6 @@

 import datetime
+import urllib.parse

 from flask import request, make_response, render_template, session, redirect

@@ -10,6 +11,7 @@ import terrareg.models
 import terrareg.audit
 import terrareg.audit_action
 import terrareg.auth
+import terrareg.utils

 class ApiOpenIdCallback(ErrorCatchingResource):
@@ -22,9 +24,15 @@ class ApiOpenIdCallback(ErrorCatchingResource):
         if not state:
             return {}, 400

+        # Adapt current URL to URL manipulated over PUBLIC_URL to avoid
+        # issues with reverse proxies forwarding to Terrareg serving on HTTP port
+        parsed_url = urllib.parse.urlparse(request.url)
+        protocol, domain, port = terrareg.utils.get_public_url_details()
+        parsed_url = parsed_url._replace(scheme=protocol, netloc=f'{domain}:{port}')
+
         # Fetch access token
         try:
-            access_token = terrareg.openid_connect.OpenidConnect.fetch_access_token(uri=request.url, valid_state=state)
+            access_token = terrareg.openid_connect.OpenidConnect.fetch_access_token(uri=parsed_url.geturl(), valid_state=state)
             if access_token is None:
                 raise Exception('Error getting access token')
         except Exception as exc:
whoracle commented 7 months ago

Hey @MatthewJohn

Yep, can confirm, that did the trick :)

Rebuilt the container, set the following block in my docker-compose.yml, and off she went.

version: '3'
networks:
  gitea:
    external: false

services:
  terrareg:
    image: git.home.lynxcore.org/homelab/terrareg/terrareg:latest
    container_name: "terrareg"
    restart: unless-stopped
    depends_on:
      - mysql
      - gitea
    environment:
      - MIGRATE_DATABASE=True
      - SECRET_KEY=BLA
      - ADMIN_AUTHENTICATION_TOKEN=BLA
      - PUBLIC_URL=https://terraform.home.lynxcore.org
      - OPENID_CONNECT_CLIENT_ID=BLA
      - OPENID_CONNECT_CLIENT_SECRET=BLA
      - OPENID_CONNECT_ISSUER=https://auth.home.lynxcore.org/application/o/terrareg/
      - OPENID_CONNECT_SCOPES=openid,profile,email,groups
      - AUTO_CREATE_NAMESPACE=False
      - AUTO_CREATE_MODULE_PROVIDER=False
      - UPLOAD_API_KEYS=BLA
      - PUBLISH_API_KEYS=BLA
    ports:
      - "127.0.0.1:5000:5000"
    volumes:
      - /srv/docker/code/terrareg:/app/data
    networks:
      - gitea
    healthcheck:
      test: curl --fail http://localhost:5000 || exit 1
      interval: 5s
      retries: 30
      start_period: 30s
      timeout: 10s

# plus all the other services, obviously...

So, with the fix being in, any idea on WHY this happened? Because, as you said further upthread, you basically assume HTTPS everywhere where it's not explicitly set to HTTP. So why do you need to reparse the request.url? Is it really because terrareg thinks it's running withouth HTTPS?

And if so, I wonder how this did ever work for anyone behind an SSL terminating proxy, although the userbase for "Behind a Proxy, do not SSL between proxy and terrareg, and also using OIDC" could be rather slim...

Anyways, feel free to close this with whatever commit will fix this for good, and if you've got more questions or want me to try something out, just let me know.

MatthewJohn commented 7 months ago

Yep, can confirm, that did the trick :)

Excellent ;)

So, with the fix being in, any idea on WHY this happened? Because, as you said further upthread, you basically assume HTTPS everywhere where it's not explicitly set to HTTP. So why do you need to reparse the request.url? Is it really because terrareg thinks it's running withouth HTTPS?

Yes, this was assumed when generating a redirect URL. But in this case, we're passing the incoming URL from flask (which would be whatever the reverse-proxy calls, in your case, it would be 'http://terraform.home.lynxcore.org:5000', with whatever path/params the OpenID connect callback provides. So I've manipulated the user-specified PUBLIC_URL on-top of this, updated the protocol, port and domain to the flask URL.

Is it really because terrareg thinks it's running withouth HTTPS

Yes, if you have an application running behind a reverse proxy, the only communication the application will see is that with the reverse proxy (with the exception of X-Forwarded headers and the host header).

And if so, I wonder how this did ever work for anyone behind an SSL terminating proxy, although the userbase for "Behind a Proxy, do not SSL between proxy and terrareg, and also using OIDC" could be rather slim...

I have been pondering this - I took at look to see if the upsteam openidc library had changed (which it hasn't). Personally, I test locally with SSL in terrareg and the main deployed instances I use don't use OpenIDC.

I'm not sure if @mark-jones-rga faced this?

MatthewJohn commented 7 months ago

I've created an upstream bug: https://gitlab.dockstudios.co.uk/pub/terrareg/-/issues/484

I'll push that fix and write some tests and get it merged :)

Thanks again and apologies for the issue! If you do end up deciding to go with Terrareg, let me know if you have any further issues/suggestions :)

Many thanks Matt

mark-jones-rga commented 7 months ago

Matt, yes we did and our fix was to turn on OAUTHLIB_INSECURE_TRANSPORT=1 as an environment variable in our container definition. We run into it because from our AWS LB the protocol to the running container is http not https.

So this update will now fix if it redirects to http? PS we are still using terrareg and enjoying it! Unfortunately, not a ton of time to help contribute, plus I'm not a development wizard lol

MatthewJohn commented 7 months ago

Thanks for verifying @mark-jones-rga :)

So this update will now fix if it redirects to http?

It will stop it from throwing errors, yes. So if the user is using https to a reverse proxy, which is forwarding to terrareg on http, it will work now :) (though realistically, it's just ensuring that the value of PUBLIC_URL config is configured with an https URL - but this is used as the redirect URL, so in theory it would somewhat go towards enforcing it as well :eyes: ) :D

mark-jones-rga commented 7 months ago

Gotcha, I just recalled we fixed this by creating a local cert for the container and then updated the LB to forward to https and removed that env var.

MatthewJohn commented 7 months ago

Thanks :)

The fix has now been merged into v3.0.2

Feel free to re-open if there's further issues with it or raise another issue :)

Thanks