We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
身份认证可以用流行的Kerberos来实现。需要引用的第三方项目有:
关于Kerberos和sasl的更详细介绍可以参考这里
为了嵌入身份认证,需要修改rDSN的rpc_engine模块,从而使得socket的发起方和接收方在身份认证成功后才能将rpc_session建立成功。
使用sasl+kerberos的身份认证的流程如下:
client server | --- SASL_MECH --> | | <-- SASL_MECH --- | | | | - SASL_SEL_MECH ->| | <- SASL_SEL_OK ---| | | | --- SASL_INIT --> | | | | <-- SASL_CHAL --- | | --- SASL_RESP --> | | | | ..... | | | | <-- SASL_CHAL --- | | --- SASL_RESP --> | | | (authentication will succeed | | if all chanllenges passed) | <-- SASL_SUCC --- | (client won't response | | if servers says ok) | | | --- RPC_CALL ---> | | <-- RPC_RESP ---- |
上述流程可以简要概括为:
在实现身份认证的时候,我们遵循了rdsn中"client和server一问一答"的rpc模型,这样就可以复用rpc_engine的代码了。
具体来看,我们定义了几个类型和结构体:
DEFINE_TASK_CODE_RPC(RPC_NEGOTIATION,...) enum negotiation_status { INVALID = 0, SASL_LIST_MECHANISMS, SASL_LIST_MECHANISMS_RESP, SASL_SELECT_MECHANISMS, SASL_SELECT_MECHANISMS_OK, SASL_INITIATE, SASL_CHALLENGE, SASL_RESPONSE, SASL_SUCC, SASL_AUTH_FAIL } struct negotiation_message { 1: negotiation_status status; 2: dsn.blob msg; }
client和server端就用定义好的rpc code和IDL结构体进行交互。具体要点包括:
在设计并实现身份认证的时候,有些细节要点是必须得注意的:
接下来我们会逐个介绍这些问题。
认证方式的协商是通过两轮RPC来进行的:
平滑升级server端时候需要考虑的问题包括:
为了保证这些情况能够被处理,我们需要引入一个额外的配置项mandatory_authentication来表示是不是强制认证。如果认证是强制选项,那么对于不处理认证消息的对端,要强制关闭会话;反之,就需要跳过所有的认证过程,直接允许会话可以直接交换上层的RPC数据。
在使用Kerberos上,有几个文件/数据是需要管理好的:
默认情况下,这些数据全部以文件的形式保存在固定的路径下。但当我们部署自己的应用时,一定是希望这些路径是可配置的。kerberos库允许我们以设置环境变量的方式来指定这些文件的存取路径。在pegasus身份认证的实现中,kerberos配置和keytab是通过配置文件来指定的。而credential cache是保存在进程的虚拟内存中的。
kerberos给客户端的授权就存放在上文所说的credential cache中(因为TGT就是credential的一种);并且TGT是存在有效期的。我们需要使用Kerberos的相关API来获取TGT的有效期,并且要在到期前使用相关API来更新它。
MIT kerberos提供的接口都是线程安全的,放心使用。
在当前的实现中,server端有个启动参数来控制”是否开启身份认证“。如果需要关闭这一feature,只要重启server就可以了。
一个可能的需求是:通过RPC命令来关闭认证。这样的需求可以实现,但是有些奇怪。原因在于:
所以通过重启的方式来关闭认证是比较合理的,这也使得整个安全过程的边界很清楚:你应该在身份认证层的外部来打破保护本身。从实用的角度来看,当认证系统出问题时,可用性一定会出问题。那么你在恢复可用性时所采取的操作,究竟是重启、还是发起另一个命令,对于整个系统不可用时长的影响,应该是可以忽略不计的。
另一个需求可能是:如果不能继续更新Ticket,就自动降级到不需要认证。这也涉及到了分布式系统的一个基本问题:从进程自己的角度来看,它永远无从得知,不能更新Ticket,是自己不行了,还是网络不行了,还是认证系统不行了。贸然的关闭掉认证系统,相当于直接关掉了整个安全层,是不明智的。所以这个动作最好还是交给管理员进行评估。
最后,如果真的需要为了可用性添加这些功能,还是要多借鉴别的项目在使用Kerberos的经验。
在身份认证成功后,rpc session可以得知认证方的用户名。在每收到一条消息后,session会把用户名存入到每一条message中。这样就可以得知每个message的用户名了:
msg->user_name
假如kerberos的用户名是"sample_user/[email protected]",那么user_name即为"sample_user/pegasus",即没有realm的部分。
对于一个完备的认证过程而言,每条普通的rpc_message都需要携带身份相关的凭据。之所以这么做,是为了防止重放攻击:即一个攻击者在session认证成功后再劫持会话。
但我们在实现上并没有这么做。一方面而言,这么做会导致rpc_message的格式不兼容,给升级带来比较大的困扰;另一方面,身份认证的主要目的是为了防止内网用户的误操作,而非防止公网用户的攻击。
另一个值得注意的是,如果在建立会话时使用的ticket超时了,那么这个会话要不要关闭掉?当前也是从够用的角度出发,没有处理这个问题。
当前的实现在shengofsun/master的branch上
[security] ;; keytab文件,密钥要和krb5_principal相对应 krb5_keytab = /home/weijiesun/source/github/pegasus/local-kdc/krb5.keytab ;; kerberos的配置文件,client和server都需要 krb5_config = /home/weijiesun/source/github/pegasus/local-kdc/krb5.conf ;; 进程启动时候自己的principal krb5_principal = test-server/[email protected] ;; 要访问的server的用户名 service_name = test-server ;; 要访问哦server的fqdn service_fqdn = myhost ;; sasl的路径 sasl_plugin_path = /home/weijiesun/source/github/pegasus/rdsn/thirdparty/output/lib/sasl2 ;; 是否开启认证 open_auth = true ;; 是否强制认证 mandatory_auth = true
The text was updated successfully, but these errors were encountered:
Completed by commits in https://github.com/XiaoMi/rdsn prefixed with 'feat(security): ', such as XiaoMi/rdsn#575
Sorry, something went wrong.
feat: support create client with Proprities object (apache#166)
034c114
scripts: minor fixes on cmake (#166)
0b6b42d
#170
No branches or pull requests
总体过程
身份认证可以用流行的Kerberos来实现。需要引用的第三方项目有:
关于Kerberos和sasl的更详细介绍可以参考这里
为了嵌入身份认证,需要修改rDSN的rpc_engine模块,从而使得socket的发起方和接收方在身份认证成功后才能将rpc_session建立成功。
身份认证的过程
使用sasl+kerberos的身份认证的流程如下:
上述流程可以简要概括为:
如何实现
在实现身份认证的时候,我们遵循了rdsn中"client和server一问一答"的rpc模型,这样就可以复用rpc_engine的代码了。
具体来看,我们定义了几个类型和结构体:
client和server端就用定义好的rpc code和IDL结构体进行交互。具体要点包括:
细节要点
在设计并实现身份认证的时候,有些细节要点是必须得注意的:
接下来我们会逐个介绍这些问题。
认证方式的协商
认证方式的协商是通过两轮RPC来进行的:
平滑升级
平滑升级server端时候需要考虑的问题包括:
为了保证这些情况能够被处理,我们需要引入一个额外的配置项mandatory_authentication来表示是不是强制认证。如果认证是强制选项,那么对于不处理认证消息的对端,要强制关闭会话;反之,就需要跳过所有的认证过程,直接允许会话可以直接交换上层的RPC数据。
使用Kerberos时候的若干问题
kerberos相关文件的管理
在使用Kerberos上,有几个文件/数据是需要管理好的:
默认情况下,这些数据全部以文件的形式保存在固定的路径下。但当我们部署自己的应用时,一定是希望这些路径是可配置的。kerberos库允许我们以设置环境变量的方式来指定这些文件的存取路径。在pegasus身份认证的实现中,kerberos配置和keytab是通过配置文件来指定的。而credential cache是保存在进程的虚拟内存中的。
TGT的更新
kerberos给客户端的授权就存放在上文所说的credential cache中(因为TGT就是credential的一种);并且TGT是存在有效期的。我们需要使用Kerberos的相关API来获取TGT的有效期,并且要在到期前使用相关API来更新它。
Kerberos接口的线程安全
MIT kerberos提供的接口都是线程安全的,放心使用。
认证的临时关闭
在当前的实现中,server端有个启动参数来控制”是否开启身份认证“。如果需要关闭这一feature,只要重启server就可以了。
一个可能的需求是:通过RPC命令来关闭认证。这样的需求可以实现,但是有些奇怪。原因在于:
所以通过重启的方式来关闭认证是比较合理的,这也使得整个安全过程的边界很清楚:你应该在身份认证层的外部来打破保护本身。从实用的角度来看,当认证系统出问题时,可用性一定会出问题。那么你在恢复可用性时所采取的操作,究竟是重启、还是发起另一个命令,对于整个系统不可用时长的影响,应该是可以忽略不计的。
另一个需求可能是:如果不能继续更新Ticket,就自动降级到不需要认证。这也涉及到了分布式系统的一个基本问题:从进程自己的角度来看,它永远无从得知,不能更新Ticket,是自己不行了,还是网络不行了,还是认证系统不行了。贸然的关闭掉认证系统,相当于直接关掉了整个安全层,是不明智的。所以这个动作最好还是交给管理员进行评估。
最后,如果真的需要为了可用性添加这些功能,还是要多借鉴别的项目在使用Kerberos的经验。
有了认证后,怎么方便的做ACL
在身份认证成功后,rpc session可以得知认证方的用户名。在每收到一条消息后,session会把用户名存入到每一条message中。这样就可以得知每个message的用户名了:
假如kerberos的用户名是"sample_user/[email protected]",那么user_name即为"sample_user/pegasus",即没有realm的部分。
认证的进一步讨论
对于一个完备的认证过程而言,每条普通的rpc_message都需要携带身份相关的凭据。之所以这么做,是为了防止重放攻击:即一个攻击者在session认证成功后再劫持会话。
但我们在实现上并没有这么做。一方面而言,这么做会导致rpc_message的格式不兼容,给升级带来比较大的困扰;另一方面,身份认证的主要目的是为了防止内网用户的误操作,而非防止公网用户的攻击。
另一个值得注意的是,如果在建立会话时使用的ticket超时了,那么这个会话要不要关闭掉?当前也是从够用的角度出发,没有处理这个问题。
实现
当前的实现在shengofsun/master的branch上
如何配置
测试要点
The text was updated successfully, but these errors were encountered: