当在Docker容器中运行时,Flask_oidc会给出“Errno 99 Cannot assign requested address”的错误。

3

目标:

在运行于Docker容器中的Flask应用程序中使用OIDC。

背景:

我正在使用Flask构建Web应用程序,希望使用Keycloak提供访问权限。为此,我使用Python库flask_oidc。

所有服务都在本地运行的docker-compose文件中运行:

  • Gunicorn运行Flask应用程序(端口5000)
  • Keycloak(端口8080)

我按照https://gist.github.com/thomasdarimont/145dc9aa857b831ff2eff221b79d179a的示例进行操作,并将我的应用程序简化为这个样子。

问题:

  1. 启动所有服务
  2. 导航到需要登录的服务(示例中的/private
  3. 用户被重定向到Keycloud服务器并提示登录。
  4. 用户登录。
  5. Keycloak将用户路由回应用程序(/oidc_callback)
  6. !!! Flask应用程序崩溃,并显示OSError:[Errno 99] Cannot assign requested address错误。

当尝试连接到Keycloak服务器时,这是由flask_oidcoauth2clienthttplib2引起的。

我认为发生的事情是库尝试打开与Keycloak服务器的连接,但尝试将其绑定到localhost 。这可能会失败,因为在Docker容器内部应用程序绑定到0.0.0.0

我尝试过的:

[正常工作]在容器外运行Gunicorn / Flask应用程序,并在容器内运行Keylcoak。

对我来说,这表明我的所有设置和代码都很好,但问题出现在Docker< - > flask_oidc +之间的交互中。

问题: 有人能解释一下吗? 我真的希望有人有一个工作设置(在Docker中使用flask_oidc的Flask),并且愿意分享此信息。

更新[5-12-2018] 我想我想到了。 我使用PyOIDC手动执行所有步骤并能够进行调试。

当在计算机上同时运行Docker中的两个服务(localhost)时,会出现冲突:

  • 用户通过访问localhost:8080来找到Keycloak,通过访问localhost:5000来找到应用程序。
  • Flask应用程序在容器中运行,localhost不会被解析为主机,而是在容器内部被解析为自己。
  • 您可以让Flask使用容器中的网络连接到http://keycloak/,但是它返回的是这个域名下的所有配置。这是不好的,因为对外界来说应该是localhost:8080

现在,如果您实际上有域名(例如keycloak.awesome.app和app.awesome.app),我认为它会正常工作,因为它将使用外部DNS将其解析为IP地址,这是正确的机器。

奖励: PyOIDC可以从Keycloak检索提供程序配置,因此不再需要手动输入。耶!

新设置 对于本地开发,我决定进行如下设置:

(1) 添加到/etc/hosts: 127.0.0.1 keycloak.dev.local 127.0.0.1 app.dev.local

(2) 在docker-compose.yml中添加到您的Flask服务: extra_hosts: #host.docker.internal is not accepted. - "keycloak.dev.local:<YOUR IP ADRESS>" - "app.dev.local:<YOUR IP ADRESS>"

(=) 现在,您和Flask应用程序都可以访问keycloak.dev.local并获得正确的响应!

请注意,我仍然更喜欢一个更好的解决方案。一旦我的IP地址发生变化,此设置就会失败。


我觉得这个问题是由于flask-oidc引起的。 - Filnor
谢谢Rubenz!!! 你救了我的一天!我也遇到了同样的问题(使用gunicorn和docker没有问题,但是在docker中无法正常工作)。像你指出的那样,将我的flask-oidc url指向http://keycloak.dev.local:$port,并使用带有extrahost的docker-compose对我也起作用。 - Mr Bonjour
1个回答

2

flask-oidc从客户端密钥文件获取令牌端点配置。

我通过以下更改使其正常工作:

  1. flask应用程序keycloak容器创建了一个docker网络;
  2. 编辑了属性userinfo_uritoken_uritoken_introspection_uri,将主机名替换为keycloak容器主机名(在这种情况下,我使用的是docker-compose,keycloak容器主机名是服务名称)。

例如:

{
  "web": {
    "auth_uri": "http://localhost:8080/auth/realms/REMOVED/protocol/openid-connect/auth",
    "client_id": "flask-client",
    "client_secret": "REMOVED",
    "redirect_uris": ["http://localhost:5000/oidc_callback"],
    "userinfo_uri": "http://keycloak:8080/auth/realms/REMOVED/protocol/openid-connect/userinfo",
    "token_uri": "http://keycloak:8080/auth/realms/REMOVED/protocol/openid-connect/token",
    "token_introspection_uri": "http://keycloak:8080/auth/realms/REMOVED/protocol/openid-connect/token/introspect"
  }
}

现在它通过Docker网络连接以交换令牌信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接