openStack之openID实现单点登录

配置 Keystone 与 Horizon, 实现支持 OIDC 模式的 Web SSO
Keystone Federation 功能的简介
Keystone 作为 OpenStack 中核心组件之一,主要提供身份验证、服务管理、令牌服务及权限管理等服务。Keystone 设计之初,所有用户信息均保存在 Keystone 服务中,由 Keystone 承担用户信息管理及用户身份认证。随着 Keystone 服务的日渐成熟,兼容第三方的身份信息管理服务,成为越来越多用户期待的需求。在 Icehouse 版本中,Keystone 服务中提出 Federation 功能,作为附加功能,为用户提供 OpenStack 环境之外的身份信息管理功能。
Keystone Federation 功能,允许 Keystone 使用第三方的服务,管理 OpenStack 云环境中的用户信息,提供身份验证功能,对于已经验证过的用户,Keystone 提供令牌管理及权限管理服务,帮助用户方面使用 OpenStack 云服务。借助于 Keystone Federation,企业可以将内部现有的身份管理平台与 OpenStack 云服务进行对接,通过企业内部账号,简单便捷的使用云资源,同时,借助于更专业、更安全的身份认证手段,可以更好的确保云环境中用户信息的安全。
Federation 功能在经历了几个版本的成长,已经有了很大的进步,目前已经可以支持多种方式的身份认证,比较流行的包括:
1.基于 SAML2.0 的身份管理服务提供商;
2.基于 OpenID Connect 的身份验证提供商;
3.基于 LDAP 与 Kerberos 的身份管理及认证服务等。
Keystone Federation 基础架构及工作流程
Keystone Federation 中主要包含几个主要概念:
Identity Provider(简称 IdP):为 Keystone 服务提供用户身份管理及验证服务;
Service Provider(简称 SP):Keystone 服务,提供除用户信息管理及验证以外的其他服务;
Certificated information of User identity:作为临时信息,提供给 Keystone 服务,证明此用户已经通过验证;信息中包含用户的信息,且根据协议的不同略有差别,SAML2.0 使用 assertion 作为此信息的载体,OpenID Connect 则通过 OpenID Connect claim 作为此信息的载体;
Web Single Sign On(Web SSO):网络单点登录,用户可以通过一个账号,登录不同的系统或服务,即用户可以通过 Google email 的账号,登录到 OpenStack 云环境中进行操作。
Keystone Federation 的基础架构,以 OpenID Connect 为例,如图 1 所示:
在这里插入图片描述
图 1.Keystone Federation 基础架构图

Keystone Federation 准备工作:

在 IdP 与 SP 之间建立彼此信任,IdP 服务中需要添加 SP 的具体信息,SP 服务中也需要添加 IdP 的相关信息,并将 IdP 添加至 Keystone 信任的列表中;
在 Federation 过程中,用户身份信息存储在第三方的 IdP 中,并通过 IdP 进行身份认证,IdP 将认证结果发送给 Keystone 服务,Keystone 服务需要对 IdP 中存储的用户,创建相应的映射关系,将用户与 Keystone 服务中存在的用户组进行对应,从而进行用户权限管理。
Keystone Federation 工作流程,以用户请求查看 Keystone 服务中的服务列表为例,如图 2 所示:

图 2.Keystone Federation 的工作流程:
在这里插入图片描述
用户发送请求给 Keystone 服务,查看服务列表;

  • Keystone 服务验证用户的有效性,根据用户请求中包含的验证方法,Keystone 服务将信息发送至第三方 IdP(此实验中,为
    Google Sign-In),进一步请求用户身份验证;

  • 第三方 IdP 验证用户身份后,通过 OpenID Connect claim,发送至 Keystone 服务,证明用户身份已经确认,里面包含用户的具体信息及 IdP 的具体信息;

  • Keystone 服务通过 Apache Httpd Server 中的模块 mod_auth_openidc,对 claim 信息进行检查,确认 IdP
    身份有效后,查询本地数据中 IdP 与 SP 之间对于用户的映射表,找出映射到的用户组;

  • Keystone服务根据对应的用户组,验证用户的操作权限,并返回此权限范围内可看到的云环境中的服务列表。

Keystone Federation 的优势:

  • Keystone 服务可以不再存储用户的身份信息及密码等,减少了 Keystone 服务对于此类信息维护的工作内容,使 OpenStack 云平台的用户管理更加多样化;

  • Keystone 服务不再需要添加额外的验证机制,用户的身份验证功能可以通过 IdP 完成,可以更好的使用新增的用户验证算法,从而提升 OpenStack 云平台的安全性;

  • 多个组织可以通过维护本地的 IdP,可以共用同一个 OpenStack 云环境;

  • 为用户提供 Web SSO 功能,使用户登录 OpenStack 云环境更加便捷。

OpenID Connect 简介
OpenID Connect(简称 OIDC) 是基于 OAuth 2.0 的一种身份认证协议,基于 JSON 格式,良好的兼容 REST,在 OAuth 的基础上,允许客户端通过 Authorization Server 验证用户身份,并以标准的 ID_TOKEN 获取用户的基本信息。OIDC 协议丰富了云端应用程序及移动端应用对于身份认证的需求,可以借助于已有的验证服务,为用户提供登录服务。
OpenID Connect 中包含一些基础的概念,如下:
OpenID Connect Provider(简称 OIDC Provider):用于验证用户身份,并提供 claim 给 RP 的系统或服务;
Relaying Party(简称 RP):客户端程序,请求用户身份验证,并从 OIDC Provider 获得 claim 的应用或服务;
End-User:使用 RP,且通过 OIDC Provider 进行管理的用户;
OpenID Connect 的主要工作流程,如图 3 所示:

图 3.OpenID Connect 工作流程
在这里插入图片描述

  • 用户请求登录 RP 提供的应用或服务,RP 发送请求至 OIDC Provider,请求用户身份验证;
  • OIDC Provider 验证用户身份,并获取用户的授权信息;
  • OIDC Provider 回复给 RP 验证过的用户的基本信息,通常包括 ID Token 及 Access Token;
  • RP 发送请求至 UserInfo Endpoint 服务,请求中包含 Access Token;
  • UserInfo Endpoint 服务返回给 RP 关于用户的 claims 信息。

目前,OpenID Connect 主要支持三种身份验证流程,分别是:

  • 基于 Authorization Code 进行身份认证;
  • 基于 Implicit 流程进行身份认证;
  • 基于 Hybrid流程进行身份认证

Keystone Federation 实验环境配置与搭建
本次实验环境基于 Ubuntu14.04 进行搭建,基于目前 OpenStack 社区 master 分支上的代码,借助于 devstack 进行搭建。devstack 所使用到的配置文件localrc内容如下:

[[local|localrc]]
ENABLED_SERVICES=key,g-api,g-reg,n-api,n-crt,n-obj,n-cpu,n-net,n-cond,cinder,c-sch,c-api,c-vol,n-sch,n-cauth,horizon,mysql,rabbit
SERVICE_TOKEN=password
ADMIN_PASSWORD=password
MYSQL_PASSWORD=password
RABBIT_PASSWORD=password
SERVICE_PASSWORD=password
LOGFILE=/opt/stack/logs/stack.sh.log
LIBS_FROM_GIT=python-keystoneclient,python-openstackclient

环境中,仅安装基础 OpenStack Services,在满足实验要求的情况下,尽可能简化环境搭建步骤。

Identity Provider 部分环境配置
本次实验中,IdP 使用 Google Identity Platform 提供的 Google Sign-In,Google Sign-In 是 Google 提供的安全的身份认证系统,允许用户通过 Google 账号登录第三方应用或系统,简化了用户使用服务的登录过程。

将 OpenStack 云服务平台作为 Service Provider 注册到 Google IdP 中

通过 Google Developers Console 添加一个新的项目,作为 SP,代表 OpenStack 云平台提供的服务,实验中,项目名为"federation-demo-cloud";
创建 OAuth 2.0 client ID,如图 4 所示:
图 4.OAuth 2.0 client ID 创建
在这里插入图片描述
创建好后,将会得到创建项目的 client ID 及相应的 client secret,如图 5 所示:
图 5.OAuth 2.0 client ID 及 client secret
在这里插入图片描述
client ID 及 client secret 将会在后面的配置中使用。创建好的 client ID 及相关信息,可以通过 Google Developer Console 进行查看与修改。

Service Provider 中必要实例创建
由于用户身份信息存储在 Keystone 服务外部,为了实现 Keystone 服务对于用户的权限管理,需要创建必要的用户组,来管理通过 Federation 方式进行身份认证的用户,并为此类用户在相应的项目及域中添加合适的角色,以便用户可以在分配的项目或域中完成操作。

创建super_adminrc文件,并添加为系统变量,便于后续openstack命令的使用,文件内容如下:

export OS_TOKEN=openstack
export OS_URL=http://$your_host_ip:5000/v3
export OS_IDENTITY_API_VERSION=3

创建用户组,以管理 Federation 的用户,名为"federation_group",命令如下:

# openstack group create --domain default --description "Federation User Group" federation_group

创建实验所需的项目, 名为"federation_demo_project",命令如下:

# openstack project create --domain default --description "Federation Demo Project" federation_demo_project

为"federation_group"用户组,在项目"federation_demo_project"及域"Default"中添加管理员角色,命令如下:

# openstack role add --domain default --group $federation_group_uuid admin

# openstack role add --project $federation_demo_project_uuid --group $federation_group_uuid admin

为了实现 Keystone Federation,需要创建额外三个实例,分别是 IdP 实例,Mapping 实例及 Protocol 实例。

Keystone 服务需要将实验中的 IdP 信息添加到系统中,创建 IdP 实例,IdP 名为"google",命令如下:

`# openstack identity provider create google --remote-id` `https://accounts.google.com`

Keystone 需要创建 Mapping 实例,用于管理 Federation 用户的权限,创建 Mapping 需要提供相应的映射规则,文件名为"google-mapping-rules.json",内容如下:

[
 {
 "local": [
 {
 "group": {
 "id": "$created_group_id"
 }
 }
 ],
 "remote": [
 {
 "type": "HTTP_OIDC_ISS",
 "any_one_of": [
 "https://accounts.google.com"
 ]
 }
 ]
 }
]

创建的 Mapping 实例名为"google_idp_mapping",命令如下:

# openstack mapping create google-idp-mapping --rules ./mapping_rule.json

Keystone 服务需要为信任的 IdP 创建 Protocol 实例,用于记录 IdP 使用的身份验证协议,以及 IdP 与 Mapping 实例的对应关系,实例名为"oidc",命令如下:

# openstack federation protocol create oidc --identity-provider google --mapping google-idp-mapping

Service Provide 部分的配置
Keystone 服务,作为基于 WSGI 的服务,可以运行在 WSGI 服务其中,在 Kilo 版本之前,默认使用 eventlet 作为 WSGI 服务器,从 Liberty 版本开始,devstack 出来的 OpenStack 环境中,Keystone 服务默认跑在 Apache Httpd 服务器中。本次实验,需要 Keystone 服务跑在 Apache Httpd 服务其中,便于借助于 Httpd 服务器中的 module 处理与 OIDC Provider 数据传递。

更改 Keystone 服务的配置文件,/etc/keystone/keystone.conf,在[auth]中添加对于 OpenID Connect 的支持,同时在[federation]中添加"remote_id_attribute",更改内容如下:

[auth]

    # Allowed authentication methods. (list value)
    methods = external,password,token,oauth1,oidc
    oidc = keystone.auth.plugins.mapped.Mapped
    ......
    [federation]
    # Value to be used to obtain the entity ID of the Identity Provider from the
    # environment (e.g. if using the mod_shib plugin this value is `Shib-Identity-
    # Provider`). (string value)
    remote_id_attribute = HTTP_OIDC_ISS

安装mod_auth_openidc模块,允许 Apache Httpd 服务器,借助于第三方 OIDC Provider 验证用户身份信息,安装命令如下:

# sudo apt-get install libjansson4 libhiredis0.10 libcurl3 -y
# wget https://github.com/pingidentity/mod_auth_openidc/releases/download/v1.8.3/libapache2-mod-auth-openidc_1.8.3-1_amd64.deb
# sudo dpkg -i libapache2-mod-auth-openidc_1.8.3-1_amd64.deb

配置 Keystone 服务的 VirtualHost,配置文件位于/etc/apache2/sites-enabled/keystone.conf:
添加对于mod_auth_openidc的支持,添加内容如下:

LoadModule auth_openidc_module /usr/lib/apache2/modules/mod_auth_openidc.so
配置 Keystone 服务的 VirtualHost,由于 Keystone Federation 服务使用 Keystone V3 版本的服务,V3 版本的 Keystone 服务不再通过端口进行请求的区分,因此,更改任何一个 VirtualHost 即可,本次实验,以更改端口为"5000"的 VirtualHost 为例,更改内容如下:

<VirtualHost *:5000>
 ......
 OIDCClaimPrefix "OIDC-"
 OIDCResponseType "id_token"
 OIDCScope "openid email profile"
 OIDCProviderMetadataURL https://accounts.google.com/.well-known/openid-configuration
 OIDCClientID $your_created_client_id
 OIDCClientSecret $your_client_generated_secret
 OIDCCryptoPassphrase openstack
 OIDCRedirectURI http://$your_machine_hostname:5000/v3/auth/OS-FEDERATION/websso/oidc/redirect
 <Location ~ "/v3/auth/OS-FEDERATION/websso/oidc">
 AuthType openid-connect
 Require valid-user
 LogLevel debug
 </Location>
 ......
</VirtualHost>

更改 Horizon 服务的配置文件,增添 Web SSO 功能,配置文件位于/opt/stack/horizon/openstack_dashboard/local/local_settings.py,更改内容如下:

  ......
    OPENSTACK_API_VERSIONS = {
     "identity": 3
    }
    ......
    OPENSTACK_KEYSTONE_URL="http://$your_machine_hostname:5000/v3"
    ......
    # Enables keystone web single-sign-on if set to True.
    WEBSSO_ENABLED = True
    WEBSSO_CHOICES = (
     ("credentials", _("Keystone Credentials")),
     ("oidc", _("OpenID Connect"))
    )
    WEBSSO_INITIAL_CHOICE = "credentials"
    ......

更改 Keystone 服务的配置文件,将 Horizon 服务的登录页面添加至 Keystone 服务信任的登录页面,更改内容如下:

[federation]
# A list of trusted dashboard hosts. Before accepting a Single Sign-On request
# to return a token, the origin host must be a member of the trusted_dashboard
# list. This configuration option may be repeated for multiple values.
trusted_dashboard = http://$your_machine_hostname/dashboard/auth/websso/

并将相应的sso_callback_template.html文件拷贝到 Keystone 服务配置项目录,重启 Apache Httpd 服务器,命令如下:

# cp /opt/stack/keystone/etc/sso_callback_template.html /etc/keystone/
# sudo service apache2 restart

测试实验环境
通过浏览器,输入 Horizon 服务的地址,进入 Horizon 服务的登录界面,并选择 OpenID Connect 作为用户身份认证的方式,如图 6 所示:
图 6.Horizon 登录界面
在这里插入图片描述
点击链接,页面将自动跳转至 Googl Sign-In 页面,输入用户的 Google 邮箱及密码,进行登录,登录成功后,会跳转回 Horizon 页面,如图 7 所示:
图 7. 登录成功后的 Horizon 界面
在这里插入图片描述
可以看到,在 OpenStack 环境中,Keystone 服务将通过 Federation 登录的用户,映射到"federation_demo_project"中,并为用户创建了一个临时的用户 ID,允许用户在此项目中使用云环境中的资源。

Keystone Federation 功能代码解析
本章以用户通过 Federation 获取 unscoped Token 的过程为例,分析数据的流向,方法的调用过程及主要代码的作用。

用户通过 Keystone Federation 方法验证身份,获取 unscoped Token 的方法调用过程,如图 8 所示:
图 8. 获取 unscoped token 的调用过程
在这里插入图片描述
用户通过 Google Sign-In 进行身份认证的过程中,Google Sign-In 作为 OpenID Connect Provider,用于验证用户身份,Apache Httpd 服务器的mod_auth_openidc模块则作为 Relaying Party,用于与 OIDC 进行交互,获取验证后的 claims 信息,其中,配置在 Keystone 服务 VirtualHost 中的主要参数作用如下:

   OIDCClaimPrefix "OIDC-" //定义 Claims 中的信息都添加 OIDC 前缀,为 context 所用
    OIDCResponseType "id_token" //定义 RP 获取 OIDCP 的 token 形式
    OIDCScope "openid email profile" //定义 Claim 中用户的信息列表
    OIDCProviderMetadataURL <a href="https://accounts.google.com/.well-known/openid-configuration">https://accounts.google.com/.well-known/openid-configuration</a> //定义 RP 在获取 token,获取用户信息过程中需要用到的 endpoints 的地址集合
    OIDCRedirectURI <a href="http://ip9-114-193-105.pok.stglabs.ibm.com:5000/v3/auth/OS-FEDERATION/websso/oidc/redirect">http://ip9-114-193-105.pok.stglabs.ibm.com:5000/v3/auth/OS-FEDERATION/websso/oidc/redirect</a> //用于定义在验证结束后跳转的 URL

根据mod_auth_openidc中定义的跳转 URL,会调用 Keystone 服务提供的 API /v3/auth/OS-FEDERATION/websso/oidc进行处
理,处理 Federation 相关的代码,均存放于./keystone/keystone/contrib/federation下,根据 Router 中的定义:

self._add_resource(
    mapper, auth_controller,
    path='/auth' + self._construct_url('websso/{protocol_id}'),
    get_post_action='federated_sso_auth',
    rel=build_resource_relation(resource_name='websso'),
    path_vars={
        'protocol_id': PROTOCOL_ID_PARAMETER_RELATION,
    })

会交给 Controller 中对应的方法federated_sso_auth进行处理。

Federation 功能对应的 Controller 文件,位于./keystone/keystone/contrib/federation/controllers.py,其中,方法federated_sso_auth的主要代码如下:

def federated_sso_auth(self, context, protocol_id):
 ......
    ref = self.federation_api.get_idp_from_remote_id(remote_id)
    # NOTE(stevemar): the returned object is a simple dict that
    # contains the idp_id and remote_id.
    identity_provider = ref['idp_id']
    res = self.federated_authentication(context, identity_provider, protocol_id)
 ......

此方法的主要作用,是根据:claim 中提供的remote_id_name,获取 IdP 的实例,并调用方法federated_authentication。
方法federated_authentication的主要代码如下:

def federated_authentication(self, context, identity_provider, protocol):
 ......
    auth = {
        'identity': {
            'methods': [protocol],
        protocol: {
                'identity_provider': identity_provider,
                'protocol': protocol
            }
        }
    }
 ......
    return self.authenticate_for_token(context, auth=auth)

此方法主要构建用于验证用户的payload,并调用auth模块的方法authenticate_for_token,验证用户并创建 token。

方法authenticate_for_token位于./keystone/keystone/contrib/federation/controllers.py,此方法是所有用户身份认证及 token 获取的入口,主要代码如下:

def authenticate_for_token(self, context, auth=None):
    """Authenticate user and issue a token."""
 ......
        self.authenticate(context, auth_info, auth_context)
 ......
        (token_id, token_data) = self.token_provider_api.issue_v3_token(
            auth_context['user_id'], method_names, expires_at, project_id,
            domain_id, auth_context, trust, metadata_ref, include_catalog,
            parent_audit_id=token_audit_id)
 ......

其中,方法 self.authenticate()会根据/etc/keystone/keystone.conf 中的配置项 auth.method,调用具体的 driver 进行处理,本次实验中,用于处理用于验证的 driver 为./keystone/keystone/auth/plugins/mapped.py:Mapped(),验证通过后,根据用户信息,调用 token 模块生成 unscoped token。
总结
随着云计算的迅速发展,无论是公有云、私有云还是混合云都将面临更大考验,其中安全性和易用性必然成为用户选择云产品的考量要点。Openstack Keystone Federation 功能,通过拓展验证用户身份的渠道,为用户登录 OpenStack 云环境提供了更多的选择空间,实现了账号的统一管理,易用性强。此外还很好的兼容了 Web SSO 模式,通过第三方 Identity Provider 的引入,将管理用户身份认证信息的工作交给更为权威的第三方服务或用户更为信任的服务方,解放了云服务提供商对用户信息的维护与管理,使用户信息的保存更加安全,登录更加简便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值