netbirdio / netbird

Connect your devices into a secure WireGuard®-based overlay network with SSO, MFA and granular access controls.
https://netbird.io
BSD 3-Clause "New" or "Revised" License
10.87k stars 492 forks source link

Keycloak 17.0.2: Direct device authentication not working #475

Open ykorzikowski opened 2 years ago

ykorzikowski commented 2 years ago

Hello there,

I set up erverything like described in the selfhosting guide with keycloak. I can login to the admin console with keycloak and can see Peers etc.

However, when I try to do a netbird up, it wont connect to the management service.

$ netbird up  --management-url https://netbird-api.company.com/
WARN[2022-09-22T00:52:36+02:00] retrying Login to the Management service in 1.104660288s due to error rpc error: code = Unknown desc = context deadline exceeded

I can curl the api from my machin:

$ curl https://netbird-api.compay.com/api/groups
The token isn't valid
braginini commented 2 years ago

Hey @ykorzikowski

Are you running Dashboard and API on different machines, right? It might be that for the gRPC API a default 33073 port is used, as per the docker-compose.yml file.

Try

netbird up  --management-url https://netbird-api.company.com:33073
ykorzikowski commented 2 years ago

Good morning, just checked your reply.

I forget to tell you: I am using a nginx as reverse proxy.

CONTAINER ID   IMAGE                         COMMAND                  CREATED       STATUS       PORTS                                            NAMES
538bd6b9673e   netbirdio/management:latest   "/go/bin/netbird-mgm…"   8 hours ago   Up 8 hours   0.0.0.0:33073->80/tcp, :::33073->80/tcp          infrastructure_files-management-1
13a3d67ef2cb   wiretrustee/dashboard:main    "/usr/bin/supervisor…"   8 hours ago   Up 8 hours   443/tcp, 0.0.0.0:8080->80/tcp, :::8080->80/tcp   infrastructure_files-dashboard-1
17c8165e7fd5   coturn/coturn                 "docker-entrypoint.s…"   9 hours ago   Up 9 hours                                                    infrastructure_files-coturn-1
9ada4b76d13b   netbirdio/signal:latest       "/go/bin/netbird-sig…"   9 hours ago   Up 9 hours   0.0.0.0:10000->80/tcp, :::10000->80/tcp          infrastructure_files-signal-1

So basically, I want use no TLS in the docker containers, but with my reverse proxy. The Management Service still asks for some certificate, so I give him a self-signed cert.

server {
    listen *:80;
    listen [::]:80;
    server_name  netbird.***.com;

    location / {
        return 301 https://$server_name$request_uri;
    }
}

server {
    include security.conf;
    listen *:443 ssl;
    listen [::]:443 ssl;
    server_name netbird.***.com;
    ssl_certificate /etc/letsencrypt/live/***.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/***.com/privkey.pem;

    access_log /var/log/nginx/***.com/netbird.log;
    error_log /var/log/nginx/***.com/err/netbird.log;

    location / {
        proxy_pass http://10.10.10.118:8080;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Scheme $scheme;
    proxy_set_header        X-Forwarded-Proto https;
        proxy_set_header        X-Forwarded-Host netbird.***.com;
    }

}

and

server {
    listen *:80;
    listen [::]:80;
    server_name  netbird-api.***.com;

    location / {
        return 301 https://$server_name$request_uri;
    }
}

server {
    include security.conf;
    listen *:443 ssl;
    listen [::]:443 ssl;
    server_name netbird-api.***.com;
    ssl_certificate /etc/letsencrypt/live/***.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/***.com/privkey.pem;

    access_log /var/log/nginx/***.com/netbird-api.log;
    error_log /var/log/nginx/***.com/err/netbird-api.log;

    location / {
        proxy_pass https://10.10.10.118:33073;
        proxy_ssl_verify              off;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        Access-Control-Allow-Origin "*";
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Scheme $scheme;
        proxy_set_header        X-Forwarded-Proto https;
        proxy_set_header        X-Forwarded-Host netbird-api.***.com;
    }

}

So maybe we can figure it out together and add it to the documentation :)

braginini commented 2 years ago

We didn't try it yet with Ngnix but there should be some config that allows gRPC connections.

The Management service exposes gRPC API to clients to fetch the network config.

Dashboard uses the Management HTTP API.

gRPC and HTTP APIs are running on the same port.

ykorzikowski commented 2 years ago

So the netbird client uses the gRPC-API and not HTTP?

braginini commented 2 years ago

So the netbird client uses the gRPC-API and not HTTP?

Yes, exactly. The HTTP API is used by the Dashboard.

We will be putting things behind Caddy for simpler setups in the near future.

ykorzikowski commented 2 years ago

THX for the tip. I am one step further now:

server {
    include security.conf;
    listen *:9000 ssl http2;
    listen [::]:9000 ssl;
    server_name netbird-grpc.***.com;
    ssl_certificate /etc/letsencrypt/live/***.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/***.com/privkey.pem;

    access_log /var/log/nginx/***.com/netbird-grpc.log;
    error_log /var/log/nginx/***.com/err/netbird-grpc.log;

    location / {
        grpc_pass grpcs://10.10.10.118:33073;
        grpc_ssl_verify off;
    }

}

Now Keycloak Oauth opens, but I get this on mgmt console:

time="2022-09-22T08:05:46Z" level=debug msg="rpc error: code = PermissionDenied desc = provided peer with the key wgPubKey ***= is not registered and no setup key or jwt was provided, remote addr is 10.10.10.109:50042" file="grpcserver.go:282"

Maybe I did something wrong when setting up the keycloak realm.

braginini commented 2 years ago

I see, I think this one will be easy to fix. The Keycloak is fine.

How did you start the client? This way?

netbird up  --management-url https://netbird-api.company.com/

You should either run it with the setup key like so:

netbird up  --management-url https://netbird-api.company.com:33073 --setup-key <Your Setup Key>

Or Device Auth Flow (SSO Login) has to be enabled in Management config: https://github.com/netbirdio/netbird/blob/c5705803a503a910c7fb07fbc3fe9515f6b88701/infrastructure_files/management.json.tmpl#L42

What is in your DeviceAuthorizationFlow config?

ykorzikowski commented 2 years ago

It looks like this. I am using the master realm, not sure if this is an issue. I did not create a extra one like in the setup guide described.

    "DeviceAuthorizationFlow": {
        "Provider": "hosted",
        "ProviderConfig": {
          "Audience": "netbird-client",
          "Domain": "",
          "ClientID": "netbird-client",
          "TokenEndpoint": "https://sso.***.com/realms/master/protocol/openid-connect/token",
          "DeviceAuthEndpoint": "https://sso.***.com/realms/master/protocol/openid-connect/auth/device"
         }
    }
braginini commented 2 years ago

It looks like this. I am using the master realm, not sure if this is an issue. I did not create a extra one like in the setup guide described.

    "DeviceAuthorizationFlow": {
        "Provider": "hosted",
        "ProviderConfig": {
          "Audience": "netbird-client",
          "Domain": "",
          "ClientID": "netbird-client",
          "TokenEndpoint": "https://sso.***.com/realms/master/protocol/openid-connect/token",
          "DeviceAuthEndpoint": "https://sso.***.com/realms/master/protocol/openid-connect/auth/device"
         }
    }

It is hard to say what went wrong if you didn't follow the guide. Maybe you didn't enable Device Authorization Grant in step 4 (second screenshot) of the client configuration? https://netbird.io/docs/integrations/identity-providers/self-hosted/using-netbird-with-keycloak#step-4-create-a-netbird-client

ykorzikowski commented 2 years ago

You are right, it was not selected.

I get this, but ithe netbird up command stuck.

grafik

Now I get another error in keycloak logs:

2022-09-23 17:43:20,332 WARN  [org.keycloak.events] (executor-thread-26) type=OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR, realmId=master, clientId=null, userId=null, ipAddress=79.**.**.70, error=invalid_oauth2_user_code, reason='device code not found (it may already have been used)'

Thank you very much for help :)

braginini commented 2 years ago

And if you restart NetBird and try again? The issue is reproducible?

ykorzikowski commented 2 years ago

Yep, I restarted netbird.

I tried on a different machine as client with a different user. The version of keycloak i use is 17.0.2. It looks like, the callback from keycloak back to netbird is not triggered (but I do not know the exact way how the login procedure works). The CLI is endless waiting for the auth. If you re-open the link, keycloak complains that device key is already used (like above described).

THis keys get created on the attempt: grafik

One thing I notice: I logged in with two users, but the cant see each other in users view:

User A: grafik

User B: grafik

keycloak log of auth:

2022-09-24 07:49:53,610 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (executor-thread-20) PrivacyIDEA Client: Replacing privacyIDEA instance for realm master
2022-09-24 07:49:53,613 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-1) PrivacyIDEA Client: POST /auth
2022-09-24 07:49:53,613 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-1) PrivacyIDEA Client: username=keycloak_service_account
2022-09-24 07:49:53,613 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-1) PrivacyIDEA Client: password=************************************
2022-09-24 07:49:53,614 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-1) PrivacyIDEA Client: realm=***.com.admin
2022-09-24 07:49:53,806 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-1) PrivacyIDEA Client: POST /validate/triggerchallenge
2022-09-24 07:49:53,807 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-1) PrivacyIDEA Client: user=yko_adm_user
2022-09-24 07:49:53,807 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-1) PrivacyIDEA Client: realm=***.com.admin
2022-09-24 07:49:54,204 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (OkHttp https://2fa.***.com/...) PrivacyIDEA Client: /validate/triggerchallenge:
{
  "detail": {
    "attributes": {
      "hideResponseInput": true
    },
    "client_mode": "poll",
    "message": "Bitte geben Sie einen OTP-Wert ein: , Please confirm the authentication on your mobile device! Use the polling feature of your privacyIDEA Authenticator App to check for a new Login request.",
    "messages": [
      "Bitte geben Sie einen OTP-Wert ein: ",
      "Please confirm the authentication on your mobile device! Use the polling feature of your privacyIDEA Authenticator App to check for a new Login request."
    ],
    "multi_challenge": [
      {
        "client_mode": "interactive",
        "message": "Bitte geben Sie einen OTP-Wert ein: ",
        "serial": "***",
        "transaction_id": "00942768684158838260",
        "type": "totp"
      },
      {
        "attributes": {
          "hideResponseInput": true
        },
        "client_mode": "poll",
        "message": "Please confirm the authentication on your mobile device! Use the polling feature of your privacyIDEA Authenticator App to check for a new Login request.",
        "serial": "***",
        "transaction_id": "00942768684158838260",
        "type": "push"
      }
    ],
    "serial": "***",
    "threadid": 140429160433472,
    "transaction_id": "00942768684158838260",
    "transaction_ids": [
      "00942768684158838260",
      "00942768684158838260"
    ],
    "type": "push"
  },
  "id": 2,
  "jsonrpc": "2.0",
  "result": {
    "authentication": "ACCEPT",
    "status": true,
    "value": 2
  },
  "time": 1664005794.1786666,
  "version": "privacyIDEA 3.7.3",
  "versionnumber": "3.7.3",
  "signature": "rsa_sha256_pss:7c00edba56691d004d26457616143077ad56d7607f07c3da40f95bceb2d57018f741786f90ab8eb4fbe9b476e27299b96e256baac0a4ef9489b91f5ad8a57245a365a10a219f50132dbd5e859a0d5ba5f136690e789102e12639b48fa0e8039af0224792a106643e85b9e65409a46069813edf0e713c7fc186cca092e02186a09e161f8f01c7bb70fc7808f17353b9e5fedd494c640a6e3f917474c6f215ae97f1deb9734375f74bc9677de819dda887fb8b49495872b26472f7fd243acc14215626bcc93c0a177d418910ddc1940181c2b7680c6cd928913dc9224b4a6115ce475cb2705e0c00def1d72afa79fc9eb504d8449cb2758dd554c95c67bcfc96ce"
}
2022-09-24 07:49:58,331 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-2) PrivacyIDEA Client: GET /validate/polltransaction
2022-09-24 07:49:58,331 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-2) PrivacyIDEA Client: transaction_id=00942768684158838260
2022-09-24 07:50:00,500 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-3) PrivacyIDEA Client: GET /validate/polltransaction
2022-09-24 07:50:00,500 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-3) PrivacyIDEA Client: transaction_id=00942768684158838260
2022-09-24 07:50:02,667 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-4) PrivacyIDEA Client: GET /validate/polltransaction
2022-09-24 07:50:02,668 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-4) PrivacyIDEA Client: transaction_id=00942768684158838260
2022-09-24 07:50:04,824 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-5) PrivacyIDEA Client: GET /validate/polltransaction
2022-09-24 07:50:04,824 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-5) PrivacyIDEA Client: transaction_id=00942768684158838260
2022-09-24 07:50:04,884 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-6) PrivacyIDEA Client: POST /validate/check
2022-09-24 07:50:04,884 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-6) PrivacyIDEA Client: user=yko_adm_user
2022-09-24 07:50:04,885 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-6) PrivacyIDEA Client: pass=
2022-09-24 07:50:04,885 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-6) PrivacyIDEA Client: transaction_id=00942768684158838260
2022-09-24 07:50:04,885 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (pool-9-thread-6) PrivacyIDEA Client: realm=***.com.admin
2022-09-24 07:50:04,987 INFO  [org.privacyidea.authenticator.PrivacyIDEAAuthenticator] (OkHttp https://2fa.***.com/...) PrivacyIDEA Client: /validate/check:
{
  "detail": {
    "message": "Found matching challenge",
    "serial": "***",
    "threadid": 140429160433472
  },
  "id": 2,
  "jsonrpc": "2.0",
  "result": {
    "authentication": "ACCEPT",
    "status": true,
    "value": true
  },
  "time": 1664005804.9552202,
  "version": "privacyIDEA 3.7.3",
  "versionnumber": "3.7.3",
  "signature": "rsa_sha256_pss:aeb77fe5037c16d9322dc6f9727c071ee65e2381f06e57fefdf2e7dae4730933f987ca70fa9bd66efc0d0c508945e41ce6095130abdb012a5a979d22f04f86eb115e00dd3eba2292afd7d7611282c5bedea94398c56d96e9e78053a8c05b264e1318f6c8bef3f004fb5af5b6d8bbdb65d44c8630374fd717a49aba43efa14d35f75e4190f5e38e4aaefda126f7c14a941153e5d5d84c1d4007ccbecb9295ff30c5b8c2f1bd2493041300b21dbf388918e370b30c012cb90e1863d312674d4d03324609390151941274ecebd9975f70ccf6aa99a9b32cc03ce58d696f900a2394d43d88223e9a1f372860bcb1c586e7e08b50e8bd9c918b6fc4578a20eb376cd1"
}
2022-09-24 07:54:51,235 WARN  [org.keycloak.services] (executor-thread-20) KC-SERVICES0091: Request is missing scope 'openid' so it's not treated as OIDC, but just pure OAuth2 request.
braginini commented 2 years ago

I guess that this is unrelated to the device auth issue:

One thing I notice: I logged in with two users, but the cant see each other in users view: But it is related to this. You probably skipped it in the Keycloak guide.

https://netbird.io/docs/integrations/identity-providers/self-hosted/using-netbird-with-keycloak#step-8-ensure-that-all-users-will-join-the-same-netbird-network-optional

braginini commented 2 years ago

Overall, I suggest that you go through the setup as per the guideline completing all the steps:

https://netbird.io/docs/integrations/identity-providers/self-hosted/using-netbird-with-keycloak

pnowy commented 1 year ago

@ykorzikowski @braginini I've spent some time recently with setup the self-hosted NetBird based on Keycloak and in general everything works fine (GCP based) - just needed to struggle a little bit.

I'm waiting to be able to setup DNS (https://github.com/netbirdio/netbird/issues/373) maybe then I will put some instruction how to configure it in GCP env specific if it will useful for other people and project itself.

@braginini I think Keycloak addition to docker-compose version should be quite easy as it possible to import realm out-of-the-box so maybe we should add as a part of NetBird the specific docker-compose which configure NetBird + Keycloak in one shot.

During the installation I noticed that command for management component command: ["--port", "443", "--log-file", "console", "--disable-anonymous-metrics=true", "--single-account-mode-domain=mynetbird.com"] should be updated - otherwise (at least in my case) the separated client were added to different account/tenant if empty. I think this part wasn't exactly described in the docs and configure script doesn't update it in the fly.

@braginini I have also 2 questions:

Thanks!

pnowy commented 1 year ago

Ok - I checked and it seems that UI (dashboard) don't have to be exposed with Keycloak - the realm is enough to authenticate the user/machine.

braginini commented 1 year ago

Hey @pnowy We thought of adding Authentik to docker-compose. But Keycloak should be a good option as well. The alternative was to embed a very simple IdP implemented with Zitadel.

It is not required exposing the dashboard, but you will need to manage the SSL certificates on your own because Letsencrypt validates certs dynamically.

As for the HA availability. No advice in particular, but we planned that for Q1'23. We just refactored the storage interface to be able to embed HA storages.

ykorzikowski commented 1 year ago

After updating everything to the most recent 0.17.0 I re-tried the device authorization with my keycloak instance. In the meantime I also updated keycloak to 22.0.1.

I get the "Device Login Successful" like in the Expected Result section, but the terminal is still waiting for the response (so there is never a connection being established).

I recreate the netbird-client in keycloak and checked my configuration but I am not able to find the issue.

keycloak.log (after first successfull message, I can't retry it with same device code. Otherwise I get the following error)

2023-04-28 22:11:38,067 WARN  [org.keycloak.events] (executor-thread-30) type=OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR, realmId=master, clientId=null, userId=null, ipAddress=80.141.**.**, error=invalid_oauth2_user_code, reason='device code not found (it may already have been used)'

/var/log/netbird/client.log

2023-04-29T00:12:11+02:00 WARN client/server/server.go:119: failed login: rpc error: code = InvalidArgument desc = invalid setup-key or no sso information provided, err: invalid UUID length: 0

management.json

{
    "Stuns": [
        {
            "Proto": "udp",
            "URI": "stun:netbird.***.com:3478",
            "Username": "",
            "Password": null
        }
    ],
    "TURNConfig": {
        "Turns": [
            {
                "Proto": "udp",
                "URI": "turn:netbird.***.com:3478",
                "Username": "self",
                "Password": "***"
            }
        ],
        "CredentialsTTL": "12h",
        "Secret": "secret",
        "TimeBasedCredentials": false
    },
    "Signal": {
        "Proto": "https",
        "URI": "netbird.***.com:10000",
        "Username": "",
        "Password": null
    },
    "Datadir": "",
    "HttpConfig": {
        "Address": "0.0.0.0:80",
        "AuthIssuer": "https://sso.***.com/realms/master",
        "AuthAudience": "netbird-client",
        "AuthKeysLocation": "https://sso.***.com/realms/master/protocol/openid-connect/certs",
        "disabled_CertFile":"/etc/letsencrypt/live/netbird.***.com/fullchain.pem",
        "disabled_CertKey":"/etc/letsencrypt/live/netbird.***.com/privkey.pem",
        "OIDCConfigEndpoint":"https://sso.***.com/realms/master/.well-known/openid-configuration"
    },
    "IdpManagerConfig": {
      "ManagerType":  "keycloak",
      "KeycloakClientCredentials": {
        "ClientID": "netbird-backend",
        "ClientSecret": "***",
        "GrantType": "client_credentials",
        "TokenEndpoint": "https://sso.***.com/realms/master/protocol/openid-connect/token",
        "AdminEndpoint": "https://sso.***.com/admin/realms/master"
      }
    },
    "DeviceAuthorizationFlow": {
        "Provider": "hosted",
        "ProviderConfig": {
          "Audience": "netbird-client",
          "Domain": "",
          "ClientID": "netbird-client",
          "TokenEndpoint": "https://sso.***.com/realms/master/protocol/openid-connect/token",
          "DeviceAuthEndpoint": "https://sso.***.com/realms/master/protocol/openid-connect/auth/device",
          "Scope": "openid",
          "UseIDToken": false
         }
    }
}