keystone
作为 OpenStack 的基础支持服务,Keystone 做下面这几件事情:
--管理用户及其权限
--维护 OpenStack Services 的 Endpoint
--Authentication(认证)和 Authorization(鉴权)
User 指代任何使用 OpenStack 的实体,可以是真正的用户,其他系统或者服务
除了 admin 和 demo,OpenStack 也为 nova、cinder、glance、neutron 服务创建了相应的 User。 admin 也可以管理这些 User
$ openstack user list
+----------------------------------+---------------------+
| ID | Name |
+----------------------------------+---------------------+
| 2bbcae39de5a4c92888ba02020f29768 | admin |
| e1cb38f61f6c4cbdbe08652e07069d7e | demo |
| f1c6e54f6bec4be1a94dd30a4f178f75 | alt_demo |
| 1f067b057c544bb8ad505b91d771bb05 | nova |
| 2115005aa669427ba577714ee0ac83bb | glance |
| c8e6616110d44e0293959dd7d94d64ec | cinder |
| ce675f7f03444592a28cb7c68754cc9e | neutron |
| ca69c4b0b69643fdb68df055557d6c04 | placement |
| 2f6aba0e76954e0093048bef8c422d6b | barbican |
| 532bea245f9e490ebf6e153649ba8bc9 | service-admin |
| 2d0b38a71904460ba6ecdbb815585b23 | project_a_admin |
| 1826d19694004513920f46fe51b13142 | project_a_creator |
| f27799ade4a544d1ba7baf3039694d52 | project_a_creator_2 |
| 8a6a6c61379e4f718c2c31652d08b6d1 | project_a_observer |
| 4cd94d3bb652439eb091a3f436d68b09 | project_a_auditor |
| 144434a9b68f4f3894ee747f104b169d | project_b_admin |
| 76350a7aabeb4f0c863f90b34888f142 | project_b_creator |
| 4725c9be2b444fd7b79cef8d5c7c8f5e | project_b_observer |
| 4f74b3f00a5f44ecb668c46ed6bb28bc | project_b_auditor |
| 5426986e479846f4ba1ce0d1d6203210 | octavia |
+----------------------------------+---------------------+
Credentials 是 User 用来证明自己身份的信息,可以是:
--用户名/密码
--Token
--API Key
--其他高级方式
Authentication 是 Keystone 验证 User 身份的过程。User 访问 OpenStack 时向 Keystone 提交用户名和密码形式的 Credentials,Keystone 验证通过后会给 User 签发一个 Token 作为后续访问的 Credential。
Token 是由数字和字母组成的字符串,User 成功 Authentication 后 Keystone 生成 Token 并分配给 User。Token 用做访问 Service 的 Credential,Service 会通过 Keystone 验证 Token 的有效性,Token 的有效期默认是 24 小时
token 是用户的一种凭证,需拿正确的用户名/密码向 Keystone 申请才能得到。如果用户每次都采用用户名/密码访问 OpenStack API,容易泄露用户信息,带来安全隐患。所以 OpenStack 要求用户访问其 API 前,必须先获取 token,然后用 token 作为用户凭据访问 OpenStack API
$ openstack token issue
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Value |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| expires | 2020-06-25T14:06:35+0000 |
| id | gAAAAABe9KFbcQBg4YhgdSF63nisqB9SwiiVO69D_HLgKvHBi6D_5Qwj0QwZthnXax0Eu-4jlG1iaFU_1QRJt59N5nVPmFYjgDElnDvrllCBK8NZB25l9tuqG14xESOERrxpGj4t0_hg1V_O2RLMPrGeCNpLrsB0LUSpualGlUBTgcivafKHdmY |
| project_id | 19e61e26bddc4dd9a942c7f7b936cff2 |
| user_id | 2bbcae39de5a4c92888ba02020f29768 |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
$ openstack token issue -f value -c id
gAAAAABe9KGGQ8GU9cfc7VAWl_F9eUKQBaIVh4dtdQP_-XLB8S1X59RijuHPCNhCLLV-asnBsp0lEHfY_Sz7K7TNUHqJJq4evCdC_-mM-70XVQXpSyAW1RBqN5mGk2XSfXP_n6XuJCM_7Lv-lUeegnEu7EQOzYoZLQirzI1xTUACR5xbaB1MKZs
Project 用于将 OpenStack 的资源(计算、存储和网络)进行分组和隔离。
根据 OpenStack 服务的对象不同,Project 可以是一个客户(公有云,也叫租户)、部门或者项目组(私有云)。
这里请注意:
--资源的所有权是属于 Project 的,而不是 User。
--在 OpenStack 的界面和文档中,Tenant / Project / Account 这几个术语是通用的,但长期看会倾向使用 Project
--每个 User(包括 admin)必须挂在 Project 里才能访问该 Project 的资源。 一个User可以属于多个 Project。
--admin 相当于 root 用户,具有最高权限
$ openstack project list
+----------------------------------+--------------------+
| ID | Name |
+----------------------------------+--------------------+
| 19e61e26bddc4dd9a942c7f7b936cff2 | admin |
| 21443037c85d440d945ec44a4f8cb898 | alt_demo |
| 4d3cc3bd0c344758a52083569797d829 | invisible_to_admin |
| 75e04aa75e604134bb1663e93c2b13cc | demo |
| 7fb660857ed94439a6ed287d770d61d9 | project_b |
| 8b0658a56c2640f9a4d96ecaa0218c22 | service |
| dfce788300f8453c89ce6474e05eb8c8 | project_a |
+----------------------------------+--------------------+
Service 包括 Compute (Nova)、Block Storage (Cinder)、Object Storage (Swift)、Image Service (Glance) 、Networking Service (Neutron) 等。每个 Service 都会提供若干个 Endpoint,User 通过 Endpoint 访问资源和执行操作
$ openstack service list
+----------------------------------+-------------+----------------+
| ID | Name | Type |
+----------------------------------+-------------+----------------+
| 311c6a413e54485798371db34f835d53 | nova_legacy | compute_legacy |
| 41f97e1f4c2549bd8b6e7eacdff84d3e | nova | compute |
| 552c5416a91d414584c3cdf91263e078 | glance | image |
| 961b4ca00a6541b4b11061dd04564b93 | cinder | block-storage |
| a4ee2bb897b04a6b8822c260260f7e96 | barbican | key-manager |
| beee886f4a8845bbbe95b978876df762 | cinderv3 | volumev3 |
| d2691c1e5b0f4d0aaf43b389ea7bb724 | keystone | identity |
| d45fc7d3999142e6b733b205ff9a84de | cinderv2 | volumev2 |
| e624da9dbb7c4d7a986f28ffa917e3b1 | placement | placement |
| ef39c03cb9204eb8969d6f256abed411 | neutron | network |
| faa02708e77742e5a179c95ee3eb05f4 | octavia | load-balancer |
+----------------------------------+-------------+----------------+
Endpoint 是一个网络上可访问的地址,通常是一个 URL。Service 通过 Endpoint 暴露自己的 API。 Keystone 负责管理和维护每个 Service 的 Endpoint
$ openstack endpoint list
+----------------------------------+-----------+--------------+----------------+---------+-----------+-------------------------------------------------+
| ID | Region | Service Name | Service Type | Enabled | Interface | URL |
+----------------------------------+-----------+--------------+----------------+---------+-----------+-------------------------------------------------+
| 2e4e2726fbfb4967bfd06fde9b62149c | RegionOne | placement | placement | True | public | http://192.168.101.11/placement |
| 3c8f6834334446a5b290a7e0ae0b1dee | RegionOne | cinderv3 | volumev3 | True | public | http://192.168.101.11/volume/v3/$(project_id)s |
| 4eb51ee233a74722a111355da1e76c9c | RegionOne | neutron | network | True | public | http://192.168.101.11:9696/ |
| 73f6ad2bfd744d26945c08f337113ed5 | RegionOne | nova | compute | True | public | http://192.168.101.11/compute/v2.1 |
| 8698c6a3e18c4437ad8106d870a52f8a | RegionOne | glance | image | True | public | http://192.168.101.11/image |
| 888c3b9f8ce242938ecb8ce768fab63c | RegionOne | barbican | key-manager | True | public | http://192.168.101.11/key-manager |
| 940fa383142943039cb02160028f589a | RegionOne | nova_legacy | compute_legacy | True | public | http://192.168.101.11/compute/v2/$(project_id)s |
| aa9d9606e9d14bee9581deb3fb83cda9 | RegionOne | barbican | key-manager | True | internal | http://192.168.101.11/key-manager |
| bf1d87c95e364e19b2726779601900bb | RegionOne | octavia | load-balancer | True | admin | http://192.168.101.11/load-balancer |
| cfcf4800a6e943fca4af4bbab39267e7 | RegionOne | octavia | load-balancer | True | internal | http://192.168.101.11/load-balancer |
| d0779d2498574ff283ce5654a6f7f87f | RegionOne | octavia | load-balancer | True | public | http://192.168.101.11/load-balancer |
| e0af8e75dfec48678b1c6aaf58c830e0 | RegionOne | keystone | identity | True | public | http://192.168.101.11/identity |
| ea32c2986e0345d0ba2225b81e0f72c6 | RegionOne | cinder | block-storage | True | public | http://192.168.101.11/volume/v3/$(project_id)s |
| f71f18da6e50402586ea2249b1a194c6 | RegionOne | keystone | identity | True | admin | http://192.168.101.11/identity |
| f85b83196668449b8e932088654e0ff3 | RegionOne | cinderv2 | volumev2 | True | public | http://192.168.101.11/volume/v2/$(project_id)s |
+----------------------------------+-----------+--------------+----------------+---------+-----------+-------------------------------------------------+
$ openstack catalog list
+-------------+----------------+-----------------------------------------------------------------------------+
| Name | Type | Endpoints |
+-------------+----------------+-----------------------------------------------------------------------------+
| nova_legacy | compute_legacy | RegionOne |
| | | public: http://192.168.101.11/compute/v2/19e61e26bddc4dd9a942c7f7b936cff2 |
| | | |
| nova | compute | RegionOne |
| | | public: http://192.168.101.11/compute/v2.1 |
| | | |
| glance | image | RegionOne |
| | | public: http://192.168.101.11/image |
| | | |
| cinder | block-storage | RegionOne |
| | | public: http://192.168.101.11/volume/v3/19e61e26bddc4dd9a942c7f7b936cff2 |
| | | |
| barbican | key-manager | RegionOne |
| | | public: http://192.168.101.11/key-manager |
| | | RegionOne |
| | | internal: http://192.168.101.11/key-manager |
| | | |
| cinderv3 | volumev3 | RegionOne |
| | | public: http://192.168.101.11/volume/v3/19e61e26bddc4dd9a942c7f7b936cff2 |
| | | |
| keystone | identity | RegionOne |
| | | public: http://192.168.101.11/identity |
| | | RegionOne |
| | | admin: http://192.168.101.11/identity |
| | | |
| cinderv2 | volumev2 | RegionOne |
| | | public: http://192.168.101.11/volume/v2/19e61e26bddc4dd9a942c7f7b936cff2 |
| | | |
| placement | placement | RegionOne |
| | | public: http://192.168.101.11/placement |
| | | |
| neutron | network | RegionOne |
| | | public: http://192.168.101.11:9696/ |
| | | |
| octavia | load-balancer | RegionOne |
| | | admin: http://192.168.101.11/load-balancer |
| | | RegionOne |
| | | internal: http://192.168.101.11/load-balancer |
| | | RegionOne |
| | | public: http://192.168.101.11/load-balancer |
| | | |
+-------------+----------------+-----------------------------------------------------------------------------+
Role:Keystone 借助 Role 实现 Authorization
--Keystone定义Role
--可以为 User 分配一个或多个 Role
--Service 决定每个 Role 能做什么事情 Service 通过各自的 policy.json 文件对 Role 进行访问控制
$ openstack role list
+----------------------------------+-------------------------------+
| ID | Name |
+----------------------------------+-------------------------------+
| 067212517a374d8692cf01a01a75328a | load-balancer_observer |
| 14fd1216620941958bf90db4b8efc2a6 | observer |
| 30168caccf7c44e7af48d411099ec2a6 | key-manager:service-admin |
| 3ec19ce0c26a4d8684576d9725a91926 | load-balancer_quota_admin |
| 430728e522294a7881847c736ffbade7 | load-balancer_global_observer |
| 466bb851f82646768bba4719968a9825 | anotherrole |
| 47df03b189e04de684807635fc742684 | ResellerAdmin |
| 54cb3852e60c41609310b4ace7d2c604 | member |
| 6d3461078b9f46f98aa969c2ff058039 | service |
| 77c81413fe1e4fb0bf854371a5a6e455 | audit |
| 90fb2f086d994e23b5223c743250e2f3 | load-balancer_admin |
| da8360a614a0450f968cf5bbebc94ddd | load-balancer_member |
| dec71e22688d472cb0c371bc576e7065 | creator |
| e1bf9d4866b74facbf70f18ff4c60f59 | admin |
| e1e5febe74c44968b20355895bdafc36 | reader |
+----------------------------------+-------------------------------+
$ openstack role show -f json admin
{
"description": null,
"domain_id": null,
"id": "e1bf9d4866b74facbf70f18ff4c60f59",
"name": "admin",
"options": {
"immutable": true
}
}
查看keystone的log:
sudo journalctl -f --unit devstack@keystone.service
devstack的默认配置:
root@controller:~# cat /etc/keystone/keystone.conf | grep -v ^$ | grep -v '#'
[identity]
password_hash_rounds = 4
driver = sql
[assignment]
driver = sql
[role]
driver = sql
[resource]
driver = sql
[cache]
memcache_servers = localhost:11211
backend = dogpile.cache.memcached
enabled = True
[oslo_messaging_notifications]
transport_url = rabbit://stackrabbit:admin@192.168.101.11:5672/
[DEFAULT]
max_token_size = 16384
debug = True
logging_exception_prefix = ERROR %(name)s %(instance)s
logging_default_format_string = %(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s
logging_context_format_string = %(color)s%(levelname)s %(name)s [%(global_request_id)s %(request_id)s %(project_name)s %(user_name)s%(color)s] %(instance)s%(color)s%(message)s
logging_debug_format_suffix = {{(pid=%(process)d) %(funcName)s %(pathname)s:%(lineno)d}}
admin_endpoint = http://192.168.101.11/identity
public_endpoint = http://192.168.101.11/identity
[token]
provider = fernet
[database]
connection = mysql+pymysql://root:admin@127.0.0.1/keystone?charset=utf8
[fernet_tokens]
key_repository = /etc/keystone/fernet-keys/
[credential]
key_repository = /etc/keystone/credential-keys/
[security_compliance]
unique_last_password_count = 2
lockout_duration = 10
lockout_failure_attempts = 2
配置参数解析,其余可以参考 https://docs.openstack.org/keystone/ussuri/configuration/config-options.html
password_hash_rounds
This option represents a trade off between security and performance. Higher values lead to slower performance, but higher security. Changing this option will only affect newly created passwords as existing password hashes already have a fixed number of rounds applied, so it is safe to tune this option in a running cluster. The default for bcrypt is 12, must be between 4 and 31, inclusive. The default for scrypt is 16, must be within range(1,32). The default for pbkdf_sha512 is 60000, must be within range(1,1<<32) WARNING: If using scrypt, increasing this value increases BOTH time AND memory requirements to hash a password.
driver(default: sql)
Entry point for the identity mapping backend driver in the keystone.identity.id_mapping namespace. Keystone only provides a sql driver, so there is no reason to change this unless you are providing a custom entry point.
memcache_servers(default: localhost:11211)
Memcache servers in the format of “host:port”. (dogpile.cache.memcached and oslo_cache.memcache_pool backends only).
cache--backend(default: dogpile.cache.null)
Cache backend module. For eventlet-based or environments with hundreds of threaded servers, Memcache with pooling (oslo_cache.memcache_pool) is recommended. For environments with less than 100 threaded servers, Memcached (dogpile.cache.memcached) or Redis (dogpile.cache.redis) is recommended. Test environments with a single instance of the server can use the dogpile.cache.memory backend.
max_token_size(default: 255)
Similar to [DEFAULT] max_param_size, but provides an exception for token values. With Fernet tokens, this can be set as low as 255
token--provier(default: fernet)
Entry point for the token provider in the keystone.token.provider namespace. The token provider controls the token construction, validation, and revocation operations. Supported upstream providers are fernet and jws. Neither fernet or jws tokens require persistence and both require additional setup. If using fernet, you’re required to run keystone-manage fernet_setup, which creates symmetric keys used to encrypt tokens. If using jws, you’re required to generate an ECDSA keypair using a SHA-256 hash algorithm for signing and validating token, which can be done with keystone-manage create_jws_keypair. Note that fernet tokens are encrypted and jws tokens are only signed. Please be sure to consider this if your deployment has security requirements regarding payload contents used to generate token IDs
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 更换密钥。
fernet的数据性能最好,原因是它不需要后端持久化操作(采用 Key Rotation定期更换密钥,只要Keystone具有访问这些key的权限,更新后的token就不需要在keystone数据库中存储,缓解了数据库负载压力),并且token的认证,使用的是密钥进行解密,能够直接得出token Data的信息,从而进行token的过期认证。它的失败原因,只可能是token过期了,或者是token放到了cache缓存中,但是已经被回收了。归根到底,还是token过期了
fernet_tokens --- key_repository (default: /etc/keystone/fernet-keys/)
Directory containing Fernet receipt keys. This directory must exist before using keystone-manage fernet_setup for the first time, must be writable by the user running keystone-manage fernet_setup or keystone-manage fernet_rotate, and of course must be readable by keystone’s server process. The repository may contain keys in one of three states: a single staged key (always index 0) used for receipt validation, a single primary key (always the highest index) used for receipt creation and validation, and any number of secondary keys (all other index values) used for receipt validation. With multiple keystone nodes, each node must share the same key repository contents, with the exception of the staged key (index 0). It is safe to run keystone-manage fernet_rotate once on any one node to promote a staged key (index 0) to be the new primary (incremented from the previous highest index), and produce a new staged key (a new key with index 0); the resulting repository can then be atomically replicated to other nodes without any risk of race conditions (for example, it is safe to run keystone-manage fernet_rotate on host A, wait any amount of time, create a tarball of the directory on host A, unpack it on host B to a temporary location, and atomically move (mv) the directory into place on host B). Running keystone-manage fernet_rotate twice on a key repository without syncing other nodes will result in receipts that can not be validated by all nodes.
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数据库中存储
credential --- key_repository(default: /etc/keystone/credential-keys/)
Directory containing Fernet keys used to encrypt and decrypt credentials stored in the credential backend. Fernet keys used to encrypt credentials have no relationship to Fernet keys used to encrypt Fernet tokens. Both sets of keys should be managed separately and require different rotation policies. Do not share this repository with the repository used to manage keys for Fernet tokens.
unique_last_password_count
This controls the number of previous user password iterations to keep in history, in order to enforce that newly created passwords are unique. The total number which includes the new password should not be greater or equal to this value. Setting the value to zero (the default) disables this feature. Thus, to enable this feature, values must be greater than 0. This feature depends on the sql backend for the [identity] driver
lockout_failure_attempts
The maximum number of times that a user can fail to authenticate before the user account is locked for the number of seconds specified by [security_compliance] lockout_duration. This feature is disabled by default. If this feature is enabled and [security_compliance] lockout_duration is not set, then users may be locked out indefinitely until the user is explicitly enabled via the API. This feature depends on the sql backend for the [identity] driver
lockout_duration
The number of seconds a user account will be locked when the maximum number of failed authentication attempts (as specified by [security_compliance] lockout_failure_attempts) is exceeded. Setting this option will have no effect unless you also set [security_compliance] lockout_failure_attempts to a non-zero value. This feature depends on the sql backend for the [identity] driver.