keystone three types of authentication: UUID, PKI, Fernet

token is a user's credentials, the need to take the correct username / password to get to the Keystone application. If the user each time using a username / password to access the OpenStack API, easy to disclose user information, a security risk. OpenStack before it requires the user to access its API, you must first obtain the token, and then use the token as the user credentials to access OpenStack API

1.UUID certification principles

When the user needs to operate (such as access nova create a virtual machine), users holding a valid username / password authentication to go keystone, keystone returned to the user a token (ie UUID). After the user performs other operations (such as access nova), the first token presented to nova-api, nova after receipt of the request, to use the token verification request destination keystone. By comparison keystone valid token, token and checking determines the validity of the token, and returns the result to the nova

Defects: Each request must be verified through the keystone, causing performance bottlenecks

1. User name password sent to keystone

2. Keystone username and password authentication, and generates a token (UUID), sent to the client

3. Client-side caching UUID token

4. The client sends a specific execution request (nova boot) and UUID to keystone

5. Keystone obtain token from an http request and check token is valid

6. Token valid, processes the request and returns the results of client requests

7. Token failure, reject client requests, returns 401

UUID way source code analysis:

UUID token is a random string has a fixed length of 32 Byte,). Hex generated by uuid.uuid4 (

def _get_token_id(self, token_data):    return uuid.uuid4().hex

Generated sample: 144d8a99a42447379ac37f78bf0ef608

2.PKI certification principles

When initialization keystone, keystone generated CA.pem CA's public key and private key CA.key, while the keystone produce its own public key and private key keystone.pub keystone.key, then keystone.pub be CA's signature, generate keystone.pem

When the user holds the user name / password authentication to the keystone, keystone basic user information encrypted by keystone.key, and the ciphertext is returned to the user as a token. When the user sends a request token holding time (e.g., access nova), nova get the user token, by previously get keystone certificate keystone.pem (this process only once) decrypts obtain user information

For the user's token, the time needed to conduct legitimate token, and also whether there is a token judgment. So when every nova need to ask to get the token list failed a token to the keystone, check the token is invalid. The process for the keystone of the load is still quite light, so the PKI was effectively solve the problem of keystone performance bottlenecks

Summary: OpenStack service each API Endpoint has a keystone certificate issued by the revocation list and root certificate. API do not go directly to the keystone in the authentication token is legitimate, just and based on the certificate revocation list keystone can determine the token is legitimate. But there will still be required each time a request keystone to get a list of operational failure, inevitable

PKI process, first need to use the command generator keystone-manage pki_setup CA and associated token mechanism, which code is as follows:

    def _get_token_id(self, token_data):

        try:

            token_json = jsonutils.dumps(token_data, cls=utils.PKIEncoder)

            token_id = str(cms.cms_sign_token(token_json,

                                              CONF.signing.certfile,

                                              CONF.signing.keyfile))   #DEFAULT_TOKEN_DIGEST_ALGORITHM=sha256

其中,‘token_data’是获取的user、role、endpoint、catlog等信息集合,而最重要的语句是cms使用签名生成token的过程:cms_sign_token,使用默认的sha256方式加密,处理过程使用process,进行数据的读取、处理,

           process = subprocess.Popen(['openssl', 'cms', '-sign',

                                 '-signer', signing_cert_file_name,

                                 '-inkey', signing_key_file_name,

                                 '-outform', 'PEM',

                                 '-nosmimecap', '-nodetach',

                                 '-nocerts', '-noattr',

                                 '-md', message_digest, ],

                                stdin=subprocess.PIPE,

                                stdout=subprocess.PIPE,

                                stderr=subprocess.PIPE,

                                close_fds=True)

最后output, err = process.communicate(data) 生成Token-id,这个过程涉及到openssl相关的加密技术

CMS token一般都超过1600个字节,样例:

3.Fernet认证原理

1.user在客户端输入用户名密码,发送给keystone

2.Keystone验证用户名密码,并且生成token(UUID),发送给客户端

3.客户端缓存token(UUID)

4.客户端发送具体的执行请求给openstack API

5.OpenStack API向 keystone请求token认证

6.Keystone从http请求中获取token,并检查token是否有效

7.Token有效,处理请求,并返回openstack api请求结果

8.Token失效,拒绝客户端请求,返回401

当集群运行较长一段时间后,访问其 API 会变得奇慢无比,究其原因在于 Keystone 数据库存储了大量的 token 导致性能太差,解决的办法是经常清理 token。为了避免上述问题,社区提出了Fernet token,fernet 是当前主流推荐的token格式,它采用 cryptography 对称加密库(symmetric cryptography,加密密钥和解密密钥相同) 加密 token,具体由 AES-CBC 加密和散列函数 SHA256 签名。Fernet 是专为 API token 设计的一种轻量级安全消息格式,不需要存储于数据库,减少了磁盘的 IO,带来了一定的性能提升。为了提高安全性,需要采用 Key Rotation 更换密钥

以上代码表明,token 包含了 user_id,project_id,domain_id,methods,expires_at 等信息,重要的是,它没有 service_catalog,所以 region 的数量并不影响它的大小。self.pack() 最终调用如下代码对上述信息加密:

该token 的大小一般在 200 多 Byte 左右,样例:

gAAAAABWfX8riU57aj0tkWdoIL6UdbViV-632pv0rw4zk9igCZXgC-sKwhVuVb-wyMVC9e5TFc7uPfKwNlT6cnzLalb3Hj0K3bc1X9ZXhde9C2ghsSfVuudMhfR8rThNBnh55RzOB8YTyBnl9MoQ XBO5UIFvC7wLTh_2klihb6hKuUqB6Sj3i_8

简要叙述一下fernet采用 Key Rotation 更换密钥的原理,默认的轮换长度是3,当以keystone-manage fernet-setup生成密钥时,会看到0、1两个索引表征,这分别是什么意思呢?

 

在此,需要提一下三个概念:

primary key(主密钥)有且只有一个,名为为x,当前用于加密解密token

secondary key(次次密钥)有x-1个,从Primary退役下来的,用于解密当初它加密过的token

staged key(次密钥)有且只有一个,命名为0,准备下一个rotation时变为Primary key,可以解密token

那么上述0 表示的是staged key,1 表示的是primary key,

primary key相比较另外两种key,它的索引最高,并且可以加密、也可以解密;

staged key 相较于secondary key,它更有机会变为primary key

AES256加密token,SHA256 HMAC验证完整性,

只要Keystone具有访问这些key的权限,token就不需要在keystone数据库中存储

fernet的数据性能最好,原因是它不需要后端持久化操作(采用 Key Rotation定期 更换密钥,只要Keystone具有访问这些key的权限,更新后的token就不需要在keystone数据库中存储,缓解了数据库负载压力),并且token的认证,使用的是密钥进行解密,能够直接得出token Data的信息,从而进行token的过期认证。它的失败原因,只可能是token过期了,或者是token放到了cache缓存中,但是已经被回收了。归根到底,还是token过期了

 

 

参考链接:

https://www.cnblogs.com/dhplxf/p/7966890.html

Guess you like

Origin www.cnblogs.com/omgasw/p/12157160.html